ENS contest - delfin454000's results

Decentralised naming for wallets, websites, & more.

General Information

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

ENS

Findings Distribution

Researcher Performance

Rank: 60/100

Findings: 2

Award: $118.84

🌟 Selected for report: 0

🚀 Solo Findings: 0

Typos

DNSSECImpl.sol: L105

     *        data, followed by a series of canonicalised RR records that the signature

Change canonicalised to canonicalized


The same typo (Authorises/ Authorizes, Authorised/authorised, or Unauthorized/unauthorised) occurs in all 20 lines referenced below.

Example: ReverseRegistrar.sol: L40:

    modifier authorised(address addr) {

IBaseRegistrar.sol: L20

ReverseRegistrar.sol: L40

ReverseRegistrar.sol: L46

ReverseRegistrar.sol: L80

ReverseRegistrar.sol: L126

NameWrapper.sol: L15

NameWrapper.sol: L152

NameWrapper.sol: L202

NameWrapper.sol: L224

NameWrapper.sol: L241

NameWrapper.sol: L266

NameWrapper.sol: L289

NameWrapper.sol: L315

NameWrapper.sol: L329

NameWrapper.sol: L350

NameWrapper.sol: L381

NameWrapper.sol: L421

NameWrapper.sol: L469

NameWrapper.sol: L475

NameWrapper.sol: L804

Change authorised to authorized. Similarly for other forms of the word. This assumes that a decision has been made to use standard American English throughout ENS.


ETHRegistrarController.sol: L257

            // check first few bytes are namehash

Change check first to check that first


ReverseRegistrar.sol: L156

     * @dev An optimised function to compute the sha3 of the lower-case

Change optimised to optimized


ERC1155Fuse.sol: L10

/* This contract is a variation on ERC1155 with the additions of _setData, getData and _canTransfer and ownerOf. _setData and getData allows the use of the other 96 bits next to the address of the owner for extra data. We use this to store 'fuses' that control permissions that can be burnt. 32 bits are used for the fuses themselves and 64 bits are used for the expiry of the name. When a name has expired, its fuses will be be set back to 0 */

Remove duplicate word be


NameWrapper.sol: L534

     * @param ttl ttl in the regsitry

Change regsitry to registry



Long single line comment

For the sake of readability, comments over 79 characters, such as the one below, should wrap using multi-line comment syntax.


ERC1155Fuse.sol: L10

/* This contract is a variation on ERC1155 with the additions of _setData, getData and _canTransfer and ownerOf. _setData and getData allows the use of the other 96 bits next to the address of the owner for extra data. We use this to store 'fuses' that control permissions that can be burnt. 32 bits are used for the fuses themselves and 64 bits are used for the expiry of the name. When a name has expired, its fuses will be be set back to 0 */


Comments concerning unfinished work or open items

Comments such as the one below that contain TODOs or similar language should be addressed and modified or removed

DNSSECImpl.sol: L238

        // TODO: Check key isn't expired, unless updating key itself


Named return variable not used when a function returns

The existence of a named return variable that is never used (here, newFuses) is potentially perplexing


INameWrapper.sol: L80-82

    function setFuses(bytes32 node, uint32 fuses)
        external
        returns (uint32 newFuses);


Missing @param statements


DNSSECImpl.sol: L179-183

     * @param name The name of the RRSIG record, in DNS label-sequence format.
     * @param data The original data to verify.
     * @param proof A DS or DNSKEY record that's already verified by the oracle.
     */
    function verifySignature(bytes memory name, RRUtils.SignedSet memory rrset, RRSetWithSignature memory data, bytes memory proof) internal view {

@param statement is missing for rrset


DNSSECImpl.sol: L228-238

     * @param dnskey The dns key record to verify the signature with.
     * @param rrset The signed RRSET being verified.
     * @param data The original data `rrset` was decoded from.
     * @return True iff the key verifies the signature.
     */
    function verifySignatureWithKey(RRUtils.DNSKEY memory dnskey, bytes memory keyrdata, RRUtils.SignedSet memory rrset, RRSetWithSignature memory data)
        internal
        view
        returns (bool)
    {
        // TODO: Check key isn't expired, unless updating key itself

@param statement is missing for keyrdata. I've included the "TODO" comment here (which I mentioned earlier) which refers to the key


ReverseRegistrar.sol: L72-79

     * @param addr The reverse record to set
     * @param owner The address to set as the owner of the reverse record in ENS.
     * @return The ENS node hash of the reverse record.
     */
    function claimForAddr(
        address addr,
        address owner,
        address resolver

@param missing for resolver. The resolver @param is also missing in the two examples below:

ReverseRegistrar.sol: L127-136

     * @param addr The reverse record to set
     * @param owner The owner of the reverse node
     * @param name The name to set for this address.
     * @return The ENS node hash of the reverse record.
     */
    function setNameForAddr(
        address addr,
        address owner,
        address resolver,
        string memory name

NameWrapper.sol: L397-404

     * @param label Label as a string of the .eth name to upgrade
     * @param wrappedOwner The owner of the wrapped name
     */

    function upgradeETH2LD(
        string calldata label,
        address wrappedOwner,
        address resolver

NameWrapper.sol: L267-274

     * @param tokenId The hash of the label to register (eg, `keccak256('foo')`, for 'foo.eth').
     * @param duration The number of seconds to renew the name for.
     * @return expires The expiry date of the name on the .eth registrar, in seconds since the Unix epoch.
     */
    function renew(
        uint256 tokenId,
        uint256 duration,
        uint64 expiry

@param missing for expiry



Missing require revert string

A require message should be included to enable users to understand reason for failure Recommendation: Add a brief (<= 32 char) explanatory message to each of the lines below


BytesUtils.sol: L12

        require(offset + len <= self.length);

BytesUtils.sol: L146

        require(idx + 2 <= self.length);

BytesUtils.sol: L159

        require(idx + 4 <= self.length);

BytesUtils.sol: L172

        require(idx + 32 <= self.length);

BytesUtils.sol: L185

        require(idx + 20 <= self.length);

BytesUtils.sol: L199

        require(len <= 32);

BytesUtils.sol: L200

        require(idx + len <= self.length);

BytesUtils.sol: L235

        require(offset + len <= self.length);

BytesUtils.sol: L262

        require(len <= 52);

BytesUtils.sol: L268

            require(char >= 0x30 && char <= 0x7A);

BytesUtils.sol: L270

            require(decoded <= 0x20);

Owned.sol: L10

        require(msg.sender == owner);

ETHRegistrarController.sol: L57

        require(_maxCommitmentAge > _minCommitmentAge);

ETHRegistrarController.sol: L121

        require(commitments[commitment] + maxCommitmentAge < block.timestamp);

ETHRegistrarController.sol: L246

        require(duration >= MIN_REGISTRATION_DURATION);

BytesUtil.sol: L13

        require(offset + len <= self.length);


#0 - dmvt

2022-09-08T10:42:19Z

Marking British English as a typo knowingly is a massive waste of everyone's time.

Require revert string is too long

The 22 require revert strings referenced below should be shortened to 32 characters or fewer to save gas or else consider using custom error codes (which could save even more gas)

Example:

ETHRegistrarController.sol: L99-102

            require(
                resolver != address(0),
                "ETHRegistrarController: resolver is required when data is supplied"
            );

Additional long require strings:

ETHRegistrarController.sol: L137-140

ETHRegistrarController.sol: L196-199

ETHRegistrarController.sol: L232-235

ETHRegistrarController.sol: L238-241

ETHRegistrarController.sol: L242

ETHRegistrarController.sol: L259-262

ReverseRegistrar.sol: L41-47

ReverseRegistrar.sol: L52-55

ERC1155Fuse.sol: L60-63

ERC1155Fuse.sol: L85-88

ERC1155Fuse.sol: L107-110

ERC1155Fuse.sol: L176

ERC1155Fuse.sol: L177-180

ERC1155Fuse.sol: L195-198

ERC1155Fuse.sol: L199

ERC1155Fuse.sol: L200-203

ERC1155Fuse.sol: L215-218

ERC1155Fuse.sol: L249

ERC1155Fuse.sol: L250-253

ERC1155Fuse.sol: L290-293

Controllable.sol.sol: L17



Revert error string is too long

The revert strings below should be shortened to 32 characters or fewer to save gas, or else consider using custom errors


ERC1155Fuse.sol: L322-327

                    revert("ERC1155: ERC1155Receiver rejected tokens");
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert("ERC1155: transfer to non ERC1155Receiver implementer");

ERC1155Fuse.sol: L354-359

                    revert("ERC1155: ERC1155Receiver rejected tokens");
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert("ERC1155: transfer to non ERC1155Receiver implementer");


Use of '&&' within a require function

Splitting such functions into separate require() statements (instead of using &&) saves gas


BytesUtils.sol: L268

            require(char >= 0x30 && char <= 0x7A);

Recommendation:

            require(char >= 0x30, "Error message");
            require(char <= 0x7A, "Error message");

The same require function with embedded && occurs in both sets of lines referenced below:

ERC1155Fuse.sol: L215-218

ERC1155Fuse.sol: L290-293

            require(
                amount == 1 && oldOwner == from,
                "ERC1155: insufficient balance for transfer"
            );

Recommendation:

            require(amount == 1, "Error message");
            require(oldOwner == from, "Error message");


Array length should not be looked up in every iteration of a for loop

Since calculating the array length costs gas, it's best to read the length of the array from memory before executing the loop


ERC1155Fuse.sol: L92-94

        for (uint256 i = 0; i < accounts.length; ++i) {
            batchBalances[i] = balanceOf(accounts[i], ids[i]);
        }

Suggestion:

        uint256 totalAccountsLength = accounts.length; 
        for (uint256 i = 0; i < totalAccountsLength; ++i) {
            batchBalances[i] = balanceOf(accounts[i], ids[i]);
        }

Similarly for the following for loops:

ERC1155Fuse.sol: L205-213

ETHRegistrarController.sol: L256-267



Use ++i instead of i++ to increase count in a for loop

Since use of i++ costs more gas, it is better to use ++i in the for loop below:

ETHRegistrarController.sol: L256-267



Avoid use of default "checked" behavior in a for loop

Underflow/overflow checks are made every time ++i (or i++) is called. Such checks are unnecessary since i is already limited. Therefore, use unchecked{++i}/unchecked{i++} instead


ERC1155Fuse.sol: L92-94

        for (uint256 i = 0; i < accounts.length; ++i) {
            batchBalances[i] = balanceOf(accounts[i], ids[i]);
        }

Suggestion:

        uint256 totalAccountsLength = accounts.length; 
        for (uint256 i = 0; i < totalAccountsLength;) {
            batchBalances[i] = balanceOf(accounts[i], ids[i]);

            unchecked{
              ++i;
          }
        }

Similarly for the following for loops:

ERC1155Fuse.sol: L205-213

ETHRegistrarController.sol: L256-267



AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter