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

Inconsistent comparations between FjordAuction functions allows to bid on ended auctions

Summary

Inconsistent comparations between FjordAuction functions allows to bid on ended auctions because comparations between block.timestamp and auctionEndTime differs from bid method and auctionEnd method

Vulnerability Details

Contract considers that an auction has ended if block.timestamp >= auctionEnd

function auctionEnd() external {
//console.log("=========== auctionEnd ===========");
if (block.timestamp < auctionEndTime) {
revert AuctionNotYetEnded();
}
//... snippet
ended = true;
//... snippet

However, users can bid and unbid for an action even when block.timestamp == auctionEndTime.
This is because this functions reverts if block.timestamp > auctionEndTime, but it should revert when block.timestamp == auctionEndTime too:

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

So, this allows users monitoring mempools to bid (and frontrun auctionEnd() calls) on empty auction that recently ends, ensuring he will obtain all auctioned tokens, even when the auction just finished, breaking code invariants

Impact

Loss of funds

Tools Used

Manual Review

Recommendations

So bid and unbid should check block.timestamp >= auctionEndTime:

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