ETH Price: $3,833.61 (-11.88%)

Transaction Decoder

Block:
10223261 at Jun-08-2020 05:31:07 AM +UTC
Transaction Fee:
0.000961704049487685 ETH $3.69
Gas Used:
40,071 Gas / 24.000001235 Gwei

Emitted Events:

166 ENS.NewOwner( node=B6168D4E6A16769316251939E18834097D5B028BD14398823528E541AC0CAA3A, label=BD14D5C29DDE4DACF18333AC56E983497AD1A948CEADE9DEC30154C54A45A8F5, owner=[Receiver] OwnedRegistrar )
167 ENS.NewResolver( node=F2B32640D65F40759B3179ADEF6D5531ADBA652D9EFEDAA196489BA42070F227, resolver=0x00000000...000000000 )
168 ENS.Transfer( node=F2B32640D65F40759B3179ADEF6D5531ADBA652D9EFEDAA196489BA42070F227, owner=0x00000000...000000000 )
169 OwnedRegistrar.Associate( node=B6168D4E6A16769316251939E18834097D5B028BD14398823528E541AC0CAA3A, subnode=BD14D5C29DDE4DACF18333AC56E983497AD1A948CEADE9DEC30154C54A45A8F5, owner=0x00000000...000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x31415926...173C1259b
(ENS: Eth Name Service)
0x48A25F46...0B57a83E5
0.361153272845392434 Eth
Nonce: 4499
0.360191568795904749 Eth
Nonce: 4500
0.000961704049487685
(Spark Pool)
0.222728442850986432 Eth0.223690146900474117 Eth0.000961704049487685
0xA86ba3b6...726DB69cf

Execution Trace

OwnedRegistrar.associateWithSig( node=B6168D4E6A16769316251939E18834097D5B028BD14398823528E541AC0CAA3A, label=BD14D5C29DDE4DACF18333AC56E983497AD1A948CEADE9DEC30154C54A45A8F5, owner=0x0000000000000000000000000000000000000000, nonce=1, registrarId=3775, r=E2429B5AAC584F82FC79D866550D338D4D1883C8F6308D7DEEB76A8B1093DA9A, s=48C7E624D1B3B052F1B5B83E448FF73D226DFEB8ACC6A8F5E5341B791E69DECC, v=27 )
  • Null: 0x000...001.f2a56f0b( )
  • ENS.setSubnodeOwner( node=B6168D4E6A16769316251939E18834097D5B028BD14398823528E541AC0CAA3A, label=BD14D5C29DDE4DACF18333AC56E983497AD1A948CEADE9DEC30154C54A45A8F5, owner=0xA86ba3b6d83139a49B649C05DBb69E0726DB69cf )
  • ENS.setResolver( node=F2B32640D65F40759B3179ADEF6D5531ADBA652D9EFEDAA196489BA42070F227, resolver=0x0000000000000000000000000000000000000000 )
  • ENS.setOwner( node=F2B32640D65F40759B3179ADEF6D5531ADBA652D9EFEDAA196489BA42070F227, owner=0x0000000000000000000000000000000000000000 )
    File 1 of 2: OwnedRegistrar
    pragma solidity ^0.4.24;
    
    // File: @ensdomains/ens/contracts/ENS.sol
    
    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);
    
    
        function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public;
        function setResolver(bytes32 node, address resolver) public;
        function setOwner(bytes32 node, address owner) public;
        function setTTL(bytes32 node, uint64 ttl) public;
        function owner(bytes32 node) public view returns (address);
        function resolver(bytes32 node) public view returns (address);
        function ttl(bytes32 node) public view returns (uint64);
    
    }
    
    // File: contracts/Roles.sol
    
    /**
     * @title Roles
     * @author Francisco Giordano (@frangio)
     * @dev Library for managing addresses assigned to a Role.
     * See RBAC.sol for example usage.
     */
    library Roles {
      struct Role {
        mapping (address => bool) bearer;
      }
    
      /**
       * @dev give an account access to this role
       */
      function add(Role storage _role, address _account)
        internal
      {
        _role.bearer[_account] = true;
      }
    
      /**
       * @dev remove an account's access to this role
       */
      function remove(Role storage _role, address _account)
        internal
      {
        _role.bearer[_account] = false;
      }
    
      /**
       * @dev check if an account has this role
       * // reverts
       */
      function check(Role storage _role, address _account)
        internal
        view
      {
        require(has(_role, _account));
      }
    
      /**
       * @dev check if an account has this role
       * @return bool
       */
      function has(Role storage _role, address _account)
        internal
        view
        returns (bool)
      {
        return _role.bearer[_account];
      }
    }
    
    // File: contracts/RBAC.sol
    
    /**
     * @title RBAC (Role-Based Access Control)
     * @author Matt Condon (@Shrugs)
     * @dev Stores and provides setters and getters for roles and addresses.
     * Supports unlimited numbers of roles and addresses.
     * See //contracts/mocks/RBACMock.sol for an example of usage.
     * This RBAC method uses strings to key roles. It may be beneficial
     * for you to write your own implementation of this interface using Enums or similar.
     */
    contract RBAC {
      using Roles for Roles.Role;
    
      mapping (string => Roles.Role) private roles;
    
      event RoleAdded(address indexed operator, string role);
      event RoleRemoved(address indexed operator, string role);
    
      /**
       * @dev reverts if addr does not have role
       * @param _operator address
       * @param _role the name of the role
       * // reverts
       */
      function checkRole(address _operator, string _role)
        public
        view
      {
        roles[_role].check(_operator);
      }
    
      /**
       * @dev determine if addr has role
       * @param _operator address
       * @param _role the name of the role
       * @return bool
       */
      function hasRole(address _operator, string _role)
        public
        view
        returns (bool)
      {
        return roles[_role].has(_operator);
      }
    
      /**
       * @dev add a role to an address
       * @param _operator address
       * @param _role the name of the role
       */
      function _addRole(address _operator, string _role)
        internal
      {
        roles[_role].add(_operator);
        emit RoleAdded(_operator, _role);
      }
    
      /**
       * @dev remove a role from an address
       * @param _operator address
       * @param _role the name of the role
       */
      function _removeRole(address _operator, string _role)
        internal
      {
        roles[_role].remove(_operator);
        emit RoleRemoved(_operator, _role);
      }
    
      /**
       * @dev modifier to scope access to a single role (uses msg.sender as addr)
       * @param _role the name of the role
       * // reverts
       */
      modifier onlyRole(string _role)
      {
        checkRole(msg.sender, _role);
        _;
      }
    
      /**
       * @dev modifier to scope access to a set of roles (uses msg.sender as addr)
       * @param _roles the names of the roles to scope access to
       * // reverts
       *
       * @TODO - when solidity supports dynamic arrays as arguments to modifiers, provide this
       *  see: https://github.com/ethereum/solidity/issues/2467
       */
      // modifier onlyRoles(string[] _roles) {
      //     bool hasAnyRole = false;
      //     for (uint8 i = 0; i < _roles.length; i++) {
      //         if (hasRole(msg.sender, _roles[i])) {
      //             hasAnyRole = true;
      //             break;
      //         }
      //     }
    
      //     require(hasAnyRole);
    
      //     _;
      // }
    }
    
    // File: contracts/OwnerResolver.sol
    
    contract OwnerResolver {
        ENS public ens;
    
        constructor(ENS _ens) public {
            ens = _ens;
        }
    
        function addr(bytes32 node) public view returns(address) {
            return ens.owner(node);
        }
    
        function supportsInterface(bytes4 interfaceID) public pure returns (bool) {
            return interfaceID == 0x01ffc9a7 || interfaceID == 0x3b3b57de;
        }
    }
    
    // File: contracts/OwnedRegistrar.sol
    
    pragma experimental ABIEncoderV2;
    
    
    
    
    /**
     * OwnedRegistrar implements an ENS registrar that accepts registrations by a
     * list of approved parties (IANA registrars). Registrations must be submitted
     * by a "transactor", and signed by a "registrar". Registrars can be added or
     * removed by an account with the "authoriser" role.
     *
     * An audit of this code is available here: https://hackmd.io/s/SJcPchO57
     */
    contract OwnedRegistrar is RBAC {
        ENS public ens;
        OwnerResolver public resolver;
        mapping(uint=>mapping(address=>bool)) public registrars; // Maps IANA IDs to authorised accounts
        mapping(bytes32=>uint) public nonces; // Maps namehashes to domain nonces
    
        event RegistrarAdded(uint id, address registrar);
        event RegistrarRemoved(uint id, address registrar);
        event Associate(bytes32 indexed node, bytes32 indexed subnode, address indexed owner);
        event Disassociate(bytes32 indexed node, bytes32 indexed subnode);
    
        constructor(ENS _ens) public {
            ens = _ens;
            resolver = new OwnerResolver(_ens);
            _addRole(msg.sender, "owner");
        }
    
        function addRole(address addr, string role) external onlyRole("owner") {
            _addRole(addr, role);
        }
    
        function removeRole(address addr, string role) external onlyRole("owner") {
            // Don't allow owners to remove themselves
            require(keccak256(abi.encode(role)) != keccak256(abi.encode("owner")) || msg.sender != addr);
            _removeRole(addr, role);
        }
    
        function setRegistrar(uint id, address registrar) public onlyRole("authoriser") {
            registrars[id][registrar] = true;
            emit RegistrarAdded(id, registrar);
        }
    
        function unsetRegistrar(uint id, address registrar) public onlyRole("authoriser") {
            registrars[id][registrar] = false;
            emit RegistrarRemoved(id, registrar);
        }
    
        function associateWithSig(bytes32 node, bytes32 label, address owner, uint nonce, uint registrarId, bytes32 r, bytes32 s, uint8 v) public onlyRole("transactor") {
            bytes32 subnode = keccak256(abi.encode(node, label));
            require(nonce == nonces[subnode]);
            nonces[subnode]++;
    
            bytes32 sighash = keccak256(abi.encode(subnode, owner, nonce));
            address registrar = ecrecover(sighash, v, r, s);
            require(registrars[registrarId][registrar]);
    
            ens.setSubnodeOwner(node, label, address(this));
            if(owner == 0) {
                ens.setResolver(subnode, 0);
            } else {
                ens.setResolver(subnode, resolver);
            }
            ens.setOwner(subnode, owner);
    
            emit Associate(node, label, owner);
        }
    
        function multicall(bytes[] calls) public {
            for(uint i = 0; i < calls.length; i++) {
                require(address(this).delegatecall(calls[i]));
            }
        }
    }

    File 2 of 2: ENS
    ;;; --------------------------------------------------------------------------- 
    ;;; @title The Ethereum Name Service registry. 
    ;;; @author Daniel Ellison <[email protected]> 
     
    (seq 
     
      ;; -------------------------------------------------------------------------- 
      ;; Constant definitions. 
     
      ;; Memory layout. 
      (def 'node-bytes  0x00) 
      (def 'label-bytes 0x20) 
      (def 'call-result 0x40) 
     
      ;; Struct: Record 
      (def 'resolver 0x00) ; address 
      (def 'owner    0x20) ; address 
      (def 'ttl      0x40) ; uint64 
     
      ;; Precomputed function IDs. 
      (def 'get-node-owner    0x02571be3) ; owner(bytes32) 
      (def 'get-node-resolver 0x0178b8bf) ; resolver(bytes32) 
      (def 'get-node-ttl      0x16a25cbd) ; ttl(bytes32) 
      (def 'set-node-owner    0x5b0fc9c3) ; setOwner(bytes32,address) 
      (def 'set-subnode-owner 0x06ab5923) ; setSubnodeOwner(bytes32,bytes32,address) 
      (def 'set-node-resolver 0x1896f70a) ; setResolver(bytes32,address) 
      (def 'set-node-ttl      0x14ab9038) ; setTTL(bytes32,uint64) 
     
      ;; Jumping here causes an EVM error. 
      (def 'invalid-location 0x02) 
     
      ;; -------------------------------------------------------------------------- 
      ;; @notice Shifts the leftmost 4 bytes of a 32-byte number right by 28 bytes. 
      ;; @param input A 32-byte number. 
     
      (def 'shift-right (input) 
        (div input (exp 2 224))) 
     
      ;; -------------------------------------------------------------------------- 
      ;; @notice Determines whether the supplied function ID matches a known 
      ;;         function hash and executes <code-body> if so. 
      ;; @dev The function ID is in the leftmost four bytes of the call data. 
      ;; @param function-hash The four-byte hash of a known function signature. 
      ;; @param code-body The code to run in the case of a match. 
     
      (def 'function (function-hash code-body) 
        (when (= (shift-right (calldataload 0x00)) function-hash) 
          code-body)) 
     
      ;; -------------------------------------------------------------------------- 
      ;; @notice Calculates record location for the node and label passed in. 
      ;; @param node The parent node. 
      ;; @param label The hash of the subnode label. 
     
      (def 'get-record (node label) 
        (seq 
          (mstore node-bytes node) 
          (mstore label-bytes label) 
          (sha3 node-bytes 64))) 
     
      ;; -------------------------------------------------------------------------- 
      ;; @notice Retrieves owner from node record. 
      ;; @param node Get owner of this node. 
     
      (def 'get-owner (node) 
        (sload (+ node owner))) 
     
      ;; -------------------------------------------------------------------------- 
      ;; @notice Stores new owner in node record. 
      ;; @param node Set owner of this node. 
      ;; @param new-owner New owner of this node. 
     
      (def 'set-owner (node new-owner) 
        (sstore (+ node owner) new-owner)) 
     
      ;; -------------------------------------------------------------------------- 
      ;; @notice Stores new subnode owner in node record. 
      ;; @param node Set owner of this node. 
      ;; @param label The hash of the label specifying the subnode. 
      ;; @param new-owner New owner of the subnode. 
     
      (def 'set-subowner (node label new-owner) 
        (sstore (+ (get-record node label) owner) new-owner)) 
     
      ;; -------------------------------------------------------------------------- 
      ;; @notice Retrieves resolver from node record. 
      ;; @param node Get resolver of this node. 
     
      (def 'get-resolver (node) 
        (sload node)) 
     
      ;; -------------------------------------------------------------------------- 
      ;; @notice Stores new resolver in node record. 
      ;; @param node Set resolver of this node. 
      ;; @param new-resolver New resolver for this node. 
     
      (def 'set-resolver (node new-resolver) 
        (sstore node new-resolver)) 
     
      ;; -------------------------------------------------------------------------- 
      ;; @notice Retrieves TTL From node record. 
      ;; @param node Get TTL of this node. 
     
      (def 'get-ttl (node) 
        (sload (+ node ttl))) 
     
      ;; -------------------------------------------------------------------------- 
      ;; @notice Stores new TTL in node record. 
      ;; @param node Set TTL of this node. 
      ;; @param new-resolver New TTL for this node. 
     
      (def 'set-ttl (node new-ttl) 
        (sstore (+ node ttl) new-ttl)) 
     
      ;; -------------------------------------------------------------------------- 
      ;; @notice Checks that the caller is the node owner. 
      ;; @param node Check owner of this node. 
     
      (def 'only-node-owner (node) 
        (when (!= (caller) (get-owner node)) 
          (jump invalid-location))) 
     
      ;; -------------------------------------------------------------------------- 
      ;; INIT 
     
      ;; Set the owner of the root node (0x00) to the deploying account. 
      (set-owner 0x00 (caller)) 
     
      ;; -------------------------------------------------------------------------- 
      ;; CODE 
     
      (returnlll 
        (seq 
     
          ;; ---------------------------------------------------------------------- 
          ;; @notice Returns the address of the resolver for the specified node. 
          ;; @dev Signature: resolver(bytes32) 
          ;; @param node Return this node's resolver. 
          ;; @return The associated resolver. 
     
          (def 'node (calldataload 0x04)) 
     
          (function get-node-resolver 
            (seq 
     
              ;; Get the node's resolver and save it. 
              (mstore call-result (get-resolver node)) 
     
              ;; Return result. 
              (return call-result 32))) 
     
          ;; ---------------------------------------------------------------------- 
          ;; @notice Returns the address that owns the specified node. 
          ;; @dev Signature: owner(bytes32) 
          ;; @param node Return this node's owner. 
          ;; @return The associated address. 
     
          (def 'node (calldataload 0x04)) 
     
          (function get-node-owner 
            (seq 
     
              ;; Get the node's owner and save it. 
              (mstore call-result (get-owner node)) 
     
              ;; Return result. 
              (return call-result 32))) 
     
          ;; ---------------------------------------------------------------------- 
          ;; @notice Returns the TTL of a node and any records associated with it. 
          ;; @dev Signature: ttl(bytes32) 
          ;; @param node Return this node's TTL. 
          ;; @return The node's TTL. 
     
          (def 'node (calldataload 0x04)) 
     
          (function get-node-ttl 
            (seq 
     
              ;; Get the node's TTL and save it. 
              (mstore call-result (get-ttl node)) 
     
              ;; Return result. 
              (return call-result 32))) 
     
          ;; ---------------------------------------------------------------------- 
          ;; @notice Transfers ownership of a node to a new address. May only be 
          ;;         called by the current owner of the node. 
          ;; @dev Signature: setOwner(bytes32,address) 
          ;; @param node The node to transfer ownership of. 
          ;; @param new-owner The address of the new owner. 
     
          (def 'node (calldataload 0x04)) 
          (def 'new-owner (calldataload 0x24)) 
     
          (function set-node-owner 
            (seq (only-node-owner node) 
     
              ;; Transfer ownership by storing passed-in address. 
              (set-owner node new-owner) 
     
              ;; Emit an event about the transfer. 
              ;; Transfer(bytes32 indexed node, address owner); 
              (mstore call-result new-owner) 
              (log2 call-result 32 
                  (sha3 0x00 (lit 0x00 "Transfer(bytes32,address)")) node) 
     
              ;; Nothing to return. 
              (stop))) 
     
          ;; ---------------------------------------------------------------------- 
          ;; @notice Transfers ownership of a subnode to a new address. May only be 
          ;;         called by the owner of the parent node. 
          ;; @dev Signature: setSubnodeOwner(bytes32,bytes32,address) 
          ;; @param node The parent node. 
          ;; @param label The hash of the label specifying the subnode. 
          ;; @param new-owner The address of the new owner. 
     
          (def 'node (calldataload 0x04)) 
          (def 'label (calldataload 0x24)) 
          (def 'new-owner (calldataload 0x44)) 
     
          (function set-subnode-owner 
            (seq (only-node-owner node) 
     
              ;; Transfer ownership by storing passed-in address. 
              (set-subowner node label new-owner) 
     
              ;; Emit an event about the transfer. 
              ;; NewOwner(bytes32 indexed node, bytes32 indexed label, address owner); 
              (mstore call-result new-owner) 
              (log3 call-result 32 
                  (sha3 0x00 (lit 0x00 "NewOwner(bytes32,bytes32,address)")) 
                  node label) 
     
              ;; Nothing to return. 
              (stop))) 
     
          ;; ---------------------------------------------------------------------- 
          ;; @notice Sets the resolver address for the specified node. 
          ;; @dev Signature: setResolver(bytes32,address) 
          ;; @param node The node to update. 
          ;; @param new-resolver The address of the resolver. 
     
          (def 'node (calldataload 0x04)) 
          (def 'new-resolver (calldataload 0x24)) 
     
          (function set-node-resolver 
            (seq (only-node-owner node) 
     
              ;; Transfer ownership by storing passed-in address. 
              (set-resolver node new-resolver) 
     
              ;; Emit an event about the change of resolver. 
              ;; NewResolver(bytes32 indexed node, address resolver); 
              (mstore call-result new-resolver) 
              (log2 call-result 32 
                  (sha3 0x00 (lit 0x00 "NewResolver(bytes32,address)")) node) 
     
              ;; Nothing to return. 
              (stop))) 
     
          ;; ---------------------------------------------------------------------- 
          ;; @notice Sets the TTL for the specified node. 
          ;; @dev Signature: setTTL(bytes32,uint64) 
          ;; @param node The node to update. 
          ;; @param ttl The TTL in seconds. 
     
          (def 'node (calldataload 0x04)) 
          (def 'new-ttl (calldataload 0x24)) 
     
          (function set-node-ttl 
            (seq (only-node-owner node) 
     
              ;; Set new TTL by storing passed-in time. 
              (set-ttl node new-ttl) 
     
              ;; Emit an event about the change of TTL. 
              ;; NewTTL(bytes32 indexed node, uint64 ttl); 
              (mstore call-result new-ttl) 
              (log2 call-result 32 
                  (sha3 0x00 (lit 0x00 "NewTTL(bytes32,uint64)")) node) 
     
              ;; Nothing to return. 
              (stop))) 
     
          ;; ---------------------------------------------------------------------- 
          ;; @notice Fallback: No functions matched the function ID provided. 
     
          (jump invalid-location))) 
     
    )