Transaction Hash:
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 | ||
---|---|---|---|---|---|
0x31415926...173C1259b | (ENS: Eth Name Service) | ||||
0x48A25F46...0B57a83E5 |
0.361153272845392434 Eth
Nonce: 4499
|
0.360191568795904749 Eth
Nonce: 4500
| 0.000961704049487685 | ||
0x5A0b54D5...D3E029c4c
Miner
| (Spark Pool) | 0.222728442850986432 Eth | 0.223690146900474117 Eth | 0.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 )
associateWithSig[OwnedRegistrar (ln:259)]
encode[OwnedRegistrar (ln:260)]
encode[OwnedRegistrar (ln:264)]
ecrecover[OwnedRegistrar (ln:265)]
setSubnodeOwner[OwnedRegistrar (ln:268)]
setResolver[OwnedRegistrar (ln:270)]
setResolver[OwnedRegistrar (ln:272)]
setOwner[OwnedRegistrar (ln:274)]
Associate[OwnedRegistrar (ln:276)]
File 1 of 2: OwnedRegistrar
File 2 of 2: ENS
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))) )