Vulnerability details
USER_FIRST_BID
is an auction activation mode to start the auction after the user's first bid. It is not implemented in the startAuction
or bid
function. Whenever the auction config with USER_FIRST_BID
is set it will not be triggered by user bid. It will start after the cooldown like AUCTION_TOKEN_BALANCE
activation mode.
Proof of Concept
function bid(uint256 amount) external virtual override {
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);
}
We can see that bid can only be made when auction is active. if(!info.isActive()) { revert CannotDeposit(); }
if (config.activationMode == ActivationMode.AUCTION_TOKEN_BALANCE) {
if (config.minimumDistributedAuctionToken == 0) { revert MissingAuctionTokenConfig(); }
}
if (epochAuctionTokenAmount < config.minimumDistributedAuctionToken) { revert NotEnoughAuctionTokens(); }
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;
In startAuction
function we can see that startTime
is calcualted in the same way for every activation mode (adding cooldown where for USER_FIRST_BID
it should start after first bid).
Impact
Protocol functionality is not correctly implemented.
Recommended Mitigation Steps
Change startAuction
function to start an USER_FIRST_BID
auction when user places first bid. Enforce a bid from user when auction is started.