TempleGold

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

Permanent Locking of Auction Tokens due to Unclaimed Bids

Summary

A issue in the auction contract will lead to permanent locking of auction tokens if a user places a bid right at the end of an auction for all or enough spiceToken without a bid but never calls the claim function to retrieve their tokens will lock the tokens in the contract forever. This issue prevents recovery of the tokens via the recoverAuctionTokenForZeroBidAuction and recoverToken functions, resulting in a loss of functionality and funds.

Vulnerability Details

The claim function in the auction contract is responsible for allowing users to claim their share of auction tokens based on their bid. However, if a user bids the entire amount of auction tokens and does not call claim, the tokens remain locked in the contract. The recoverAuctionTokenForZeroBidAuction function cannot be used to recover these tokens because it checks if the total bid amount for the epoch is zero. Similarly, the recoverToken function is prevented from recovering unclaimed tokens due to the checks in place.

recoverAuctionTokenForZeroBidAuction Function

https://github.com/Cyfrin/2024-07-templegold/blob/main/protocol%2Fcontracts%2Ftemplegold%2FSpiceAuction.sol#L275-L283

function recoverAuctionTokenForZeroBidAuction(uint256 epochId, address to) external override onlyDAOExecutor {
if (to == address(0)) { revert CommonEventsAndErrors.InvalidAddress(); }
if (epochId > _currentEpochId) { revert InvalidEpoch(); }
EpochInfo storage epochInfo = epochs[epochId];
if (!epochInfo.hasEnded()) { revert AuctionActive(); }
if (epochInfo.totalBidTokenAmount > 0) { revert InvalidOperation(); }
SpiceAuctionConfig storage config = auctionConfigs[epochId];
(, address auctionToken) = _getBidAndAuctionTokens(config);
uint256 amount = epochInfo.totalAuctionTokenAmount;
_totalAuctionTokenAllocation[auctionToken] -= amount;
emit CommonEventsAndErrors.TokenRecovered(to, auctionToken, amount);
IERC20(auctionToken).safeTransfer(to, amount);
}

This line reverts the operation because there is a bid
https://github.com/Cyfrin/2024-07-templegold/blob/main/protocol%2Fcontracts%2Ftemplegold%2FSpiceAuction.sol#L283

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

recoverToken Function

https://github.com/Cyfrin/2024-07-templegold/blob/main/protocol%2Fcontracts%2Ftemplegold%2FSpiceAuction.sol#L234-L238

function recoverToken(
address token,
address to,
uint256 amount
) external override onlyDAOExecutor {
if (to == address(0)) { revert CommonEventsAndErrors.InvalidAddress(); }
if (amount == 0) { revert CommonEventsAndErrors.ExpectedNonZero(); }
if (token != spiceToken && token != templeGold) {
emit CommonEventsAndErrors.TokenRecovered(to, token, amount);
IERC20(token).safeTransfer(to, amount);
return;
}
uint256 epochId = _currentEpochId;
EpochInfo storage info = epochs[epochId];
if (info.startTime == 0) { revert InvalidConfigOperation(); }
if (!info.hasEnded() && auctionConfigs[epochId+1].duration == 0) { revert RemoveAuctionConfig(); }
uint256 totalAuctionTokenAllocation = _totalAuctionTokenAllocation[token];
uint256 balance = IERC20(token).balanceOf(address(this));
uint256 maxRecoverAmount = balance - (totalAuctionTokenAllocation - _claimedAuctionTokens[token]);
if (amount > maxRecoverAmount) { revert CommonEventsAndErrors.InvalidParam(); }
IERC20(token).safeTransfer(to, amount);
emit CommonEventsAndErrors.TokenRecovered(to, token, amount);
}

This restricts recovery of tokens waiting to be claimed
https://github.com/Cyfrin/2024-07-templegold/blob/main/protocol%2Fcontracts%2Ftemplegold%2FSpiceAuction.sol#L261

uint256 maxRecoverAmount = balance - (totalAuctionTokenAllocation - _claimedAuctionTokens[token]);

Impact

This leads to permanent locking of auction tokens and Inability to recover these tokens using the recoverAuctionTokenForZeroBidAuction and recoverToken functions.

Tools Used

Manual code review and analysis.

Recommendations

Maybe add a function that allows anyone to trigger the claim on behalf of users who haven’t claimed after a certain period, possibly with an incentive for the caller.

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.