DeFiFoundry
20,000 USDC
View results
Submission Details
Severity: low
Invalid

Dust will remain in `FjordAuction` after all the tokens are claimed

Summary

The FjordAuction contracts are used to distribute auction tokens to users who bid their FjordPoints.

At the end of the auction period, auctionEnd() is called and users can start claiming their tokens using claimTokens().

Vulnerability Details

When auctionEnd() is called, a multiplier is calculated based upon the totalTokens (the auction tokens for users to claim) and the totalBids (the fjord points that were deposited in the auction).

https://github.com/Cyfrin/2024-08-fjord/blob/main/src/FjordAuction.sol#L197

multiplier = totalTokens.mul(PRECISION_18).div(totalBids);

During the claim process, claimTokens() will calculate the claimable amount of tokens for the user using the multiplier.

https://github.com/Cyfrin/2024-08-fjord/blob/main/src/FjordAuction.sol#L217

uint256 claimable = userBids.mul(multiplier).div(PRECISION_18);

Truncation may occur due to the division by PRECISION_18. This truncated amount will not be distributed to the user and will accumulate for each user.

Here is a PoC that can be pasted in test\unit\auction.t.sol and demonstrates 97 users bidding an amount of fjord points that will result in dust being stuck in the auction contract:

function testUnfavorableAuction() public {
uint256 bidderNumber = 97;
uint256 bidAmount = 3333 ether;
for(uint256 i ; i < bidderNumber ; ++i) {
address bidder = address(bytes20(keccak256(abi.encode(i))));
deal(address(fjordPoints), bidder, bidAmount);
vm.startPrank(bidder);
fjordPoints.approve(address(auction), bidAmount);
auction.bid(bidAmount);
vm.stopPrank();
}
skip(biddingTime);
auction.auctionEnd();
for(uint256 i ; i < bidderNumber ; ++i) {
address bidder = address(bytes20(keccak256(abi.encode(i))));
vm.startPrank(bidder);
auction.claimTokens();
vm.stopPrank();
}
console.log("Auction contract's tokens left :", auctionToken.balanceOf(address(auction)));
assertNotEq(
auctionToken.balanceOf(address(auction)),
0
);
}

Impact

Depending on the amount of tokens that are distributed by the auction, the amount of fjord points deposited by the users and due to the way Solidity rounds integer, after all users have claimed their tokens, a residual amount of tokens will most likely not be distributed to users and be stuck in the contract.

This issue can represent a relatively dramatic financial loss for the protocols (Fjord on one hand AND the protocol that emitted the token on the other hand AS WELL AS the protocol users) depending on the amount stuck in the contract and the actual value of the token.

Tools Used

Manual review

Recommendations

Add a function that will be responsible for retrieving the dust amount after all users have claimed their rewards.

Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

FjordAuction doesn't handle the dust remained after everyone claimed

Support

FAQs

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