Lines Of Code
https://github.com/TempleDAO/temple/blob/3768698e6d78ba1340a57406e5961a0e2faba212/protocol/contracts/templegold/SpiceAuction.sol#L221
Summary
Users are likely to lose their bid if spiceToken
is a low-decimals token and templeGold
is auctionToken
Vulnerability Details
When a user calls SpiceAuction::bid()
, he provides the amount of bidToken
he will bid.
File: contracts/templegold/SpiceAuction.sol
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);
if (amount != _bidTokenAmountAfter - _bidTokenAmountBefore) { revert CommonEventsAndErrors.InvalidParam(); }
depositors[msg.sender][epochId] += amount;
info.totalBidTokenAmount += amount;
emit Deposit(msg.sender, epochId, amount);
}
When he claims his rewards for an epoch he has bid tokens, he will get an amount corresponding to the a percentage of the amount he bid on the total bid amount for the epoch.
File: contracts/templegold/SpiceAuction.sol
function claim(uint256 epochId) external virtual override {
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);
}
In the case that the spiceToken
has a low decimals count (USDC, USDT, WBTC have 6 to 8 decimals) and templeGold
is the auctionToken
(SpiceAuctionConfig.isTempleGoldAuctionToken == true), then it's very likely that the claimAmount
calculation will result in rounding down to 0. This means that the auction recipient will get the whole bid amount, but the bidder will get 0 auctionToken
to claim, resulting in a total lost of his bid.
Impact
Bidders lose their bid and get 0 auctionToken
Tools Used
Manual review.
Recommendations
Enforce that the spiceToken
decimals are equals to the auctionToken
.
Or implement proper conversion in case spiceToken
and auctionToken
have different decimals.