NextGen - Nyx's results

Advanced smart contracts for launching generative art projects on Ethereum.

General Information

Platform: Code4rena

Start Date: 30/10/2023

Pot Size: $49,250 USDC

Total HM: 14

Participants: 243

Period: 14 days

Judge: 0xsomeone

Id: 302

League: ETH

NextGen

Findings Distribution

Researcher Performance

Rank: 128/243

Findings: 2

Award: $5.96

🌟 Selected for report: 0

🚀 Solo Findings: 0

Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L104-L120

Vulnerability details

Impact

The auction can be DOSed by the highest bidder, trapping other bidders' funds in the contract.

Proof of Concept

Users can only call the claimAuction() function after the auction end time. Once the auction has ended, the cancelBid function becomes unavailable. If a user dont to use the cancelBid() function before the end time, they will only be able to retrieve their funds with the claimAuction() function.

If the user loses the auction, their funds will be refunded through the claimAuction() function.

else if (auctionInfoData[_tokenid][i].status == true) {
                (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}(""); 
                emit Refund(auctionInfoData[_tokenid][i].bidder, _tokenid, success, highestBid);
            }

The issue is that the highest bidder can potentially cause a Denial of Service (DOS). This can happen if the winner is a contract that hasn't implemented the IERC721Receiver-onERC721Received function. As a result, the safeTransferFrom call will always revert, causing the claimAuction function to be stuck in a DOS attack indefinitely.

for (uint256 i=0; i< auctionInfoData[_tokenid].length; i ++) {
            if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) {
                IERC721(gencore).safeTransferFrom(ownerOfToken, highestBidder, _tokenid);

Tools Used

Manual Review

Create an admin functionality to reset auction time, enabling users to cancel bids and retrieve funds.

Assessed type

DoS

#0 - c4-pre-sort

2023-11-15T07:50:20Z

141345 marked the issue as duplicate of #1653

#1 - c4-pre-sort

2023-11-15T08:06:43Z

141345 marked the issue as duplicate of #843

#2 - c4-pre-sort

2023-11-16T13:36:15Z

141345 marked the issue as duplicate of #486

#3 - c4-judge

2023-12-01T22:35:54Z

alex-ppg marked the issue as not a duplicate

#4 - c4-judge

2023-12-01T22:36:26Z

alex-ppg marked the issue as duplicate of #1759

#5 - c4-judge

2023-12-08T22:13:52Z

alex-ppg marked the issue as partial-50

#6 - c4-judge

2023-12-09T00:23:12Z

alex-ppg changed the severity to 2 (Med Risk)

Awards

5.4864 USDC - $5.49

Labels

bug
2 (Med Risk)
partial-50
duplicate-175

External Links

Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L105 https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L58

Vulnerability details

Impact

The bidder's funds can be stuck in the contract.

Proof of Concept

The participateToAuction() function and the claimAuction can be called simultaneously when the getAuctionEndTime equals block.timestamp, which may lead to issues.

function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){
        require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true);
        auctionClaim[_tokenid] = true;

If both the claimAuction and participateToAuction functions are called at the getAuctionEndTime, funds from the caller of the participateToAuction function may become trapped in the contract.

The claimAuction function can be called by the highest bidder at the end of the auction. Another user can call the participateToAuction function to become the highest bidder at the same time.

function participateToAuction(uint256 _tokenid) public payable {
        require(msg.value > returnHighestBid(_tokenid) && block.timestamp <= minter.getAuctionEndTime(_tokenid) && minter.getAuctionStatus(_tokenid) == true);
        auctionInfoStru memory newBid = auctionInfoStru(msg.sender, msg.value, true);
        auctionInfoData[_tokenid].push(newBid);
    }

Suppose the highest bidder's transaction is included in the block before the user's transaction. In that case, the auction will end but the user's calls to participateToAuction will not revert(Because The participateToAuction is not currently checking whether the auction has already ended or not).

As a result, even if the user doesn't win the auction, they cannot retrieve their funds. The user can not call the cancelBids function because of this check.

function cancelBid(uint256 _tokenid, uint256 index) public {
        require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended");

Tools Used

Manual Review

Don't allow the claimAuction and participateToAuction functions are not callable at the same time.

Assessed type

Other

#0 - c4-pre-sort

2023-11-14T13:52:21Z

141345 marked the issue as duplicate of #1935

#1 - c4-pre-sort

2023-11-14T14:21:30Z

141345 marked the issue as duplicate of #962

#2 - c4-judge

2023-12-02T15:33:17Z

alex-ppg marked the issue as not a duplicate

#3 - c4-judge

2023-12-02T15:35:20Z

alex-ppg marked the issue as duplicate of #1926

#4 - c4-judge

2023-12-08T18:51:10Z

alex-ppg marked the issue as partial-50

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter