NextGen - circlelooper'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: 65/243

Findings: 3

Award: $96.20

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: smiling_heretic

Also found by: 00decree, 00xSEV, 0x180db, 0x3b, 0x656c68616a, 0xAadi, 0xAleko, 0xAsen, 0xDetermination, 0xJuda, 0xMAKEOUTHILL, 0xMango, 0xMosh, 0xSwahili, 0x_6a70, 0xarno, 0xgrbr, 0xpiken, 0xsagetony, 3th, 8olidity, ABA, AerialRaider, Al-Qa-qa, Arabadzhiev, AvantGard, CaeraDenoir, ChrisTina, DanielArmstrong, DarkTower, DeFiHackLabs, Deft_TT, Delvir0, Draiakoo, Eigenvectors, Fulum, Greed, HChang26, Haipls, Hama, Inference, Jiamin, JohnnyTime, Jorgect, Juntao, Kaysoft, Kose, Kow, Krace, MaNcHaSsS, Madalad, MrPotatoMagic, Neon2835, NoamYakov, Norah, Oxsadeeq, PENGUN, REKCAH, Ruhum, Shubham, Silvermist, Soul22, SovaSlava, SpicyMeatball, Talfao, TermoHash, The_Kakers, Toshii, TuringConsulting, Udsen, VAD37, Vagner, Zac, Zach_166, ZdravkoHr, _eperezok, ak1, aldarion, alexfilippov314, alexxander, amaechieth, aslanbek, ast3ros, audityourcontracts, ayden, bdmcbri, bird-flu, blutorque, bronze_pickaxe, btk, c0pp3rscr3w3r, c3phas, cartlex_, cccz, ciphermarco, circlelooper, crunch, cryptothemex, cu5t0mpeo, darksnow, degensec, dethera, devival, dimulski, droptpackets, epistkr, evmboi32, fibonacci, gumgumzum, immeas, innertia, inzinko, jasonxiale, joesan, ke1caM, kimchi, lanrebayode77, lsaudit, mahyar, max10afternoon, merlin, mrudenko, nuthan2x, oakcobalt, openwide, orion, phoenixV110, pontifex, r0ck3tz, rotcivegaf, rvierdiiev, seeques, shenwilly, sl1, slvDev, t0x1c, tallo, tnquanghuy0512, tpiliposian, trachev, twcctop, vangrim, volodya, xAriextz, xeros, xuwinnie, y4y, yobiz, zhaojie

Awards

0 USDC - $0.00

Labels

bug
3 (High Risk)
partial-50
duplicate-1323

External Links

Lines of code

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

Vulnerability details

Impact

Highest bidder can cancel the bid right after claiming the token.

Proof of Concept

A token minted for auction, it can be claimed by the highest bidder right after the auction ends.

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

The bid can also be cancelled at the end of the auction.

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

It can be seen that if block.timestamp is minter.getAuctionEndTime(_tokenid), the token can be claimed and cancelled in the same transaction.

function getAuctionEndTime(uint256 _tokenId) external view returns (uint) { return mintToAuctionData[_tokenId]; }

This results in the highest bidder receives the token but not pays a price.

Tools Used

Manual Review

Please consider to change the requirement and not allow the token to be claimed at auction end time.

Assessed type

Access Control

#0 - c4-pre-sort

2023-11-15T07:46:33Z

141345 marked the issue as duplicate of #962

#1 - c4-judge

2023-12-01T15:25:56Z

alex-ppg marked the issue as not a duplicate

#2 - c4-judge

2023-12-01T15:26:05Z

alex-ppg marked the issue as duplicate of #1788

#3 - c4-judge

2023-12-08T18:05:47Z

alex-ppg marked the issue as partial-50

Findings Information

Labels

bug
2 (Med Risk)
downgraded by judge
partial-50
duplicate-1597

Awards

95.7343 USDC - $95.73

External Links

Lines of code

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

Vulnerability details

Impact

Owner of burnToMint token can frontrun secondary sales.

Proof of Concept

The collection token can be traded on secondary market, since they are standard ERC721 tokens.

In a Burn-to-Mint sale model, a collection token can be burned to minted a different collection token, this is done through burnToMint method.

The minted token will be transferred to the receiver through ERC721's _safeMint method, which will call _checkOnERC721Received method if the receiver is a contract.

Then the collection token used for minting will be burned.

if (collectionAdditionalData[_mintCollectionID].collectionTotalSupply >= collectionAdditionalData[_mintCollectionID].collectionCirculationSupply) { _mintProcessing(mintIndex, ownerOf(_tokenId), tokenData[_tokenId], _mintCollectionID, _saltfun_o); // burn token _burn(_tokenId); burnAmount[_burnCollectionID] = burnAmount[_burnCollectionID] + 1; }

The problem is the _checkOnERC721Received method in the receiver contract, a bad actor may sell the to-be-burned collection token after receiving the new collection token, the buyer of the to-be-burned collection token will get the token and lose it immediately, because the token will be burned then.

Tools Used

Manual Review

Please consider to burn the to-be-burned collection token, then mint the new collection token.

Assessed type

Access Control

#0 - c4-pre-sort

2023-11-20T02:25:39Z

141345 marked the issue as duplicate of #1198

#1 - c4-pre-sort

2023-11-20T09:25:03Z

141345 marked the issue as duplicate of #1597

#2 - c4-pre-sort

2023-11-26T14:00:13Z

141345 marked the issue as duplicate of #1742

#3 - c4-judge

2023-11-29T19:54:35Z

alex-ppg marked the issue as not a duplicate

#4 - c4-judge

2023-11-29T19:54:59Z

alex-ppg marked the issue as duplicate of #1597

#5 - c4-judge

2023-12-05T12:24:54Z

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

#6 - c4-judge

2023-12-08T21:24:54Z

alex-ppg marked the issue as partial-50

Lines of code

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

Vulnerability details

Impact

Auction refunding can be DOSed by malicious winner.

Proof of Concept

Auction winner is supposed to claim token after an auction, or the admins can claim for him, the other bidders will be refunded at the claiming.

function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){ ... 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); (bool success, ) = payable(owner()).call{value: highestBid}(""); emit ClaimAuction(owner(), _tokenid, success, highestBid); } 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); } else {} } }

This method will loop through all the bidders, if the bidder is the winner, the token will be transferred to the winner through safeTransferFrom method, if the winner is a contract, onERC721Received method will be called in the receiver contract.

function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory data ) private returns (bool) { if (to.isContract()) { try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) { return retval == IERC721Receiver.onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert("ERC721: transfer to non ERC721Receiver implementer"); } else { /// @solidity memory-safe-assembly assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } }

If the bidder is not the winner, the ether will be refunded to the bidder.

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

If the winner is being malicious and revert on purpose in the onERC721Received method, then the whole claiming will fail and the other bidders won't be refunded and their ether will be locked.

Please note it's not necessarily mean that the winner will lose the token as he can make the receiver contract to accept the token at any time he wants to.

Tools Used

Manual Review

Please consider to separate refunding from claiming, so the bidders can be refunded even if the claiming is failed.

Assessed type

Access Control

#0 - c4-pre-sort

2023-11-15T07:46:16Z

141345 marked the issue as duplicate of #1653

#1 - c4-pre-sort

2023-11-15T08:06:48Z

141345 marked the issue as duplicate of #843

#2 - c4-pre-sort

2023-11-16T13:36:20Z

141345 marked the issue as duplicate of #486

#3 - c4-judge

2023-12-01T22:34:26Z

alex-ppg marked the issue as not a duplicate

#4 - c4-judge

2023-12-01T22:34:51Z

alex-ppg marked the issue as duplicate of #1759

#5 - c4-judge

2023-12-08T22:13:38Z

alex-ppg marked the issue as partial-50

#6 - c4-judge

2023-12-09T00:23:13Z

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

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