Users may bid then claim after auction end to drain the entire tokens
The auctionEnd
function will end the auction if block.timestamp < auctionEndTime
the function will set the ended
variable to true. Then the function will find the multiplier by multiplying the total tokens by the precision_18 then dividing by the total bids.
The problem occurs because users are allowed to bid after the auction has ended because of the incorrect use of the inequality to check if the auction has truly ended
let us observe the bid
function below...
as we can see if block.timestamp > auctionEndTime
we can still bid, but if we recall from the auctionEnd
function, if (block.timestamp < auctionEndTime)
then we can call endAuction
this is very problematic... because if we see a scenario where block.timestamp = auctionEndTime, both inequalities will pass for auctionEnd
function and bid
function.
This allows for the auction to be ended, but in the same block the user can then call bid then the next transaction he can call claim.
because the auctionEnd
set the multiplier and the variableended
to true, the user can bid with large amount and thencall claim in order to drain the entire tokens and cause others to be able to claim 0. This happens because the users bids was not used when accounting the multiplier in the endAuction
function
Let us explain this step by step below...
auction ends because block.timestamp = auctionEndTime and user call endAuction
the total bids is 100
the token amount is 100
The multiplier is set and ended
is set to true
the multiplier will be essentially 1, meaning that 1 point bid can claim 1 token
a user may still bid and he bids a large amount, he bids 100 points after the auction ended
the user may now claim and because the multiplier is 1 he can claim 100 tokens
the contract is drained of all tokens and no other of the bidders can claim
Direct theft of users funds
manual review
add the following check in bid and unbid functions to ensure a user may not bid after auction end
if (ended) { revert AuctionEndAlreadyCalled();
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.