TempleGold

TempleDAO
Foundry
25,000 USDC
View results
Submission Details
Severity: medium
Invalid

The current recover mechanism when the auction ends without any bids is inefficient and can be abused

Vulnerability Details

In SpiceAuction contract, recoverAuctionTokenForZeroBidAuction is meant to be used to recover the auction tokens when the auction epoch ends with no bid. The following check ensures that no bids were done for the auction:

if (epochInfo.totalBidTokenAmount > 0) { revert InvalidOperation(); }

However, this is not efficient and can be abused. A malicious actor monitoring the chain and seeing an auction is very close to an end with no bids can frontrun the bid transaction just before the epoch ends and bids with the smallest value possible, i.e 1 wei DAI, making epochInfo.totalBidTokenAmount greater than 0, and thus recoverAuctionTokenForZeroBidAuction can not be called. As consequences:

  1. The actor will get the whole auction tokens (which might be large) for 1 wei DAI, which is economically inefficient. Those tokens were meant to be recovered using recoverAuctionTokenForZeroBidAuction.

  2. The malicious actor can choose to not claim if he is not interested at all (as his attack did not cost him, only gas + 1wei DAI), locking the auction tokens permanently.

Note that the malicious actor who bidded at the very end did not have an intention to bid, as he can bid just for 1 wei of DAI, but he wanted to abuse the recoverAuctionTokenForZeroBidAuction, making it completely useless

PoC

The following PoC demonstrates the described finding, where 100 ether of auction tokens can either be locked or claimed for 1 wei DAI only. Copy and paste the following function in test/forge/templegold/SpiceAuction.t.sol:

function testPoC() public {
_startAuction(true, true);
IAuctionBase.EpochInfo memory info = spice.getEpochInfo(1);
ISpiceAuction.SpiceAuctionConfig memory _config = spice.getAuctionConfig(1);
vm.warp(info.endTime - 1);
// Bob bids 1 wei of DAI just before the epoch ends
vm.startPrank(bob);
uint256 bidAmount = 1 wei;
deal(daiToken, bob, bidAmount);
IERC20(daiToken).approve(address(spice), type(uint).max);
spice.bid(bidAmount);
vm.stopPrank();
vm.warp(info.endTime + 1);
vm.startPrank(daoExecutor);
// @audit Notice that recovering will not be possible because of last 1 wei bid
// as consequence, bob can choose to not claim, so 100 ether of auction token are locked
vm.expectRevert(abi.encodeWithSelector(IAuctionBase.InvalidOperation.selector));
spice.recoverAuctionTokenForZeroBidAuction(1, alice);
// Bob can claim the whole 100 ether auction tokens for 1 wei DAI only
}

Impact

  • Malicious actors can permanently lock auction tokens for auctions that were supposed to end with no bids

  • Actors monitoring the chain can claim all auction tokens (that were meant to be recovered because of no bids) for 1 wei DAI

  • recoverAuctionTokenForZeroBidAuction might never be used.

Tools Used

Manual Review

Recommendations

One possible mitigation could be to force a minimum bid amount for auctions with no bids and are very close to an end.

Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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