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: 69/168
Findings: 2
Award: $136.39
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 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
90.7735 USDC - $90.77
It is better choice for the function to use return statement (bool success), instead of adding the bool variable out of nowhere: https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/treasury/Treasury.sol#L164
Recommend: Applying return statement on the fuction execute() and replacing the "bool success" in the fuction only with "success". https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/treasury/Treasury.sol#L141-L146
(Before) 141: function execute( address[] calldata _targets, uint256[] calldata _values, bytes[] calldata _calldatas, bytes32 _descriptionHash) external payable onlyOwner { (After) 141: function execute( address[] calldata _targets, uint256[] calldata _values, bytes[] calldata _calldatas, bytes32 _descriptionHash) external payable onlyOwner returns (bool success){
(Before) 164: (bool success, ) = _targets[i].call{ value: _values[i] }(_calldatas[i]); (After) 164: (success, ) = _targets[i].call{ value: _values[i] }(_calldatas[i]);
https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/treasury/ITreasury.sol#L107-L112 (Before) 107: function execute( address[] calldata targets, uint256[] calldata values, bytes[] calldata calldatas, bytes32 descriptionHash) external payable; (After) 107: function execute( address[] calldata targets, uint256[] calldata values, bytes[] calldata calldatas, bytes32 descriptionHash) external payable returns (bool success);
Proper use of _ as a function name prefix A common pattern is to prefix internal and private function names with _. This pattern is correctly applied in the Nouns Builder contracts, however there are some inconsistencies in the libraries.
https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/lib/utils/Address.sol#L25 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/lib/utils/Address.sol#L30 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/lib/utils/Address.sol#L37 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/lib/utils/Address.sol#L46 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/lib/utils/SafeCast.sol#L9 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/lib/utils/SafeCast.sol#L15 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/lib/utils/SafeCast.sol#L21 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/lib/utils/SafeCast.sol#L27 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/lib/utils/SafeCast.sol#L33 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/lib/utils/SafeCast.sol#L39 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/lib/utils/SafeCast.sol#L45
There is no reason to add payable to the constructor in these situations. The "payable" keyword is used, when you want the constructor to accept Ether on the deploying time. If for some reason Ether is sent to the contract on deploying time, the ether will be stuck in the contract without a way for retrieving it, because there isn't a single function for sending this particular Ether out of the contract.
https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/metadata/MetadataRenderer.sol#L32 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/Token.sol#L30 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/Manager.sol#L55 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/Governor.sol#L41 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/treasury/Treasury.sol#L32 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/auction/Auction.sol#L39
Clear function names can increase readability. Follow a standard convertion function names such as using get for getter (view/pure) functions. Examples:
src/auction/Auction.sol (Before) 277: function treasury() external view returns (address) { (After) 277: function getTreasuryAddress() external view returns (address) { (Before) 282: function duration() external view returns (uint256) { (After) 282: function getAuctionDuration() external view returns (uint256) { (Before) 287: function reservePrice() external view returns (uint256) { (After) 287: function getAuctionReservePrice() external view returns (uint256) { (Before) 292: function timeBuffer() external view returns (uint256) { (After) 292: function getMinimumTimeBuffer() external view returns (uint256) {
Use OpenZeppelin's ECDSA contract rather than calling ecrecover() directly.
https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/Governor.sol#L27 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/lib/token/ERC721Votes.sol#L21 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/lib/utils/EIP712.sol#L19
In the contracts, floating pragmas should not be used. Contracts should be deployed with the same compiler version and flags that they have been tested with thoroughly. Locking the pragma helps to ensure that contracts do not accidentally get deployed using, for example, an outdated compiler version that might introduce bugs that affect the contract system negatively.
All contracts in the library section - https://github.com/code-423n4/2022-09-nouns-builder/tree/main/src/lib
Constructors should check the address written in an immutable address variable is not the zero address
https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/auction/Auction.sol#L40 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/auction/Auction.sol#L41 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/Governor.sol#L42 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/treasury/Treasury.sol#L33 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/Manager.sol#L62 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/Manager.sol#L63 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/Manager.sol#L64 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/Manager.sol#L65 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/Manager.sol#L66 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/Token.sol#L31 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/metadata/MetadataRenderer.sol#L33
_mint() is discouraged in favor of _safeMint() which ensures that the recipient is either an EOA or implements IERC721Receiver. Both OpenZeppelin and solmate have versions of this function
https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/Token.sol#L161 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/Token.sol#L169 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/Token.sol#L188
Auction Upgrade - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/auction/Auction.sol#L374 Governor Upgrade - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/Governor.sol#L618 Treasury Upgrade - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/treasury/Treasury.sol#L278 Manager Upgrade -https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/Manager.sol#L209 Token Upgrade - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/Token.sol#L305 Metadata Upgrade - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/metadata/MetadataRenderer.sol#L376
Consider adding a two-phase transfer, where the current owner nominates the next owner, and the next owner has to call accept*() to become the new owner. This prevents passing the ownership to an account that is unable to use it.
https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/Token.sol#L30 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/metadata/MetadataRenderer.sol#L32 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/Governor.sol#L41 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/treasury/Treasury.sol#L32 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/auction/Auction.sol#L39
https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/auction/Auction.sol#L374 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/Governor.sol#L618 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/treasury/Treasury.sol#L278 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/Manager.sol#L209 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/Token.sol#L305 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/metadata/MetadataRenderer.sol#L376
Consider defining in only one contract so that values cannot become out of sync when only one location is updated. A cheap way to store constants in a single location is to create an internal constant in a library. If the variable is a local cache of another contract's value, consider making the cache variable internal or private, which will require external users to query the contract with the source of truth, so that callers don't get out of sync.
https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/Manager.sol#L25 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/Manager.sol#L28 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/Manager.sol#L31 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/Manager.sol#L34 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/Manager.sol#L37
Not all IERC20 implementations revert() when there’s a failure in transfer(). The function signature has a boolean return value and they indicate errors that way instead. By not checking the return value, operations that should have marked as failed, may potentially go through without actually making a payment
Events should use indexed fields
https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/auction/IAuction.sol#L22 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/auction/IAuction.sol#L28 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/auction/IAuction.sol#L34 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/auction/IAuction.sol#L38 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/auction/IAuction.sol#L42 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/auction/IAuction.sol#L46 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/auction/IAuction.sol#L50 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/IGovernor.sol#L18 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/IGovernor.sol#L29 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/IGovernor.sol#L33 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/IGovernor.sol#L36 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/IGovernor.sol#L39 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/IGovernor.sol#L42 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/IGovernor.sol#L45 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/IGovernor.sol#L48 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/IGovernor.sol#L51 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/IGovernor.sol#L54 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/IGovernor.sol#L57 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/treasury/ITreasury.sol#L16 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/treasury/ITreasury.sol#L19 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/treasury/ITreasury.sol#L22 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/treasury/ITreasury.sol#L25 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/treasury/ITreasury.sol#L28 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/IManager.sol#L21 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/IManager.sol#L26 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/IManager.sol#L31 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/IToken.sol#L21 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/metadata/interfaces/IPropertyIPFSMetadataRenderer.sol#L16 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/metadata/interfaces/IPropertyIPFSMetadataRenderer.sol#L19 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/metadata/interfaces/IPropertyIPFSMetadataRenderer.sol#L22 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/metadata/interfaces/IPropertyIPFSMetadataRenderer.sol#L25 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/metadata/interfaces/IPropertyIPFSMetadataRenderer.sol#L28
If the intention is for the Ether to be used, the function should call another function, otherwise it should revert (e.g. require(msg.sender == address(weth)))
Use abi.encode() instead which will pad items to 32 bytes, which will prevent hash collisions (e.g. abi.encodePacked(0x123,0x456) => 0x123456 => abi.encodePacked(0x1,0x23456), but abi.encode(0x123,0x456) => 0x0...1230...456). “Unless there is a compelling reason, abi.encode should be preferred”. If there is only one argument to abi.encodePacked() it can often be cast to bytes() or bytes32() instead.
https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/Governor.sol#L226 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/Manager.sol#L68 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/Manager.sol#L69 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/Manager.sol#L70 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/manager/Manager.sol#L71
https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/auction/Auction.sol#L81 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/auction/Auction.sol#L119 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/auction/Auction.sol#L80
Low level calls return success if called on a destructed contract. See OpenZeppelin’s Address.so which checks address.code.length
Auction.sol is specifically involve in ERC721 tokens. Therefore the contract should implement ERC721TokenReceiver, or customer transfers involving transferFrom() calls will revert
https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/lib/utils/ReentrancyGuard.sol#L14 https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/lib/utils/ReentrancyGuard.sol#L17
#0 - GalloDaSballo
2022-09-26T21:24:01Z
3 R
Expressions for constant values such as a call to keccak256() is prefered to use immutable rather than constant. Not valid
Floating pragma version in the libraries NC
Immutable addresses lack zero-address check. L
_safeMint() should be used rather than _mint, whenever possible. Invalid
Several critical operations do not trigger events, which will make it difficult to review the correct behavior of the contracts once deployed. In this case the owner upgrades the contract, whithout using event. NC
Use two-phase ownership transfers Disputed it's available
Constant redefined elsewhere R
Constants should be defined rather than using magic numbers NC
State/flags should use enums rather than separate constants. R
Formatting should be improved, some findings are too copy pasta/ but the valid ones are pretty good
1L 5R 2NC
🌟 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.6207 USDC - $45.62
In the following function, setting.timebuffer should be cached as it is read several times.
Create a cache: uint256 cache = setting.timebuffer and replace them. src/auction/Auction.sol (Before) 141: extend = (_auction.endTime - block.timestamp) < settings.timeBuffer; (After) 141: extend = (_auction.endTime - block.timestamp) < cache;
(Before) 149: auction.endTime = uint40(block.timestamp + settings.timeBuffer); (After) 149: auction.endTime = uint40(block.timestamp + cache);
In the following function, auction.settled should be cached as it is read several times
Create a cache: bool settled = auction.settled and replace them. src/auction/Auction.sol (Before) 172: if (auction.settled) revert AUCTION_SETTLED(); (After) 172: if (settled) revert AUCTION_SETTLED();
(Before) 181: auction.settled = true; (After) 181: settled = true;
Using storage pointer instead of memory location can save a decent amount of gas.
a) The first function is createBid(), make sure to declare the memory location to a storage one
src/auction/Auction.sol (Before) 92: Auction memory _auction = auction; (After) 92: Auction storage _auction = auction;
And replacing the storage cache with these three saves extra gas. (Before) 130: auction.highestBid = msg.value; (After) 130: _auction.highestBid = msg.value;
(Before) 133: auction.highestBidder = msg.sender; (After) 133: _auction.highestBidder = msg.sender;
(Before) 149: auction.endTime = uint40(block.timestamp + settings.timeBuffer); (After) 149: _auction.endTime = uint40(block.timestamp + settings.timeBuffer);
b) The second function is _settleAuction(), make sure to declared the memory location to a storage one
src/auction/Auction.sol (Before) 169: Auction memory _auction = auction; (After) 169: Auction storage _auction = auction;
And replacing the storage cache with these two saves extra gas. (Before) 172: if (auction.settled) revert AUCTION_SETTLED(); (After) 172: if (_auction.settled) revert AUCTION_SETTLED();
(Before) 181: auction.settled = true; (After) 181: _auction.settled = true;
There is no need for boolean comprasions, so l am going to delete the "true". (Before) 181: _auction.settled = true; (After) 181: !_auction.settled;
// Note that the b) method can't be used at the same time with the "2. Storing "auction.settled" into bool cache ", this here saves a lot more gas than the bool cache.
-In the function cancle() - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/Governor.sol#L353
a) l am going to replace the memory location with storage: (Before) 358: Proposal memory proposal = proposals[_proposalId]; (After) 358: Proposal storage proposal = proposals[_proposalId];
b) After that l will replace the "proposals[_proposalId].canceled" with the storage variable "proposal", instead of fetching the reference in a map or an array: (Before) 368: proposals[_proposalId].canceled = true; (After) 368: proposal.canceled = true;
d) And finally there is no need for boolean comprasions, so l am going to delete the "true". (Before) 368: proposal.canceled = true; (After) 368: !proposal.canceled;
-In the function veto() - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/Governor.sol#L385
a) same as the last function, the boolean comprasions is no needed and therefore we will delete the "true" to save gas. (Before) 396: proposal.vetoed = true; (After) 396: !proposal.vetoed;
-In the function state() - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/Governor.sol#L413
a) going to replace the memory location with storage. (Before) 415: Proposal memory proposal = proposals[_proposalId]; (After) 415: Proposal storage proposal = proposals[_proposalId];
-In the function execute() - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/Governor.sol#L324
a) same as the last function, the boolean comprasions is no needed and therefore we will delete the "true" to save gas. (Before) 337: proposals[proposalId].executed = true; (After) 337: !proposals[proposalId].executed;
-In the function _castVote() - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/Governor.sol#L248
a) ">=" cost less gas than ">" The compiler uses opcodes GT and ISZERO for solidity code that uses >, but only requires LT for >=, which saves gas. (Before) 261: if (_support > 2) revert INVALID_VOTE(); (After) 261: if (_support >= 3) revert INVALID_VOTE();
b) same as the last function, the boolean comprasions is no needed and therefore we will delete the "true" to save gas. (Before) 264: hasVoted[_proposalId][_voter] = true; (After) 264: !hasVoted[_proposalId][_voter];
-In the function propose() - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/governor/Governor.sol#L116
a) l am going to create two caches for the arrays "_value.length" and "_calldata.length" (Add) 133: + uint256 numValue = _values.length; (Add) 134: + uint256 numCalldatas = _calldatas.length; (Before) 138: if (numTargets != _values.length) revert PROPOSAL_LENGTH_MISMATCH(); (After) 138: if (numTargets != numValue) revert PROPOSAL_LENGTH_MISMATCH(); (Before) 139: if (numTargets != _calldatas.length) revert PROPOSAL_LENGTH_MISMATCH(); (After) 139: if (numTargets != numCalldatas) revert PROPOSAL_LENGTH_MISMATCH();
-In the function queue() - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/treasury/Treasury.sol#L116
a) l am going to create an uint cache, which will hold timestamps[_proposalId]. (Add) 126: + uint _timestamps = timestamps[_proposalId]; (Before) 127: timestamps[_proposalId] = eta; (After) 127: _timestamps = eta;
-In the function execute() - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/treasury/Treasury.sol#L141
a) l am going to create and uint cache, which will hold timestamps[proposalId] (Add) 153: + uint _timestamps = timestamps[proposalId]; (Before) 154: delete timestamps[proposalId]; (After) 154: delete _timestamps;
b) setting variables as their default values is unnecessary and wastes gas. (Before) 162: for (uint256 i = 0; i < numTargets; ++i) { (After) 162: for (uint256 i; i < numTargets; ++i) {
-In the function cancel() - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/governance/treasury/Treasury.sol#L180
a) l am going to create and uint cache, which will hold timestamps[proposalId] (Add) 184: + uint _timestamps = timestamps[_proposalId]; (Before) 185: delete timestamps[_proposalId]; (After) 185: delete _timestamps;
-In the function _addFounders() - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/Token.sol#L71
a) ">=" cost less gas than ">" (Before) 88: if ((totalOwnership += uint8(founderPct)) > 100) revert INVALID_FOUNDER_OWNERSHIP(); (After) 88: if ((totalOwnership += uint8(founderPct)) >= 101) revert INVALID_FOUNDER_OWNERSHIP();
b) l am going to create a storage for the struct "Founder", which will replace "tokenRecipient[baseTokenId]". (Add) 112: + Founder storage _tokenRecipient = tokenRecipient[baseTokenId]; (Before) 113: tokenRecipient[baseTokenId] = newFounder; (After) 113: _tokenRecipient = newFounder;
-In the function _getNextTokenId() - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/Token.sol#L130
a) l am going to create a storage for the mapping "Founder", which will replace "tokenRecipient[_tokenId]", instead of repeatedly fetching the reference in a map or an array. (Add) 131: +Founder storage _tokenRecipient = tokenRecipient[_tokenId]; (Before) 132: while (tokenRecipient[_tokenId].wallet != address(0)) ++_tokenId; (After) 132: while (_tokenRecipient.wallet != address(0)) ++_tokenId;
-In the function _isForFounder() - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/Token.sol#L177
a) l am going to create a storage for the mapping "Founder", which will replace "tokenRecipient[baseTokenId]", instead of repeatedly fetching the reference in a map or an array. (Add) 181: + Founder storage _tokenRecipient = tokenRecipient[baseTokenId]; (Before) 182: if (tokenRecipient[baseTokenId].wallet == address(0)) { (After) 182: if (_tokenRecipient.wallet == address(0)) { (Before) 186: } else if (block.timestamp < tokenRecipient[baseTokenId].vestExpiry) { (After) 186: } else if (block.timestamp < _tokenRecipient.vestExpiry) { (Before) 188: _mint(tokenRecipient[baseTokenId].wallet, _tokenId); (After) 188: _mint(_tokenRecipient.wallet, _tokenId);
-In the function addProperties() - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/metadata/MetadataRenderer.sol#L91
a) No need to explicitly initialize variables with default values: (Before) 119: for (uint256 i = 0; i < numNewProperties; ++i) { (After) 119: for (uint256 i; i < numNewProperties; ++i) { (Before) 133: for (uint256 i = 0; i < numNewItems; ++i) { (After) 133: for (uint256 i; i < numNewItems; ++i) {
-In the function onMinted() - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/metadata/MetadataRenderer.sol#L171
a) No need to explicitly initialize variables with default values: (Before) 189: for (uint256 i = 0; i < numProperties; ++i) { (After) 189: for (uint256 i; i < numProperties; ++i) {
b) creating a uint cache, which will hold "tokenAttributes[i + 1]" (Add) 193: + uint256 _tokenAttributes = tokenAttributes[i + 1]; (Before) 194: tokenAttributes[i + 1] = uint16(seed % numItems); (After) 194: _tokenAttributes = uint16(seed % numItems);
-In the function getAttributes() - https://github.com/code-423n4/2022-09-nouns-builder/blob/7e9fddbbacdd7d7812e912a369cfd862ee67dc03/src/token/metadata/MetadataRenderer.sol#L206
a) Using storage pointer instead of memory location can save a decent amount of gas. (Before) 216: uint16[16] memory tokenAttributes = attributes[_tokenId]; (After) 216: uint16[16] storage tokenAttributes = attributes[_tokenId]; (Before) 234: Property memory property = properties[i]; (After) 234: Property storage property = properties[i]; (Before) 240: Item memory item = property.items[attribute]; (After) 240: Item storage item = property.items[attribute];
b) No need to explicitly initialize variables with default values: (Before) 229: for (uint256 i = 0; i < numProperties; ++i) { (After) 229: for (uint256 i; i < numProperties; ++i) {
#0 - GalloDaSballo
2022-09-18T16:41:55Z
Roughly 500 gas