All of bid()
, unbid()
and auctionEnd()
functions can be executed at the same auctionEndTime
within the same block.
In particular, if bid()
or unbid()
is executed after auctionEnd()
, it causes serious problems to the protocol.
FjordAuction.bid()
, FjordAuction.unbid()
and FjordAuction.auctionEnd()
functions are following.
As can be seen, all of bid()
, unbid()
and auctionEnd()
functions can be executed at auctionEndTime
.
From this, the following scenarios are available. To simplify, we ignore precision factor in the following calculations.
Scenario 1 of bid()
:
Assume that total auction token is 1000
and user1
bids 100
points.
At auctionEndTime
, auctionEnd()
is executed and multiplier is determined as 1000 / 100 = 10
.
In the same block of auctionEnd()
's tx but after that, user2
's bid()
tx is executed with 100
points.
If user2
claims first, 100 * 10 = 1000
auction tokens are transferred to user2
.
After that, user1
can't claim auction tokens because there are no more auction tokens left.
Scenario 2 of unbid()
:
Assume that total auction token is 1000
and user1
bids 40
points and user2
bids 60
points so the total bids are 40 + 60 = 100
.
At auctionEndTime
, auctionEnd()
is executed and multiplier is determined as 10
.
In the same block of auctionEnd()
's tx but after that, user2
's unbid()
tx is executed with 60
points.
user1
claims his 400
auction tokens.
1000 - 400 = 600
auction tokens will be locked in FjordAuction
contract.
Attacker can even use scenario 2 to lock almost auction tokens in the contract and damage other users with huge amount of points.
Users can't claim tokens after auction finishes or some tokens may be locked in FjordAuction
contract.
Attacker can lock almost auction tokens in the contract and damage other users.
Manual Review
Modify FjordAuction.auctionEnd()
function as follows.
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.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.