The issue arises when users to place bids using a "bid token" even if there are no "auction tokens" (e.g., SpiceToken) available for distribution. This can lead to users losing their bid tokens without receiving any` SpiceTokens` in return.
The vulnerability lies in the interaction between the bid and claim functions:
bid Function (Missing Balance Check):
https://github.com/Cyfrin/2024-07-templegold/blob/main/protocol%2Fcontracts%2Ftemplegold%2FSpiceAuction.sol#L183-L203
There's no check if there's any `AuctionToken` available before pulling the `bidToken` from the user to the `reciepient`
```solidity
function bid(uint256 amount) external virtual override {
/// @dev Cache, gas savings
uint256 epochId = _currentEpochId;
EpochInfo storage info = epochs[epochId];
if(!info.isActive()) { revert CannotDeposit(); }
if (amount == 0) { revert CommonEventsAndErrors.ExpectedNonZero(); }
SpiceAuctionConfig storage config = auctionConfigs[epochId];
(address bidToken,) = _getBidAndAuctionTokens(config);
address _recipient = config.recipient;
uint256 _bidTokenAmountBefore = IERC20(bidToken).balanceOf(_recipient);
IERC20(bidToken).safeTransferFrom(msg.sender, _recipient, amount);
uint256 _bidTokenAmountAfter = IERC20(bidToken).balanceOf(_recipient);
// fee on transfer tokens
if (amount != _bidTokenAmountAfter - _bidTokenAmountBefore) { revert CommonEventsAndErrors.InvalidParam(); }
depositors[msg.sender][epochId] += amount;
info.totalBidTokenAmount += amount;
emit Deposit(msg.sender, epochId, amount);
}
```
https://github.com/Cyfrin/2024-07-templegold/blob/main/protocol%2Fcontracts%2Ftemplegold%2FSpiceAuction.sol#L209-L226
Claim proceeds to try to send the bidder the auction token but fails due to no tokens available.
```solidity
function claim(uint256 epochId) external virtual override {
/// @notice cannot claim for current live epoch
EpochInfo storage info = epochs[epochId];
if (info.startTime == 0) { revert InvalidEpoch(); }
if (!info.hasEnded()) { revert CannotClaim(epochId); }
uint256 bidTokenAmount = depositors[msg.sender][epochId];
if (bidTokenAmount == 0) { revert CommonEventsAndErrors.ExpectedNonZero(); }
delete depositors[msg.sender][epochId];
SpiceAuctionConfig storage config = auctionConfigs[epochId];
(, address auctionToken) = _getBidAndAuctionTokens(config);
uint256 claimAmount = bidTokenAmount.mulDivRound(info.totalAuctionTokenAmount, info.totalBidTokenAmount, false);
/// checkpoint claim for auction token
_claimedAuctionTokens[auctionToken] += claimAmount;
IERC20(auctionToken).safeTransfer(msg.sender, claimAmount);
emit Claim(msg.sender, epochId, bidTokenAmount, claimAmount);
}
```
The issue is the lack of a check in the bid function to ensure sufficient auction token balance before accepting bids. This allows users to potentially lose their bid tokens unknowingly.
Users who place bids with the expectation of receiving `SpiceTokens` could lose the value of their bid tokens if no `SpiceTokens` are available for claim.
Manual Review
Implement a check for a non-zero auction token balance within the startAuction function before initiating an auction. This prevents accepting bids when there are no auction tokens to distribute.
```solidity
function startAuction() external override {
// ... other checks
uint256 balance = IERC20(auctionToken).balanceOf(address(this));
if (balance == 0) { revert NotEnoughAuctionTokens(); }
// ... rest of the function
}
```
Alternatively consider implementing an alternative mechanism (if technically feasible) where users can withdraw their bid tokens if no auction tokens are available for claim. This provides users with more control over their funds.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.