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

Lack of clear timestamp validation can lead to unexpected behavior in auction contracts

Summary

The bid, unbid, and auctionEnd functions in the FjordAuction.sol contract code use timestamp checks with > and < comparisons. The way these checks are implemented leads to a possible scenario where users bidding or unbidding could potentially lose their funds if they interact with the contract near the set auctionEndTime.

Vulnerability Details

This happens because the function calls are checked using only the > and < operators:

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

A gray area exists here, because the logic of block.timestamp > auctionEndTime and block.timestamp < auctionEndTime means that if the block.timestamp == auctionEndTime, none of the functions will revert.

Impact

The likelihood of an attack exploiting this function is very low, as it needs very specific actions to be taken by the users, however, it is still a bug. If the transactions for the bid function and the auctionEnd function go to the same block in which the timestamps allow both functions, the users bidding may lose their tokens in the contract. Also, block.timestamp can be manipulated by miners, as they can influence the block timestamp within a certain range. This can lead to unexpected behavior, where the auction might end slightly earlier or later than expected, impacting users.

Tools Used

Manual review.

Recommendations

For at least one of the checks, use the >= or <= operators:

function bid(uint256 amount) external {
if (block.timestamp > auctionEndTime) {
revert AuctionAlreadyEnded();
}
// ...
}
function unbid(uint256 amount) external {
if (block.timestamp > auctionEndTime) {
revert AuctionAlreadyEnded();
}
// ...
}
function auctionEnd() external {
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.