DeFiFoundry
20,000 USDC
View results
Submission Details
Severity: medium
Valid

Auction Tokens Are Irrecoverable if Total Bids for Auction is Zero

Summary

The Admin/Owner of the FjordAuctionFactory can create a new auction by calling createAuction(). During the creation process, the owner transfers auction tokens to the newly deployed auction contract. Users can bid and unbid before the auctionEndTime. However, if the totalBids amount is zero at the end of the auction, all the auction tokens become stuck in the contract and cannot be recovered.

Vulnerability Details

function createAuction(
address auctionToken,
uint256 biddingTime,
uint256 totalTokens,
bytes32 salt
) external onlyOwner {
address auctionAddress = address(
new FjordAuction{ salt: salt }(fjordPoints, auctionToken, biddingTime, totalTokens)
);
// Transfer the auction tokens from the msg.sender to the new auction contract
IERC20(auctionToken).transferFrom(msg.sender, auctionAddress, totalTokens);
emit AuctionCreated(auctionAddress);
}

https://github.com/Cyfrin/2024-08-fjord/blob/main/src/FjordAuctionFactory.sol#L52

The above function allows the owner of the FjordAuctionFactory to create an auction and transfer totalTokens (the auction tokens) to the deployed auction contract.

constructor(
address _fjordPoints,
address _auctionToken,
uint256 _biddingTime,
uint256 _totalTokens
) {
if (_fjordPoints == address(0)) {
revert InvalidFjordPointsAddress();
}
if (_auctionToken == address(0)) {
revert InvalidAuctionTokenAddress();
}
fjordPoints = ERC20Burnable(_fjordPoints);
auctionToken = IERC20(_auctionToken);
owner = msg.sender;
auctionEndTime = block.timestamp.add(_biddingTime);
totalTokens = _totalTokens;
}
function auctionEnd() external {
if (block.timestamp < auctionEndTime) {
revert AuctionNotYetEnded();
}
if (ended) {
revert AuctionEndAlreadyCalled();
}
ended = true;
emit AuctionEnded(totalBids, totalTokens);
if (totalBids == 0) {
//@audit-issue no recovery of auction tokens
auctionToken.transfer(owner, totalTokens);
return;
}
multiplier = totalTokens.mul(PRECISION_18).div(totalBids);
// Burn the FjordPoints held by the contract
uint256 pointsToBurn = fjordPoints.balanceOf(address(this));
fjordPoints.burn(pointsToBurn);
}

https://github.com/Cyfrin/2024-08-fjord/blob/main/src/FjordAuction.sol#L193

The auctionEnd() function determines the total claimable tokens for each bidder based on their bids. If totalBids equals zero, the function is designed to transfer the auction tokens back to the owner as a recovery mechanism. However, the issue arises because the owner of the FjordAuction is the deployer, which in this case is the FjordAuctionFactory.

Consequently, the transferred tokens are sent back to the AuctionFactory, where they become stuck with no way to recover them

Impact

Auction token will stuck in the contract

Tools Used

Manual

Recommendations

Instead of transferring the tokens back to the FjordAuctionFactory contract, they should be sent to the actual owner of the FjordAuctionFactory who created the auction.

Updates

Lead Judging Commences

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

If no bids are placed during the auction, the `auctionToken` will be permanently locked within the `AuctionFactory`

An auction with 0 bids will get the `totalTokens` stuck inside the contract. Impact: High - Tokens are forever lost Likelihood - Low - Super small chances of happening, but not impossible

Support

FAQs

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