Platform: Code4rena
Start Date: 06/09/2022
Pot Size: $90,000 USDC
Total HM: 33
Participants: 168
Period: 9 days
Judge: GalloDaSballo
Total Solo HM: 10
Id: 157
League: ETH
Rank: 34/168
Findings: 3
Award: $599.04
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Jeiwan
Also found by: imare, ladboy233, rvierdiiev
https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/Token.sol#L221 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/metadata/MetadataRenderer.sol#L222
From the documentation https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/docs/protocol-docs.md?plain=1#L121
But a valid/minted NFT token without previously added attributes will revert calling:
[https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/Token.sol#L221](function tokenURI(uint256 _tokenId))
Because src/token/metadata/MetadataRenderer.sol getAttributes uses the number of attributes as a signal of minted token. In case number of attributes is zero than the call will revert with TOKEN_NOT_MINTED That happens even if the tokens is minted and successfully sold at an auction.
Two solutions:
#0 - GalloDaSballo
2022-09-26T22:41:44Z
Dup of #455
🌟 Selected for report: Lambda
Also found by: 0x1337, 0x1f8b, 0x4non, 0x85102, 0xA5DF, 0xNazgul, 0xSmartContract, 0xbepresent, 0xc0ffEE, 8olidity, Aymen0909, B2, Bnke0x0, CRYP70, Captainkay, CertoraInc, Ch_301, Chom, ChristianKuri, CodingNameKiki, Deivitto, Diana, DimitarDimitrov, ElKu, EthLedger, Franfran, Funen, GimelSec, JansenC, Jeiwan, Jujic, Lead_Belly, MEP, MasterCookie, MiloTruck, Noah3o6, PPrieditis, PaludoX0, Picodes, PwnPatrol, R2, Randyyy, RaymondFam, Respx, ReyAdmirado, Rolezn, Samatak, Tointer, Tomo, V_B, Waze, _Adam, __141345__, a12jmx, ak1, asutorufos, azephiar, ballx, bharg4v, bin2chen, bobirichman, brgltd, bulej93, c3phas, cccz, ch0bu, cloudjunky, cryptonue, cryptostellar5, cryptphi, csanuragjain, d3e4, datapunk, davidbrai, delfin454000, dharma09, dic0de, dipp, djxploit, eierina, erictee, fatherOfBlocks, gogo, hansfriese, hyh, imare, indijanc, izhuer, jonatascm, ladboy233, leosathya, lucacez, lukris02, m9800, martin, minhtrng, ne0n, neumo, oyc_109, p_crypt0, pashov, pauliax, pcarranzav, pedr02b2, peritoflores, pfapostol, rbserver, ret2basic, robee, rvierdiiev, sach1r0, sahar, scaraven, sikorico, simon135, slowmoses, sorrynotsorry, tnevler, tonisives, volky, yixxas, zkhorse, zzzitron
61.0218 USDC - $61.02
Impact This behaviour can draw away users because it resembles a possible rugpull
Recommended Mitigation Steps Two posibilities:
Use of whenNotPaused modifier on Auction#createBid call https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/auction/Auction.sol#L90
Stop the process of biding in the application UX/frontend if the auction is paused. And save a little on transaction gas
Constructors should check the address written in an immutable address variable is not the zero address
Proof of Concept
Instances include:
Auction.sol
manager = IManager(_manager);
later the address of manager is again checked as:
if (msg.sender != address(manager)) revert ONLY_MANAGER();
But manager can be mistakenly assigned address(0)
Mitigation
Add a zero address check for manager.
OpenZeppelin’s documentation discourages the use of transferFrom(), use safeTransferFrom() whenever possible. Even for ERC721 tokens.
https://docs.openzeppelin.com/contracts/2.x/api/token/erc721
Recommended Mitigation Steps Mybe insted of direct sending the NTF when the auction is settled implement a user withdrawal pattern. Instead of sending use a map to identify winning addresses. If withdrawal is succesfull delete the queried entrie.
mapping(uint256 => address) internal tokenWinners;
EVM’s ecrecover is susceptible to signature malleability and is recommend using OpenZeppelin’s ECDSA library.
#0 - GalloDaSballo
2022-09-27T00:18:45Z
Disute on #274
L
L
Disputing rest
2L
🌟 Selected for report: pfapostol
Also found by: 0x1f8b, 0x4non, 0x5rings, 0xA5DF, 0xSmartContract, 0xc0ffEE, 0xkatana, Aymen0909, Bnke0x0, CertoraInc, Chandr, CodingNameKiki, Cr4ckM3, Deivitto, DimSon, Franfran, JAGADESH, JC, Jeiwan, Lambda, LeoS, Matin, Metatron, Migue, MiloTruck, PPrieditis, PaludoX0, R2, RaymondFam, Respx, ReyAdmirado, Rolezn, Saintcode_, Samatak, SnowMan, StevenL, Tointer, TomJ, Tomo, WatchDogs, Waze, _Adam, __141345__, ajtra, asutorufos, ballx, brgltd, bulej93, c3phas, ch0bu, dharma09, djxploit, durianSausage, easy_peasy, fatherOfBlocks, gianganhnguyen, gogo, imare, leosathya, lucacez, martin, oyc_109, pauliax, peiw, prasantgupta52, ret2basic, rfa, robee, sikorico, simon135, tofunmi, volky, wagmi, zishansami
45.4138 USDC - $45.41
On line https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/auction/Auction.sol#L172 instead of
if (auction.settled) revert AUCTION_SETTLED();
use previously cached _auction value insted of storage variable read:
if (_auction.settled) revert AUCTION_SETTLED();
instead of
if (_from != _to && _amount > 0) {
use
if (_from != _to && _amount != 0) {
If a function modifier such as onlyOwner is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided. The extra opcodes avoided are CALLVALUE(2),DUP1(3),ISZERO(3),PUSH2(3),JUMPI(10),PUSH1(3),DUP1(3),REVERT(0),JUMPDEST(1),POP(2), which costs an average of about 21 gas per call to the function, in addition to the extra deployment cost
There are 28 instances of this issue.
#0 - GalloDaSballo
2022-09-26T16:09:23Z
100 gas from cache auction