## Summary
There will be always a locked bid/auction token in the `SpiceAuction` contract due to rounding down in the `SpiceAuction.claim()` function.
## Vulnerability Details
When an auction ends, depositors can claim their rewards (auction token) as a ratio from their deposited amount to the total auction deposits:
```javascript
uint256 claimAmount = bidTokenAmount.mulDivRound(
info.totalAuctionTokenAmount,
info.totalBidTokenAmount,
false
);
```
due to rounding down; there will be always an unrecoverable auction tokens (that can't be recovered via `SpiceAuction.recoverToken()`) , as the `recoverToken()` will only allow withdrawing any excess tokens sent by mistake:
```javascript
function recoverToken(
address token,
address to,
uint256 amount
) external override onlyDAOExecutor {
//...
uint256 totalAuctionTokenAllocation = _totalAuctionTokenAllocation[token];
uint256 balance = IERC20(token).balanceOf(address(this));
uint256 maxRecoverAmount = balance -
(totalAuctionTokenAllocation - _claimedAuctionTokens[token]);
//...
IERC20(token).safeTransfer(to, amount);
//...
}
```
and the reason behind that is that in the ideal case where all user claimed their rewards without any losses due to rounding down; the `_totalAuctionTokenAllocation[token] - _claimedAuctionTokens[token] == 0`,
but due to rounding down; even if all the users claimed their rewards the `_totalAuctionTokenAllocation[token] - _claimedAuctionTokens[token]` will be > 0 and these leftovers can't be withdrawn (the locked tokens can be large since these are cumulative amounts).
Same issue in the `DiaGoldAuction` contract.
## Impact
Locked amount of auction tokens in the auctions contract.
## Code Snippet
```javascript
function claim(uint256 epochId) external virtual override {
EpochInfo storage info = epochs[epochId];
//...
uint256 claimAmount = bidTokenAmount.mulDivRound(
info.totalAuctionTokenAmount,
info.totalBidTokenAmount,
false
);
/// checkpoint claim for auction token
_claimedAuctionTokens[auctionToken] += claimAmount;
IERC20(auctionToken).safeTransfer(msg.sender, claimAmount);
//...
}
```
## Tools Used
Manual Review.
## Recommendations
Add a state variable to collect these leftover rewards (due to rounding down) after each claim, and enable recovering them via `recoverToken()`.