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

Auction contract does not check the return value of transfer/transferFrom function calls

Summary

As a best practice, the return values for transfer/transferFrom function should be checked to ensure that the call succeeded or failed.
The implementation of functions FjordAuction does not check the return values for transfer/transferFrom functions.

Vulnerability Details

Refer to the list of functions in FjordAuctionthat makes calls to the ERC20 token contract for transfer or transferFrom, while not checking the return boolean value.

function bid(uint256 amount) external {
if (block.timestamp > auctionEndTime) {
revert AuctionAlreadyEnded();
}
bids[msg.sender] = bids[msg.sender].add(amount);
totalBids = totalBids.add(amount);
--> fjordPoints.transferFrom(msg.sender, address(this), amount);
emit BidAdded(msg.sender, amount);
}
/**
* @notice Allows users to withdraw part or all of their bids before the auction ends.
* @param amount The amount of FjordPoints to withdraw.
*/
function unbid(uint256 amount) external {
if (block.timestamp > auctionEndTime) {
revert AuctionAlreadyEnded();
}
uint256 userBids = bids[msg.sender];
if (userBids == 0) {
revert NoBidsToWithdraw();
}
if (amount > userBids) {
revert InvalidUnbidAmount();
}
bids[msg.sender] = bids[msg.sender].sub(amount);
totalBids = totalBids.sub(amount);
--> fjordPoints.transfer(msg.sender, amount);
emit BidWithdrawn(msg.sender, amount);
}
/**
* @notice Ends the auction and calculates claimable tokens for each bidder based on their bid proportion.
*/
function auctionEnd() external {
if (block.timestamp < auctionEndTime) {
revert AuctionNotYetEnded();
}
if (ended) {
revert AuctionEndAlreadyCalled();
}
ended = true;
emit AuctionEnded(totalBids, totalTokens);
if (totalBids == 0) {
--> 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);
}
/**
* @notice Allows users to claim their tokens after the auction has ended.
*/
function claimTokens() external {
if (!ended) {
revert AuctionNotYetEnded();
}
uint256 userBids = bids[msg.sender];
if (userBids == 0) {
revert NoTokensToClaim();
}
uint256 claimable = userBids.mul(multiplier).div(PRECISION_18);
bids[msg.sender] = 0;
--> auctionToken.transfer(msg.sender, claimable);
emit TokensClaimed(msg.sender, claimable);
}

Impact

There is a potential that the internal account will break if the transfer() or transferFrom() actually fails, but since the return value is being ignored, the calling contract assumes that it will always succeed. This will break the internal accounting for the calling contract.

Tools Used

Manual review

Recommendations

Always check the return values for the transfer() and transferFrom() functions. Some ERC tokens does not follow the standard, hence it is recommended to use safeTransfer functions instead.

Updates

Lead Judging Commences

inallhonesty Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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