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

Set a minimum bid amount threshold to ensure auction fairness and project funding security

Summary

if the total number of bids (totalBids) is very low or manipulated to be extremely low, the multiplier can be excessively high, leading to a disproportionate distribution of tokens. This vulnerability could allow a malicious actor to exploit the auction, receiving an unfairly large number of tokens relative to their bid.

Vulnerability Details

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

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

Because this vulnerability exists, as long as all participating addresses (can be attackers or others) use very small bidAmount, this vulnerability can be exploited.

Exp:

• Multiple attackers use different addresses to place small bids.

• When the auction ends, the attackers benefit from the high multiplier, receiving a large amount of tokens relative to their small bids.

• This allows them to exploit the auction, claiming disproportionately large token rewards compared to their actual bid amounts.

forge test --match-path test/unit/auction.t.sol --match-contract TestAuction --match-test "testBug" -vvvv

function testBug() public {
address bidder1=address(0x11);
address bidder2=address(0x22);
address bidder3=address(0x33);
uint256 bidAmount=1;
deal(address(fjordPoints), bidder1, bidAmount);
deal(address(fjordPoints), bidder2, bidAmount);
deal(address(fjordPoints), bidder3, bidAmount);
vm.startPrank(bidder1);
fjordPoints.approve(address(auction), bidAmount);
auction.bid(bidAmount);
vm.stopPrank();
vm.startPrank(bidder2);
fjordPoints.approve(address(auction), bidAmount);
auction.bid(bidAmount);
vm.stopPrank();
vm.startPrank(bidder3);
fjordPoints.approve(address(auction), bidAmount);
auction.bid(bidAmount);
vm.stopPrank();
skip(biddingTime);
auction.auctionEnd();
vm.startPrank(bidder1);
auction.claimTokens();
}
├─ [37396] FjordAuction::claimTokens()
│ ├─ [29816] ERC20BurnableMock::transfer(0x0000000000000000000000000000000000000011, 333333333333333333333 [3.333e20])
│ │ ├─ emit Transfer(from: FjordAuction: [0xF62849F9A0B5Bf2913b396098F7c7019b51A820a], to: 0x0000000000000000000000000000000000000011, value: 333333333333333333333 [3.333e20])
│ │ └─ ← [Return] true
│ ├─ emit TokensClaimed(bidder: 0x0000000000000000000000000000000000000011, amount: 333333333333333333333 [3.333e20])

Impact

It could allow a single or multiple malicious actors to drain the entire auction token pool with minimal investment, thereby undermining the fairness and purpose of the auction.

Tools Used

Manual review

Recommendations

To implement a minimum total bids threshold, you can modify the auctionEnd() function to check if the total bids have met the required threshold before ending the auction.

/// @notice The minimum total amount of bids required to end the auction.
uint256 public minTotalBids = 100 * PRECISION_18; // Example threshold, adjust as needed
function auctionEnd() external {
if (block.timestamp < auctionEndTime) {
revert AuctionNotYetEnded();
}
if (ended) {
revert AuctionEndAlreadyCalled();
}
ended = true;
emit AuctionEnded(totalBids, totalTokens);
if (totalBids < minTotalBids) {
revert NotEnoughBids(); // Custom error for insufficient bids
}
if (totalBids == 0) {
auctionToken.transfer(owner, totalTokens);
return;
}
multiplier = totalTokens.mul(PRECISION_18).div(totalBids);
// Burn the FjordPoints held by the contract
uint256 pointsToBurn = fjordPoints.balanceOf(address(this));
fjordPoints.burn(pointsToBurn);
}
Updates

Lead Judging Commences

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

Support

FAQs

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