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

`FjordAuctionFactory.sol::createAuction` can be create an auction with `totalTokens` value of 0 which will lead to all bidders rewards being 0

## Summary
In the `FjordAuctionFactory` contract the `createAuction` function creates a new auction. However it does not check if `totalTokens` is more than 0. If an auction is created with `totalTokens` being zero this will result in that, when an auction ends and the function `auctionEnd` is called, the `multiplier` will be 0. The bidder of the auction will want to claim their reward, but when they call `claimTokens`, `claimable` will be 0. Essentially transfering 0 tokens to the bidders.
## Vulnerability Details
In the FjordAuctionFactory contract, the createAuction function does not validate that the totalTokens parameter is greater than zero:
https://github.com/Cyfrin/2024-08-fjord/blob/0312fa9dca29fa7ed9fc432fdcd05545b736575d/src/FjordAuctionFactory.sol#L55
This allows the creation of an auction with zero total tokens. The issue manifests in the FjordAuction contract's auctionEnd function:
https://github.com/Cyfrin/2024-08-fjord/blob/0312fa9dca29fa7ed9fc432fdcd05545b736575d/src/FjordAuction.sol#L181
When totalTokens is zero, the multiplier calculation will always result in zero. Consequently, in the claimTokens function:
https://github.com/Cyfrin/2024-08-fjord/blob/0312fa9dca29fa7ed9fc432fdcd05545b736575d/src/FjordAuction.sol#L217
## Impact
1. Wasted Resources by bidders spending gas on bids and potentially lock up their FjordPoints for the duration of the auction, receiving nothing in return.
2. Trust Erosion by participation in zero-reward auctions could severely damage user trust in the Fjord protocol.
3. System Integrity by the existence of such auctions undermines the integrity and perceived fairness of the entire auction system.
## POC
Make a new file into the `invariant` folder and paste the following code:
```solidity
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity =0.8.21;
import { AuctionFactory, FjordAuction } from "../../src/FjordAuctionFactory.sol";
import { FjordPointsMock } from "../mocks/FjordPointsMock.sol";
import { FjordStaking } from "../../src/FjordStaking.sol";
import { LimitedStakeHandler } from "./handler/LimitedStakeHandler.sol";
import { Test, console } from "forge-std/Test.sol";
import { MockERC20 } from "./MockERC20.sol";
contract InvariantTest is Test {
AuctionFactory factory;
FjordAuction public auction;
MockERC20 public fjordPoints;
MockERC20 public auctionToken;
address deployer = makeAddr("deployer");
address owner = makeAddr("owner");
address bidder = makeAddr("bidder");
uint256 biddingTime = 1 hours;
uint256 totalTokens = 0;
bytes32 salt = bytes32(abi.encodePacked("Na Qnko brat mu"));
function setUp() public {
fjordPoints = new MockERC20("Fjord", "FJO");
auctionToken = new MockERC20("auc", "auc");
vm.prank(deployer);
factory = new AuctionFactory(address(fjordPoints));
vm.prank(deployer);
factory.createAuction(address(auctionToken), biddingTime, totalTokens, salt);
auction = FjordAuction(predictCreate2Address(salt));
}
function predictCreate2Address(bytes32 _salt) internal view returns (address) {
bytes memory bytecode = abi.encodePacked(
type(FjordAuction).creationCode,
abi.encode(fjordPoints, auctionToken, biddingTime, totalTokens)
);
bytes32 hash =
keccak256(abi.encodePacked(bytes1(0xff), address(factory), _salt, keccak256(bytecode)));
return address(uint160(uint256(hash)));
}
function testZeroTokensAuction() public {
uint256 amount = 100;
fjordPoints.mint(bidder, amount);
vm.prank(bidder);
fjordPoints.approve(address(auction), type(uint256).max);
// Place a bid
vm.prank(bidder);
auction.bid(amount);
// Fast forward to after auction end
vm.warp(2 hours);
// End the auction
vm.prank(deployer);
auction.auctionEnd();
// // Try to claim tokens
vm.prank(bidder);
auction.claimTokens();
assert(auctionToken.balanceOf(bidder) == 0);
}
}
```
Paste the following
## Tools Used
Manual Review, Foundry Tests
## Recommendations
1. Add a check in the `createAuction` function to ensure `totalTokens` is greater than zero:
```diff
function createAuction(
address auctionToken,
uint256 biddingTime,
uint256 totalTokens,
bytes32 salt
) external onlyOwner {
+ if(totalTokens == 0) revert();
// ... other logic
}
```
2. Implement a minimum `totalTokens` value that makes sense for your protocol's economics.
```diff
+ uint256 minimumTotalTokens;
+ function setMinimumTotalTokens(address _minimumTotalTokens) external onlyOwner {
+ minimumTotalTokens = _minimumTotalTokens;
+ }
function createAuction(
address auctionToken,
uint256 biddingTime,
uint256 totalTokens,
bytes32 salt
) external onlyOwner {
+ if(totalTokens < minimumTotalTokens) revert();
// ... other logic
}
```
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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