TempleGold

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

H-01 SpiceAuction::startAuction() may revert when totalAuctionTokenAllocation - _claimedAuctionTokens[auctionToken] is larger than balance.

Relevant GitHub Links

https://github.com/Cyfrin/2024-07-templegold/blob/57a3e597e9199f9e9e0c26aab2123332eb19cc28/protocol/contracts/templegold/SpiceAuction.sol#L107
https://github.com/Cyfrin/2024-07-templegold/blob/57a3e597e9199f9e9e0c26aab2123332eb19cc28/protocol/contracts/templegold/SpiceAuction.sol#L160
https://github.com/Cyfrin/2024-07-templegold/blob/57a3e597e9199f9e9e0c26aab2123332eb19cc28/protocol/contracts/templegold/SpiceAuction.sol#L173

Summary

SpiceAuction::startAuction() may revert when totalAuctionTokenAllocation - _claimedAuctionTokens[auctionToken] is larger than balance.

Vulnerability Details

Whenever an auction is started totalAuctionTokenAllocation[auctionToken] is incremented with the corresponding epochAuctionTokenAmount. This logic is fine as it is, the problem comes when SpiceAuction::removeAuctionConfig() is called for a startedAuction in cooldown.
In this method we don't have any handling of totalAuctionTokenAllocation[auctionToken] rather we just delete the epoch with the info in it. This way totalAuctionTokenAllocation[auctionToken] remains incremented and whenever we call startAuction() again if in previous run
we had an increment that made the value of totalAuctionTokenAllocation[auctionToken]higher that the current balance it may underflow and revert resulting in the DOS of startAuction().

function startAuction() external override {
uint256 epochId = _currentEpochId;
/// @dev config is always set for next auction
/// @notice Configuration is set before auctions so configId = currentEpochId + 1;
SpiceAuctionConfig storage config = auctionConfigs[epochId+1];
if (config.duration == 0) { revert CannotStartAuction(); }
/// @notice only starter
if (config.starter != address(0) && msg.sender != config.starter) { revert CommonEventsAndErrors.InvalidAccess(); }
/// @notice enough wait period since last auction
if (epochId > 0) {
/// @dev `_currentEpochId` is still last epoch
EpochInfo memory lastEpochInfo = epochs[epochId];
/// use waitperiod from last auction config
uint64 _waitPeriod = auctionConfigs[epochId].waitPeriod;
if (lastEpochInfo.endTime + _waitPeriod > block.timestamp) { revert CannotStartAuction(); }
} else {
/// For first auction
if (_deployTimestamp + config.waitPeriod > block.timestamp) { revert CannotStartAuction(); }
}
(,address auctionToken) = _getBidAndAuctionTokens(config);
uint256 totalAuctionTokenAllocation = _totalAuctionTokenAllocation[auctionToken];
uint256 balance = IERC20(auctionToken).balanceOf(address(this));
uint256 epochAuctionTokenAmount = balance - (totalAuctionTokenAllocation - _claimedAuctionTokens[auctionToken]);//@audit if balance is less then we DOS
if (config.activationMode == ActivationMode.AUCTION_TOKEN_BALANCE) {
if (config.minimumDistributedAuctionToken == 0) { revert MissingAuctionTokenConfig(); }
}
if (epochAuctionTokenAmount < config.minimumDistributedAuctionToken) { revert NotEnoughAuctionTokens(); }
// epoch start settings
// now update currentEpochId
epochId = _currentEpochId = _currentEpochId + 1;
EpochInfo storage info = epochs[epochId];
uint128 startTime = info.startTime = uint128(block.timestamp) + config.startCooldown;
uint128 endTime = info.endTime = startTime + config.duration;
info.totalAuctionTokenAmount = epochAuctionTokenAmount;
// Keep track of total allocation auction tokens per epoch
_totalAuctionTokenAllocation[auctionToken] = totalAuctionTokenAllocation + epochAuctionTokenAmount; //@audit we do not update the allocation when removeAuctionConfig is called
emit AuctionStarted(epochId, msg.sender, startTime, endTime, epochAuctionTokenAmount);
}

Impact

High

Tools Used

Manual review

Recommendations

Update in SpiceAuction::removeAuctionConfig() _totalAuctionTokenAllocation[auctionToken] -= info.totalAuctionTokenAmount.

Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

missing totalAuctionTokenAllocation deduction in removeAuctionConfig leads to stuck funds

Support

FAQs

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