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

Amount of auction token could remain locked.

Summary

Some amount (big or small) of auction token could remain in the contract even if all users claimed their auction tokens if certain conditions are met due to the calculations made for claiming.

Vulnerability Details

The expected behavior is that after all users claim their reward, then the balance of auctionToken for the contract FjordAuction must be zero.

The method FjordAuction::claimTokens is responsible for determining the amount of auction tokens a user can claim. It uses the multiplier state variable and PRECISION_18 with value of 1e18.

The problem is that some amount (big or small) can remain unclaimed by the user due to this calculation.

The amount of unclaimed token depends on the values that were deposited and different cases are analyzed in the table below.
For the sake of simplicity all the cases consist of 3 deposits and an amount of 1000 ether for the supply of the auction token.

Bid 1 (ETH) Bid 2 (ETH) Bid 3 (ETH) Unclaimable Tokens (WEI)
0.00342333 0.0045633333 0.005233333 1
10.003423575968 12.004568306787 11.005233912676 32
333 333 335.14 939
13334444 13344443 13354444.14 30837575
3454242537.333 4564534312.33333 5234566431325366.3333 2600775822962080

Impact

An amount of auction tokens remain unclaimed.

Tools Used

Manual Review, Foundry

Proof Of Concept

To setup the POC follow these steps:

  • Add the following method to ERC20BurnableMock:

function mintForTestingPurposes(address account, uint256 amount) external {
_mint(account, amount);
}
  • Add the following import to auction.t.sol: import "forge-std/Test.sol";

  • Add the following method to TestAuction contract:

function test_unclaimableAuctionTokens() public {
// Define the bidders and their bid amounts
address bidder1 = address(0x3);
address bidder2 = address(0x4);
address bidder3 = address(0x5);
uint256 bidAmount1 = 333 ether;
uint256 bidAmount2 = 333 ether;
uint256 bidAmount3 = 335.14 ether;
fjordPoints.mintForTestingPurposes(bidder1, bidAmount1);
fjordPoints.mintForTestingPurposes(bidder2, bidAmount2);
fjordPoints.mintForTestingPurposes(bidder3, bidAmount3);
// Bidder 1 places a bid
vm.startPrank(bidder1);
fjordPoints.approve(address(auction), bidAmount1);
auction.bid(bidAmount1);
vm.stopPrank();
// Bidder 2 places a bid
vm.startPrank(bidder2);
fjordPoints.approve(address(auction), bidAmount2);
auction.bid(bidAmount2);
vm.stopPrank();
// Bidder 3 places a bid
vm.startPrank(bidder3);
fjordPoints.approve(address(auction), bidAmount3);
auction.bid(bidAmount3);
vm.stopPrank();
// Verify the bids
assertEq(auction.bids(bidder1), bidAmount1);
assertEq(auction.bids(bidder2), bidAmount2);
assertEq(auction.bids(bidder3), bidAmount3);
skip(biddingTime);
auction.auctionEnd();
// All bidders claim tokens.
vm.startPrank(bidder1);
auction.claimTokens();
vm.stopPrank();
vm.startPrank(bidder2);
auction.claimTokens();
vm.stopPrank();
vm.startPrank(bidder3);
auction.claimTokens();
vm.stopPrank();
console.log("Auction Token contract end balance:", auctionToken.balanceOf(address(auction)));
}
  • Run the command: forge test --mt test_unclaimableAuctionTokens -vvvv

  • Observe the output - the amount of unreachable auction tokens.

To change the output, modify the values of the variables bidAmount1, bidAmount2, bidAmount3 according to the table above.

Recommendations

Consider one of the following or other solutions similar to these:

  • When the last user makes a claim, send the remainder of the auction token to the owner or burn it.

  • Consider larger precision value when operating with large bids (larger than the amount of total auction tokens), this will drastically reduce the amount of locked tokens and the rest of them can simply be burned.

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.