ETH Price: $2,682.98 (+0.89%)

Transaction Decoder

Block:
17277909 at May-17-2023 07:34:23 AM +UTC
Transaction Fee:
0.002094205385395474 ETH $5.62
Gas Used:
50,089 Gas / 41.809686466 Gwei

Account State Difference:

  Address   Before After State Difference Code
(bloXroute: Regulated Builder)
0.087609275666523665 Eth0.087659364666523665 Eth0.000050089
0x283Af0B2...A627EB7F5
(ENS: Old ETH Registrar Controller)
0xc5CB5390...86973d7dA
0.188491304255811422 Eth
Nonce: 36
0.186397098870415948 Eth
Nonce: 37
0.002094205385395474

Execution Trace

ETHBulkRegistrarV1.bulkCommit( )
  • ETHRegistrarController.commit( commitment=6617AA998F7CBC7530A64F9E4CFF6E7DEAD7A4A2BC13785343A8C11D1AC0E0A0 )
    File 1 of 2: ETHBulkRegistrarV1
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    import "./IETHBulkRegistrar.sol";
    import "./IETHRegistrarController.sol";
    contract ETHBulkRegistrarV1 is IETHBulkRegistrar {
        IETHRegistrarController public immutable registrarController;
        constructor(IETHRegistrarController _registrarController) {
            registrarController = _registrarController;
        }
        function bulkRentPrice(string[] calldata names, uint256 duration) external view override returns (uint256 total) {
            for (uint256 i = 0; i < names.length; i++) {
                uint price = registrarController.rentPrice(names[i], duration);
                total += price;
            }
            return total;
        }
        function bulkMakeCommitment(string[] calldata name, address owner, bytes32 secret) external view override returns (bytes32[] memory commitmentList) {
            commitmentList = new bytes32[](name.length);
            for (uint256 i = 0; i < name.length; i++) {
                commitmentList[i] = registrarController.makeCommitmentWithConfig(name[i], owner, secret, address(0), address(0));
            }
            return commitmentList;
        }
        function commitments(bytes32 commit) external view override returns (uint256) {
            return registrarController.commitments(commit);
        }
        function bulkCommit(bytes32[] calldata commitmentList) external override {
            for (uint256 i = 0; i < commitmentList.length; i++) {
                registrarController.commit(commitmentList[i]);
            }
        }
        function bulkRegister(string[] calldata names, address owner, uint duration, bytes32 secret) external payable override {
            uint256 cost = 0;
            for (uint256 i = 0; i < names.length; i++) {
                uint price = registrarController.rentPrice(names[i], duration);
                registrarController.register{value: (price)}(names[i], owner, duration, secret);
                cost = cost + price;
            }
            // Send any excess funds back
            if (msg.value > cost) {
                (bool sent, ) = msg.sender.call{value: msg.value - cost}("");
                require(sent, "Failed to send Ether");
            }
        }
        function registerWithConfig(string calldata name, address owner, uint duration, bytes32 secret, address resolver, address addr) external payable override {
            uint cost = registrarController.rentPrice(name, duration);
            registrarController.registerWithConfig{value: cost}(name, owner, duration, secret, resolver, addr);
            // Send any excess funds back
            if (msg.value > cost) {
                (bool sent, ) = msg.sender.call{value: msg.value - cost}("");
                require(sent, "Failed to send Ether");
            }
        }
        function makeCommitmentWithConfig(string calldata name, address owner, bytes32 secret, address resolver, address addr) external view override returns (bytes32 commitment) {
            commitment = registrarController.makeCommitmentWithConfig(name, owner, secret, resolver, addr);
            return commitment;
        }
    }
    pragma solidity >=0.8.4;
    interface IETHRegistrarController {
        function rentPrice(string memory, uint) external view returns (uint);
        function available(string memory) external returns (bool);
        function commit(bytes32) external;
        function register(string calldata, address, uint256, bytes32) external payable;
        function registerWithConfig(string memory, address, uint256, bytes32, address, address) external payable;
        function makeCommitmentWithConfig(string memory, address, bytes32, address, address) external pure returns (bytes32);
        function renew(string calldata, uint256) external payable;
        function commitments(bytes32) external view returns (uint256);
    }
    pragma solidity >=0.8.4;
    interface IETHBulkRegistrar {
        function bulkRentPrice(string[] calldata names, uint256 duration) external view returns (uint256 total);
        function bulkRegister(string[] calldata names, address owner, uint duration, bytes32 secret) external payable;
        function bulkCommit(bytes32[] calldata commitments) external;
        function bulkMakeCommitment(string[] calldata name, address owner, bytes32 secret) external view returns (bytes32[] memory commitments);
        function commitments(bytes32 commit) external view returns (uint256);
        function registerWithConfig(string calldata name, address owner, uint duration, bytes32 secret, address resolver, address addr) external payable;
        function makeCommitmentWithConfig(string calldata name, address owner, bytes32 secret, address resolver, address addr) external view returns (bytes32);
    }
    

    File 2 of 2: ETHRegistrarController
    // File: @ensdomains/ethregistrar/contracts/PriceOracle.sol
    
    pragma solidity >=0.4.24;
    
    interface PriceOracle {
        /**
         * @dev Returns the price to register or renew a name.
         * @param name The name being registered or renewed.
         * @param expires When the name presently expires (0 if this is a new registration).
         * @param duration How long the name is being registered or extended for, in seconds.
         * @return The price of this renewal or registration, in wei.
         */
        function price(string calldata name, uint expires, uint duration) external view returns(uint);
    }
    
    // File: @ensdomains/ens/contracts/ENS.sol
    
    pragma solidity >=0.4.24;
    
    interface ENS {
    
        // Logged when the owner of a node assigns a new owner to a subnode.
        event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
    
        // Logged when the owner of a node transfers ownership to a new account.
        event Transfer(bytes32 indexed node, address owner);
    
        // Logged when the resolver for a node changes.
        event NewResolver(bytes32 indexed node, address resolver);
    
        // Logged when the TTL of a node changes
        event NewTTL(bytes32 indexed node, uint64 ttl);
    
        // Logged when an operator is added or removed.
        event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
    
        function setRecord(bytes32 node, address owner, address resolver, uint64 ttl) external;
        function setSubnodeRecord(bytes32 node, bytes32 label, address owner, address resolver, uint64 ttl) external;
        function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external returns(bytes32);
        function setResolver(bytes32 node, address resolver) external;
        function setOwner(bytes32 node, address owner) external;
        function setTTL(bytes32 node, uint64 ttl) external;
        function setApprovalForAll(address operator, bool approved) external;
        function owner(bytes32 node) external view returns (address);
        function resolver(bytes32 node) external view returns (address);
        function ttl(bytes32 node) external view returns (uint64);
        function recordExists(bytes32 node) external view returns (bool);
        function isApprovedForAll(address owner, address operator) external view returns (bool);
    }
    
    // File: openzeppelin-solidity/contracts/introspection/IERC165.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @title IERC165
     * @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
     */
    interface IERC165 {
        /**
         * @notice Query if a contract implements an interface
         * @param interfaceId The interface identifier, as specified in ERC-165
         * @dev Interface identification is specified in ERC-165. This function
         * uses less than 30,000 gas.
         */
        function supportsInterface(bytes4 interfaceId) external view returns (bool);
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/IERC721.sol
    
    pragma solidity ^0.5.0;
    
    
    /**
     * @title ERC721 Non-Fungible Token Standard basic interface
     * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
     */
    contract IERC721 is IERC165 {
        event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
        event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
        event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
    
        function balanceOf(address owner) public view returns (uint256 balance);
        function ownerOf(uint256 tokenId) public view returns (address owner);
    
        function approve(address to, uint256 tokenId) public;
        function getApproved(uint256 tokenId) public view returns (address operator);
    
        function setApprovalForAll(address operator, bool _approved) public;
        function isApprovedForAll(address owner, address operator) public view returns (bool);
    
        function transferFrom(address from, address to, uint256 tokenId) public;
        function safeTransferFrom(address from, address to, uint256 tokenId) public;
    
        function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public;
    }
    
    // File: openzeppelin-solidity/contracts/ownership/Ownable.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @title Ownable
     * @dev The Ownable contract has an owner address, and provides basic authorization control
     * functions, this simplifies the implementation of "user permissions".
     */
    contract Ownable {
        address private _owner;
    
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    
        /**
         * @dev The Ownable constructor sets the original `owner` of the contract to the sender
         * account.
         */
        constructor () internal {
            _owner = msg.sender;
            emit OwnershipTransferred(address(0), _owner);
        }
    
        /**
         * @return the address of the owner.
         */
        function owner() public view returns (address) {
            return _owner;
        }
    
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            require(isOwner());
            _;
        }
    
        /**
         * @return true if `msg.sender` is the owner of the contract.
         */
        function isOwner() public view returns (bool) {
            return msg.sender == _owner;
        }
    
        /**
         * @dev Allows the current owner to relinquish control of the contract.
         * @notice Renouncing to ownership will leave the contract without an owner.
         * It will not be possible to call the functions with the `onlyOwner`
         * modifier anymore.
         */
        function renounceOwnership() public onlyOwner {
            emit OwnershipTransferred(_owner, address(0));
            _owner = address(0);
        }
    
        /**
         * @dev Allows the current owner to transfer control of the contract to a newOwner.
         * @param newOwner The address to transfer ownership to.
         */
        function transferOwnership(address newOwner) public onlyOwner {
            _transferOwnership(newOwner);
        }
    
        /**
         * @dev Transfers control of the contract to a newOwner.
         * @param newOwner The address to transfer ownership to.
         */
        function _transferOwnership(address newOwner) internal {
            require(newOwner != address(0));
            emit OwnershipTransferred(_owner, newOwner);
            _owner = newOwner;
        }
    }
    
    // File: @ensdomains/ethregistrar/contracts/BaseRegistrar.sol
    
    pragma solidity >=0.4.24;
    
    
    
    
    contract BaseRegistrar is IERC721, Ownable {
        uint constant public GRACE_PERIOD = 90 days;
    
        event ControllerAdded(address indexed controller);
        event ControllerRemoved(address indexed controller);
        event NameMigrated(uint256 indexed id, address indexed owner, uint expires);
        event NameRegistered(uint256 indexed id, address indexed owner, uint expires);
        event NameRenewed(uint256 indexed id, uint expires);
    
        // The ENS registry
        ENS public ens;
    
        // The namehash of the TLD this registrar owns (eg, .eth)
        bytes32 public baseNode;
    
        // A map of addresses that are authorised to register and renew names.
        mapping(address=>bool) public controllers;
    
        // Authorises a controller, who can register and renew domains.
        function addController(address controller) external;
    
        // Revoke controller permission for an address.
        function removeController(address controller) external;
    
        // Set the resolver for the TLD this registrar manages.
        function setResolver(address resolver) external;
    
        // Returns the expiration timestamp of the specified label hash.
        function nameExpires(uint256 id) external view returns(uint);
    
        // Returns true iff the specified name is available for registration.
        function available(uint256 id) public view returns(bool);
    
        /**
         * @dev Register a name.
         */
        function register(uint256 id, address owner, uint duration) external returns(uint);
    
        function renew(uint256 id, uint duration) external returns(uint);
    
        /**
         * @dev Reclaim ownership of a name in ENS, if you own it in the registrar.
         */
        function reclaim(uint256 id, address owner) external;
    }
    
    // File: @ensdomains/ethregistrar/contracts/StringUtils.sol
    
    pragma solidity >=0.4.24;
    
    library StringUtils {
        /**
         * @dev Returns the length of a given string
         *
         * @param s The string to measure the length of
         * @return The length of the input string
         */
        function strlen(string memory s) internal pure returns (uint) {
            uint len;
            uint i = 0;
            uint bytelength = bytes(s).length;
            for(len = 0; i < bytelength; len++) {
                byte b = bytes(s)[i];
                if(b < 0x80) {
                    i += 1;
                } else if (b < 0xE0) {
                    i += 2;
                } else if (b < 0xF0) {
                    i += 3;
                } else if (b < 0xF8) {
                    i += 4;
                } else if (b < 0xFC) {
                    i += 5;
                } else {
                    i += 6;
                }
            }
            return len;
        }
    }
    
    // File: @ensdomains/resolver/contracts/Resolver.sol
    
    pragma solidity >=0.4.25;
    
    /**
     * A generic resolver interface which includes all the functions including the ones deprecated
     */
    interface Resolver{
        event AddrChanged(bytes32 indexed node, address a);
        event AddressChanged(bytes32 indexed node, uint coinType, bytes newAddress);
        event NameChanged(bytes32 indexed node, string name);
        event ABIChanged(bytes32 indexed node, uint256 indexed contentType);
        event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y);
        event TextChanged(bytes32 indexed node, string indexed indexedKey, string key);
        event ContenthashChanged(bytes32 indexed node, bytes hash);
        /* Deprecated events */
        event ContentChanged(bytes32 indexed node, bytes32 hash);
    
        function ABI(bytes32 node, uint256 contentTypes) external view returns (uint256, bytes memory);
        function addr(bytes32 node) external view returns (address);
        function addr(bytes32 node, uint coinType) external view returns(bytes memory);
        function contenthash(bytes32 node) external view returns (bytes memory);
        function dnsrr(bytes32 node) external view returns (bytes memory);
        function name(bytes32 node) external view returns (string memory);
        function pubkey(bytes32 node) external view returns (bytes32 x, bytes32 y);
        function text(bytes32 node, string calldata key) external view returns (string memory);
        function interfaceImplementer(bytes32 node, bytes4 interfaceID) external view returns (address);
    
        function setABI(bytes32 node, uint256 contentType, bytes calldata data) external;
        function setAddr(bytes32 node, address addr) external;
        function setAddr(bytes32 node, uint coinType, bytes calldata a) external;
        function setContenthash(bytes32 node, bytes calldata hash) external;
        function setDnsrr(bytes32 node, bytes calldata data) external;
        function setName(bytes32 node, string calldata _name) external;
        function setPubkey(bytes32 node, bytes32 x, bytes32 y) external;
        function setText(bytes32 node, string calldata key, string calldata value) external;
        function setInterface(bytes32 node, bytes4 interfaceID, address implementer) external;
    
        function supportsInterface(bytes4 interfaceID) external pure returns (bool);
    
        /* Deprecated functions */
        function content(bytes32 node) external view returns (bytes32);
        function multihash(bytes32 node) external view returns (bytes memory);
        function setContent(bytes32 node, bytes32 hash) external;
        function setMultihash(bytes32 node, bytes calldata hash) external;
    }
    
    // File: @ensdomains/ethregistrar/contracts/ETHRegistrarController.sol
    
    pragma solidity ^0.5.0;
    
    
    
    
    
    
    /**
     * @dev A registrar controller for registering and renewing names at fixed cost.
     */
    contract ETHRegistrarController is Ownable {
        using StringUtils for *;
    
        uint constant public MIN_REGISTRATION_DURATION = 28 days;
    
        bytes4 constant private INTERFACE_META_ID = bytes4(keccak256("supportsInterface(bytes4)"));
        bytes4 constant private COMMITMENT_CONTROLLER_ID = bytes4(
            keccak256("rentPrice(string,uint256)") ^
            keccak256("available(string)") ^
            keccak256("makeCommitment(string,address,bytes32)") ^
            keccak256("commit(bytes32)") ^
            keccak256("register(string,address,uint256,bytes32)") ^
            keccak256("renew(string,uint256)")
        );
    
        bytes4 constant private COMMITMENT_WITH_CONFIG_CONTROLLER_ID = bytes4(
            keccak256("registerWithConfig(string,address,uint256,bytes32,address,address)") ^
            keccak256("makeCommitmentWithConfig(string,address,bytes32,address,address)")
        );
    
        BaseRegistrar base;
        PriceOracle prices;
        uint public minCommitmentAge;
        uint public maxCommitmentAge;
    
        mapping(bytes32=>uint) public commitments;
    
        event NameRegistered(string name, bytes32 indexed label, address indexed owner, uint cost, uint expires);
        event NameRenewed(string name, bytes32 indexed label, uint cost, uint expires);
        event NewPriceOracle(address indexed oracle);
    
        constructor(BaseRegistrar _base, PriceOracle _prices, uint _minCommitmentAge, uint _maxCommitmentAge) public {
            require(_maxCommitmentAge > _minCommitmentAge);
    
            base = _base;
            prices = _prices;
            minCommitmentAge = _minCommitmentAge;
            maxCommitmentAge = _maxCommitmentAge;
        }
    
        function rentPrice(string memory name, uint duration) view public returns(uint) {
            bytes32 hash = keccak256(bytes(name));
            return prices.price(name, base.nameExpires(uint256(hash)), duration);
        }
    
        function valid(string memory name) public pure returns(bool) {
            return name.strlen() >= 3;
        }
    
        function available(string memory name) public view returns(bool) {
            bytes32 label = keccak256(bytes(name));
            return valid(name) && base.available(uint256(label));
        }
    
        function makeCommitment(string memory name, address owner, bytes32 secret) pure public returns(bytes32) {
            return makeCommitmentWithConfig(name, owner, secret, address(0), address(0));
        }
    
        function makeCommitmentWithConfig(string memory name, address owner, bytes32 secret, address resolver, address addr) pure public returns(bytes32) {
            bytes32 label = keccak256(bytes(name));
            if (resolver == address(0) && addr == address(0)) {
                return keccak256(abi.encodePacked(label, owner, secret));
            }
            require(resolver != address(0));
            return keccak256(abi.encodePacked(label, owner, resolver, addr, secret));
        }
    
        function commit(bytes32 commitment) public {
            require(commitments[commitment] + maxCommitmentAge < now);
            commitments[commitment] = now;
        }
    
        function register(string calldata name, address owner, uint duration, bytes32 secret) external payable {
          registerWithConfig(name, owner, duration, secret, address(0), address(0));
        }
    
        function registerWithConfig(string memory name, address owner, uint duration, bytes32 secret, address resolver, address addr) public payable {
            bytes32 commitment = makeCommitmentWithConfig(name, owner, secret, resolver, addr);
            uint cost = _consumeCommitment(name, duration, commitment);
    
            bytes32 label = keccak256(bytes(name));
            uint256 tokenId = uint256(label);
    
            uint expires;
            if(resolver != address(0)) {
                // Set this contract as the (temporary) owner, giving it
                // permission to set up the resolver.
                expires = base.register(tokenId, address(this), duration);
    
                // The nodehash of this label
                bytes32 nodehash = keccak256(abi.encodePacked(base.baseNode(), label));
    
                // Set the resolver
                base.ens().setResolver(nodehash, resolver);
    
                // Configure the resolver
                if (addr != address(0)) {
                    Resolver(resolver).setAddr(nodehash, addr);
                }
    
                // Now transfer full ownership to the expeceted owner
                base.reclaim(tokenId, owner);
                base.transferFrom(address(this), owner, tokenId);
            } else {
                require(addr == address(0));
                expires = base.register(tokenId, owner, duration);
            }
    
            emit NameRegistered(name, label, owner, cost, expires);
    
            // Refund any extra payment
            if(msg.value > cost) {
                msg.sender.transfer(msg.value - cost);
            }
        }
    
        function renew(string calldata name, uint duration) external payable {
            uint cost = rentPrice(name, duration);
            require(msg.value >= cost);
    
            bytes32 label = keccak256(bytes(name));
            uint expires = base.renew(uint256(label), duration);
    
            if(msg.value > cost) {
                msg.sender.transfer(msg.value - cost);
            }
    
            emit NameRenewed(name, label, cost, expires);
        }
    
        function setPriceOracle(PriceOracle _prices) public onlyOwner {
            prices = _prices;
            emit NewPriceOracle(address(prices));
        }
    
        function setCommitmentAges(uint _minCommitmentAge, uint _maxCommitmentAge) public onlyOwner {
            minCommitmentAge = _minCommitmentAge;
            maxCommitmentAge = _maxCommitmentAge;
        }
    
        function withdraw() public onlyOwner {
            msg.sender.transfer(address(this).balance);
        }
    
        function supportsInterface(bytes4 interfaceID) external pure returns (bool) {
            return interfaceID == INTERFACE_META_ID ||
                   interfaceID == COMMITMENT_CONTROLLER_ID ||
                   interfaceID == COMMITMENT_WITH_CONFIG_CONTROLLER_ID;
        }
    
        function _consumeCommitment(string memory name, uint duration, bytes32 commitment) internal returns (uint256) {
            // Require a valid commitment
            require(commitments[commitment] + minCommitmentAge <= now);
    
            // If the commitment is too old, or the name is registered, stop
            require(commitments[commitment] + maxCommitmentAge > now);
            require(available(name));
    
            delete(commitments[commitment]);
    
            uint cost = rentPrice(name, duration);
            require(duration >= MIN_REGISTRATION_DURATION);
            require(msg.value >= cost);
    
            return cost;
        }
    }