Platform: Code4rena
Start Date: 12/07/2022
Pot Size: $75,000 USDC
Total HM: 16
Participants: 100
Period: 7 days
Judge: LSDan
Total Solo HM: 7
Id: 145
League: ETH
Rank: 90/100
Findings: 1
Award: $39.87
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0xKitsune
Also found by: 0x040, 0x1f8b, 0x29A, 0xNazgul, 0xNineDec, 0xsam, 8olidity, Aussie_Battlers, Aymen0909, Bnke0x0, CRYP70, Ch_301, Chom, Deivitto, Dravee, ElKu, Fitraldys, Funen, GimelSec, IllIllI, JC, JohnSmith, Lambda, MiloTruck, Noah3o6, RedOneN, ReyAdmirado, Rohan16, Rolezn, Ruhum, Sm4rty, TomJ, Tomio, Waze, _Adam, __141345__, ajtra, ak1, arcoun, asutorufos, benbaessler, brgltd, bulej93, c3phas, cRat1st0s, cryptonue, delfin454000, durianSausage, fatherOfBlocks, gogo, hake, hyh, joestakey, karanctf, kyteg, lcfr_eth, lucacez, m_Rassska, rajatbeladiya, rbserver, robee, rokinot, sach1r0, sahar, samruna, sashik_eth, seyni, simon135, zuhaibmohd
39.8689 USDC - $39.87
[G-1]- USE CALLDATA INSTEAD OF MEMORY FOR FUNCTION PARAMETERS TYPE :
If a reference type function parameter is read-only, it is cheaper in gas to use calldata instead of memory. Calldata is a non-modifiable, non-persistent area where function arguments are stored, and behaves mostly like memory.
File: contracts/dnssec-oracle/DNSSECImpl.sol line 80 : function verifyRRSet(RRSetWithSignature[] memory input) external virtual view override returns(bytes memory) line 91 : function verifyRRSet(RRSetWithSignature[] memory input, uint256 now) public virtual view override returns(bytes memory) File: contracts/wrapper/ERC1155Fuse.sol line 188 : function safeBatchTransferFrom(address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data)
[G-2]- USE OF ++i COST LESS GAS THAN i++ IN FOR LOOPS :
File: contracts/dnssec-oracle/BytesUtils.sol line 313 : for(uint256 idx = off; idx < off + len; idx++) File: contracts/dnssec-oracle/DNSSECImpl.sol line 93 : for(uint i = 0; i < input.length; i++) File: contracts/ethregistrar/ETHRegistrarController.sol line 256 : for (uint256 i = 0; i < data.length; i++)
[G-3]- FUNCTIONS GUARANTEED TO REVERT WHEN CALLED BY NORMAL USERS CAN BE MARKED PAYABLE :
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 the owner because the compiler will not include checks for whether a payment was provided. The extra opcodes avoided are :
CALLVALUE(gas=2), DUP1(gas=3), ISZERO(gas=3), PUSH2(gas=3), JUMPI(gas=10), PUSH1(gas=3), DUP1(gas=3), REVERT(gas=0), JUMPDEST(gas=1), POP(gas=2).
Which costs an average of about 21 gas per call to the function, in addition to the extra deployment cost
File: contracts/dnssec-oracle/DNSSECImpl.sol line 58 : function setAlgorithm(uint8 id, Algorithm algo) public owner_only line 69 : function setDigest(uint8 id, Digest digest) public owner_only line 562 : function _calcPayout(DataTypes.Auction memory auction_, address to, uint256 artIn) internal view returns (uint256 liquidatorCut, uint256 auctioneerCut) File: contracts/wrapper/NameWrapper.sol line 105 : function setMetadataService(IMetadataService _newMetadataService) public onlyOwner line 128 : function setUpgradeContract(INameWrapperUpgrade _upgradeAddress) public onlyOwner line 251 : function registerAndWrapETH2LD(string calldata label, address wrappedOwner, uint256 duration, address resolver, uint32 fuses, uint64 expiry) external override onlyController returns (uint256 registrarExpiry) line 271 : function renew(uint256 tokenId, uint256 duration, uint64 expiry) external override onlyController returns (uint256 expires) line 335 : function unwrapETH2LD(bytes32 labelhash, address newRegistrant, address newController) public override onlyTokenOwner(_makeNode(ETH_NODE, labelhash))
[G-4] USE CUSTOM ERRORS RATHER THAN REQUIRE() STRINGS TO SAVE DEPLOYMENT GAS :
Custom errors from Solidity 0.8.4 are cheaper than revert strings (cheaper deployment cost and runtime cost when the revert condition is met) while providing the same amount of information.
There are many lines with this issue throughout the contracts.
File: contracts/ethregistrar/ETHRegistrarController.sol line 99 : require(resolver != address(0),"ETHRegistrarController: resolver is required when data is supplied"); line 137 : require( msg.value >= (price.base + price.premium),"ETHRegistrarController: Not enough ether provided"); line 196 : require(msg.value >= price.base,"ETHController: Not enough Ether provided for renewal"); line 233 : require(commitments[commitment] + minCommitmentAge <= block.timestamp,"ETHRegistrarController: Commitment is not valid"); line 238 : require(commitments[commitment] + maxCommitmentAge > block.timestamp,"ETHRegistrarController: Commitment has expired"); line 242 : require(available(name), "ETHRegistrarController: Name is unavailable"); line 259 : require(txNamehash == nodehash,"ETHRegistrarController: Namehash on record do not match the name being registered"); File: contracts/wrapper/BytesUtil.sol line 28 : require(offset == self.length - 1, "namehash: Junk at end of name"); line 42 : require(idx < self.length, "readLabel: Index out of bounds"); File: contracts/wrapper/ERC1155Fuse.sol line 61 : require(account != address(0),"ERC1155: balance query for the zero address"); line 85 : require(accounts.length == ids.length,"ERC1155: accounts and ids length mismatch"); line 107 : require(msg.sender != operator,"ERC1155: setting approval status for self"); line 176 : require(to != address(0), "ERC1155: transfer to the zero address");