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: 163/168
Findings: 1
Award: $45.41
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 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.4145 USDC - $45.41
Use a solidity version of at least 0.8.2 to get simple compiler automatic inlining Use a solidity version of at least 0.8.3 to get better struct packing and cheaper multiple storage reads Use a solidity version of at least 0.8.4 to get custom errors, which are cheaper at deployment than revert()/require()
strings Use a solidity version of at least 0.8.10 to have external calls skip contract existence checks if the external call has a return value
ERC1967Proxy.sol:L2 UUPS.sol:L2 ERC1967Upgrade.sol:L2 ERC721Votes.sol:L2 ERC721.sol:L2
src/lib/proxy/ERC1967Proxy.sol:2:pragma solidity ^0.8.4; src/lib/proxy/UUPS.sol:2:pragma solidity ^0.8.4; src/lib/proxy/ERC1967Upgrade.sol:2:pragma solidity ^0.8.4; src/lib/token/ERC721Votes.sol:2:pragma solidity ^0.8.4; src/lib/token/ERC721.sol:2:pragma solidity ^0.8.4;
As notDelegated() is only used once in this contract (in function proxiableUUID()), it should get inlined to save gas:
src/lib/proxy/UUPS.sol:32: modifier notDelegated() {
src/lib/proxy/UUPS.sol:61: function proxiableUUID() external view notDelegated returns (bytes32) {
mapping
of an address
to a struct
, where appropriateSaves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot. Finally, if both fields are accessed in the same function, can save ~42 gas per access due to not having to recalculate the key's keccak256 hash (Gkeccak256 - 30 gas) and that calculation's associated stack operations.
There are 2 instances of this issue:
ERC721Votes.sol:L29 ERC721Votes.sol:L33 ERC721Votes.sol:L37
src/lib/token/ERC721Votes.sol:29: mapping(address => address) internal delegation; src/lib/token/ERC721Votes.sol:33: mapping(address => uint256) internal numCheckpoints; src/lib/token/ERC721Votes.sol:37: mapping(address => mapping(uint256 => Checkpoint)) internal checkpoints;
ERC721.sol:L26 ERC721.sol:L30 ERC721.sol:L34 ERC721.sol:L38
src/lib/token/ERC721.sol:26: mapping(uint256 => address) internal owners; src/lib/token/ERC721.sol:30: mapping(address => uint256) internal balances; src/lib/token/ERC721.sol:34: mapping(uint256 => address) internal tokenApprovals; src/lib/token/ERC721.sol:38: mapping(address => mapping(address => bool)) internal operatorApprovals;
abi.encodePacked()
 not abi.encode()
Changing abi.encode
 to abi.encodePacked
 can save gas. abi.encode
pads extra null bytes at the end of the call data which is normally unnecessary. In general, abi.encodePacked
is more gas-efficient.
MetadataRenderer.sol:L251 Manager.sol:L68 Manager.sol:L69 Manager.sol:L70 Manager.sol:L71 ERC721Votes.sol:L162 Governor.sol:L104 Governor.sol:L230 Treasury.sol:L107
src/token/metadata/MetadataRenderer.sol:251: return uint256(keccak256(abi.encode(_tokenId, blockhash(block.number), block.coinbase, block.timestamp))); src/manager/Manager.sol:68: metadataHash = keccak256(abi.encodePacked(type(ERC1967Proxy).creationCode, abi.encode(_metadataImpl, ""))); src/manager/Manager.sol:69: auctionHash = keccak256(abi.encodePacked(type(ERC1967Proxy).creationCode, abi.encode(_auctionImpl, ""))); src/manager/Manager.sol:70: treasuryHash = keccak256(abi.encodePacked(type(ERC1967Proxy).creationCode, abi.encode(_treasuryImpl, ""))); src/manager/Manager.sol:71: governorHash = keccak256(abi.encodePacked(type(ERC1967Proxy).creationCode, abi.encode(_governorImpl, ""))); src/lib/token/ERC721Votes.sol:162: abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), keccak256(abi.encode(DELEGATION_TYPEHASH, _from, _to, nonces[_from]++, _deadline))) src/governance/governor/Governor.sol:104: return keccak256(abi.encode(_targets, _values, _calldatas, _descriptionHash)); src/governance/governor/Governor.sol:230: keccak256(abi.encode(VOTE_TYPEHASH, _voter, _proposalId, _support, nonces[_voter]++, _deadline)) src/governance/treasury/Treasury.sol:107: return keccak256(abi.encode(_targets, _values, _calldatas, _descriptionHash));
You should change abi.encode to abi.encodePacked
If needed, the values can be read from the verified contract source code, or if there are multiple values there can be a single getter function that returns a tuple of the values of all currently-public constants. Saves 3406-3606 gas in deployment gas due to the compiler not having to create non-payable getter functions for deployment calldata, not having to store the bytes of the value outside of where it’s used, and not adding another entry to the method ID table
Governor.sol:L27 Manager.sol:L25 Manager.sol:L28 Manager.sol:L31 Manager.sol:L34 Manager.sol:L37
src/governance/governor/Governor.sol:27: bytes32 public constant VOTE_TYPEHASH = keccak256("Vote(address voter,uint256 proposalId,uint256 support,uint256 nonce,uint256 deadline)"); src/manager/Manager.sol:25: address public immutable tokenImpl; src/manager/Manager.sol:28: address public immutable metadataImpl; src/manager/Manager.sol:31: address public immutable auctionImpl; src/manager/Manager.sol:34: address public immutable treasuryImpl; src/manager/Manager.sol:37: address public immutable governorImpl;
#0 - GalloDaSballo
2022-09-26T20:18:51Z
100
50
150
Rest is misguided