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: 31/100
Findings: 2
Award: $205.89
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0x29A
Also found by: Amithuddar, CRYP70, RedOneN, Sm4rty, benbaessler, berndartmueller, cccz, rbserver
https://github.com/code-423n4/2022-07-ens/blob/main/contracts/wrapper/NameWrapper.sol#L231 https://github.com/code-423n4/2022-07-ens/blob/main/contracts/wrapper/NameWrapper.sol#L341-L345
Use safeTransferFrom
instead of transferFrom
for ERC721 instances so tokens don't get lost in the void by being locked up if they get sent to contracts who don't know how to handle them. In addition to this, the transaction may also result in a silent failure.
This was found in contracts/wrapper/NameWrapper.sol:341
(where tokens are transferred from the address of NameWrapper
to the newRegistrant
) and in contracts/wrapper/NameWrapper.sol:231
where the registrant tokens are being transferred from the user to the NameWrapper
I recommend the use of safeTransferFrom
in the referenced lines from the source code as the OpenZeppelin documentation highly encourages the use of safeTransferFrom
as opposed to transferFrom
where possible as this safely transfers the tokenId by first checking the contract recipients are aware of the ERC721 protocol.
Source: https://docs.openzeppelin.com/contracts/4.x/api/token/erc721#IERC721-transferFrom-address-address-uint256-
In addition to this, the source code for openzeppelin-contracts/blob/master/contracts/token/ERC721/IERC721.sol:71
requires the implementation of onERC721Received()
or the inheritance of IERC721Receiver
in NameWrapper.sol
when tokens are transferred from the user to the NameWrapper
contract.
#0 - jefflau
2022-07-27T09:03:24Z
#1 - dmvt
2022-08-03T14:25:28Z
Note that line 231 is not a valid instance because the transfer is to the contract.
🌟 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.8564 USDC - $39.86
Hello! CRYP70 here, thank you so much for allowing me to participate in the ENS contest. I have found a couple of valid gas optimisations for this platform which may help keep platform transaction prices down - please see my findings below. :)
++i
saves more gass than i++
++i
generally costs less gas than i++
or i = i + 1
(about 5 units per increment) because i++
must increment a value and then "return" the old value which means the program may need to hold two numbers in memory. When ++i
is used, it will only ever use one number in memory.
See the example below for an simplified illustration:
pragma solidity ^0.8.13; contract MyFavouriteCounter { uint public count; function incrementPrefixCount() public returns (uint) { count = 1; return (++count); // returns 2 } function incrementPostfixCount() public returns (uint) { count = 1; return (count++); // returns 1 } }
I managed to identify this in the following locations:
<array>.length
can be cached as opposed to looking up the length with each interation<array>.length
can be cached in a variable so the program doesn't need to spend additional gas to determine the length of the target array. I believe memory arrays use 3 gas units through the mload
opcode and calldata arrays will use 3 gas units via the calldataload
opcode. See the very simple example below with resulting gas units spent (note that this is excluding gas optimisation of the index incrementer and includes gas price spent after reading from storage for both function calls).
pragma solidity 0.8.13; contract MyFavouriteLooper { string[] testarr = ["a", "b"]; function stored() public { // gas units spent: 23713 uint256 len = testarr.length; for(uint256 i = 0; i < len; i++){ } } function notstored() public { // gas units spent: 27479 for(uint256 i = 0; i < testarr.length; i++){ } } }
I managed to identify this in the following solidity files:
Many thanks!