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

Auction token will be transferred back to AuctionFactory and locked in AuctionFactory if there is no bidder.

Summary

When there is no bidder for one auction, the auction tokens will be transferred back to AuctionFactory, auction tokens will be locked in auctionFactory because the owner cannot withdraw tokens from auction factory.

Vulnerability Details

When the project owner creates one auction via FjordAuctionFactory, one new auction contract will be created and the FjordAuctionFactory will become the new auction contract's owner.

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);
}

FjordAuction.sol:

constructor(
address _fjordPoints,
address _auctionToken,
uint256 _biddingTime,
uint256 _totalTokens
) {
...
auctionToken = IERC20(_auctionToken);
// Factory is the owner.
owner = msg.sender;
...
}

If there is no any bidder in one auction, the auction tokens in this auction contract will be returned back to the owner when the auction ends. The problem is that the owner is auctionFactory, and the factory's owner cannot withdraw auctionTokens from auctionFactory contract.

function auctionEnd() external {
...
if (totalBids == 0) {
auctionToken.transfer(owner, totalTokens);
return;
}
...
}

Poc

function test_Factory() public {
deal(address(auctionToken), alice, 100 ether);
vm.startPrank(alice);
// Alice is the factory's owner.
factory = new AuctionFactory(address(fjordPoints));
auctionToken.approve(address(factory), 100 ether);
factory.createAuction(address(auctionToken), biddingTime, 100 ether, bytes32("123"));
console.log("Factor owner balance: ", auctionToken.balanceOf(alice));
vm.warp(2 weeks);
auction = FjordAuction(0x26d8DC373D83f0f19cC6D0b2cba5FfCE89B77061);
auction.auctionEnd();
console.log("Factor owner balance After bid ends: ", auctionToken.balanceOf(alice));
console.log("Factory balance after bid ends: ", auctionToken.balanceOf(address(factory)));
}

The output is as below:

[PASS] test_Factory() (gas: 2023985)
Logs:
Auction Address:
0x26d8DC373D83f0f19cC6D0b2cba5FfCE89B77061
Factor owner balance: 0
Factor owner balance After bid ends: 0
Factory balance after bid ends: 100000000000000000000

Impact

When there is not any bidder in one auction, the auction tokens will be locked in the auctionFactory and not be return back to the initial factory owner.

Tools Used

Manual

Recommendations

Add one withdraw function in FjordAuctionFactory contract, and the factory owner can withdraw funds in FjordAuctionFactory contract.

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.