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

Auction tokens can be blocked forever in 'FjordAuctionFactory'.

Vulnerability details

'FjordAuctionFactory' is able to create new auctions, when this happens, the caller send the total amount of 'auctionToken' to the auction address.

Users can bid and unbid in that auction, but if there are not bids, the total amount of 'auctionTokens' will be sent back to the 'FjordAuctionFactory' that has not the logic to withdraw / manage them.

Impact

All the funds that are given back to 'FjordAuctionFactory' from an auction will result as lost.

POC

(Using Foundry).

function test_vulnerability_lossOfFundsInFjordAuction(uint256 amount) public {
vm.startPrank(minter);
//Give 2000 Fjord to minter
deal(address(fjordToken), minter, 2000e18);
ERC20(fjordToken).approve(address(fjordStaking), 2000e18);
fjordStaking.addReward(2000e18);
vm.stopPrank();
address gianni = address(123);
vm.startPrank(gianni);
deal(address(fjordToken), gianni, 1_000e18); //assigns 1.000 FJORD to Gianni
uint256 startingGianniBalance = ERC20(fjordToken).balanceOf(address(gianni));
//Approve the staking contract to spend FJORD tokens
ERC20(fjordToken).approve(address(fjordStaking), type(uint256).max);
amount = bound(amount, 1, 1_000); // 1 - 1.000 FJORD
//stake
fjordStaking.stake(amount);
//skip 5 weeks
skip(5 weeks);
//claim
fjordPoints.claimPoints();
//create auction
vm.startPrank(owner);
bytes32 salt = bytes32(keccak256(abi.encode("Pepe to the moon")));
address auctionToken = 0x6982508145454Ce325dDbE47a25d4ec3d2311933; //Pepe address
uint256 biddingTime = 7 days;
uint256 totalTokens = 1_000_000;
deal(auctionToken, owner, 2_000_000);
ERC20(auctionToken).approve(address(auctionFactory), 2_000_000);
address expectedAuctionFactory = 0x754a33fFD5f284EDE3e98f6fa0a186C1527D0AC6; //I got this address just by using the foundry console log with -vvvvv, in this way i got the emitted address
fjordAuction = FjordAuction(expectedAuctionFactory);
auctionFactory.createAuction(auctionToken, biddingTime, totalTokens, salt);
assertEq(ERC20(auctionToken).balanceOf(address(fjordAuction)), 1_000_000); //When the auction is created, fjord auction has 1.000.000 PEPE token
vm.stopPrank();
//No bids
//End auction
skip(7 days);
fjordAuction.auctionEnd();
//See balances
assertEq(ERC20(auctionToken).balanceOf(address(fjordAuction)), 0); //When the auction is ended, fjord auction has 0 PEPE token
assertEq(ERC20(auctionToken).balanceOf(address(auctionFactory)), 1_000_000); //When the auction is ended, fjord auction factory has now 1.000.000 PEPE token but those can be withdrawed because there is not a logic to do that!!
}

Tools Used

Manual review, Foundry

Recommendations

It is highly suggested to implement a function that allow the owner of 'FjordAuctionFactory' to withdraw those funds.

In 'FjordAuctionFactory' consider implementing this logic:

function manageTokens(address token, uint256 amount, address to) public onlyOwner {
IERC20(token).transfer(to, amount);
}
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.