ETH Price: $1,974.95 (+0.71%)

Transaction Decoder

Block:
24509398 at Feb-22-2026 02:23:59 AM +UTC
Transaction Fee:
0.00000276703577136 ETH $0.005465
Gas Used:
85,680 Gas / 0.032295002 Gwei

Emitted Events:

992 BaseRegistrarImplementation.NameRenewed( id=2186714972188721648088781264963208606216198231231569496041371939304632504430, expires=1777665071 )
993 0x59e16fccd424cc24e280be16e11bcd56fb0ce547.0xfa956c3bce4cb4b01166868ecaf0620566bc7e33fc70b0b9c6aef61e37e50b94( 0xfa956c3bce4cb4b01166868ecaf0620566bc7e33fc70b0b9c6aef61e37e50b94, 0x04d5a3063f15d3a4072d69ef5d8cc1cc53517300aed6b2f0c589bab4c8a4506e, 0000000000000000000000000000000000000000000000000000000000000080, 0000000000000000000000000000000000000000000000000003b7f405c2f62c, 0000000000000000000000000000000000000000000000000000000069f5042f, 0000000000000000000000000000000000000000000000000000000000000000, 000000000000000000000000000000000000000000000000000000000000000a, 6d6f6e69746f72626f7400000000000000000000000000000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
(Titan Builder)
14.647843973065871796 Eth14.647843979363351796 Eth0.00000000629748
0x57f1887a...Af147eA85
0x59E16fcC...6fb0CE547
(ENS: ETH Registrar Controller 2)
72.775210290095754089 Eth72.776256973722452373 Eth0.001046683626698284
0xED976cA9...e503a09C7
0.029722249347674675 Eth
Nonce: 4782
0.028672798685205031 Eth
Nonce: 4783
0.001049450662469644

Execution Trace

ETH 0.001067617299232249 ENS: ETH Registrar Controller 2.18026ad1( )
  • BaseRegistrarImplementation.nameExpires( id=2186714972188721648088781264963208606216198231231569496041371939304632504430 ) => ( 1764622271 )
  • ExponentialPremiumPriceOracle.price( name=monitorbot, expires=1764622271, duration=13042800 ) => ( [{name:base, type:uint256, order:1, indexed:false, value:1046683626698284, valueString:1046683626698284}, {name:premium, type:uint256, order:2, indexed:false, value:0, valueString:0}] )
    • EACAggregatorProxy.STATICCALL( )
      • 0x7d4e742018fb52e48b08be73d041c18b21de6fb5.STATICCALL( )
      • EACAggregatorProxy.STATICCALL( )
        • 0x7d4e742018fb52e48b08be73d041c18b21de6fb5.STATICCALL( )
        • BaseRegistrarImplementation.renew( id=2186714972188721648088781264963208606216198231231569496041371939304632504430, duration=13042800 ) => ( 1777665071 )
          • ENSRegistryWithFallback.owner( node=93CDEB708B7545DC668EB9280176169D1C33CFD8ED6F04690A0BCC88A93FC4AE ) => ( 0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85 )
          • ETH 0.000020933672533965 0xed976ca9036bc2d4e25ba8219fada1be503a09c7.CALL( )
            File 1 of 4: BaseRegistrarImplementation
            // 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/token/ERC721/IERC721Receiver.sol
            
            pragma solidity ^0.5.0;
            
            /**
             * @title ERC721 token receiver interface
             * @dev Interface for any contract that wants to support safeTransfers
             * from ERC721 asset contracts.
             */
            contract IERC721Receiver {
                /**
                 * @notice Handle the receipt of an NFT
                 * @dev The ERC721 smart contract calls this function on the recipient
                 * after a `safeTransfer`. This function MUST return the function selector,
                 * otherwise the caller will revert the transaction. The selector to be
                 * returned can be obtained as `this.onERC721Received.selector`. This
                 * function MAY throw to revert and reject the transfer.
                 * Note: the ERC721 contract address is always the message sender.
                 * @param operator The address which called `safeTransferFrom` function
                 * @param from The address which previously owned the token
                 * @param tokenId The NFT identifier which is being transferred
                 * @param data Additional data with no specified format
                 * @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
                 */
                function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
                public returns (bytes4);
            }
            
            // File: openzeppelin-solidity/contracts/math/SafeMath.sol
            
            pragma solidity ^0.5.0;
            
            /**
             * @title SafeMath
             * @dev Unsigned math operations with safety checks that revert on error
             */
            library SafeMath {
                /**
                * @dev Multiplies two unsigned integers, reverts on overflow.
                */
                function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                    // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                    // benefit is lost if 'b' is also tested.
                    // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                    if (a == 0) {
                        return 0;
                    }
            
                    uint256 c = a * b;
                    require(c / a == b);
            
                    return c;
                }
            
                /**
                * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
                */
                function div(uint256 a, uint256 b) internal pure returns (uint256) {
                    // Solidity only automatically asserts when dividing by 0
                    require(b > 0);
                    uint256 c = a / b;
                    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
            
                    return c;
                }
            
                /**
                * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
                */
                function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                    require(b <= a);
                    uint256 c = a - b;
            
                    return c;
                }
            
                /**
                * @dev Adds two unsigned integers, reverts on overflow.
                */
                function add(uint256 a, uint256 b) internal pure returns (uint256) {
                    uint256 c = a + b;
                    require(c >= a);
            
                    return c;
                }
            
                /**
                * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
                * reverts when dividing by zero.
                */
                function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                    require(b != 0);
                    return a % b;
                }
            }
            
            // File: openzeppelin-solidity/contracts/utils/Address.sol
            
            pragma solidity ^0.5.0;
            
            /**
             * Utility library of inline functions on addresses
             */
            library Address {
                /**
                 * Returns whether the target address is a contract
                 * @dev This function will return false if invoked during the constructor of a contract,
                 * as the code is not actually created until after the constructor finishes.
                 * @param account address of the account to check
                 * @return whether the target address is a contract
                 */
                function isContract(address account) internal view returns (bool) {
                    uint256 size;
                    // XXX Currently there is no better way to check if there is a contract in an address
                    // than to check the size of the code at that address.
                    // See https://ethereum.stackexchange.com/a/14016/36603
                    // for more details about how this works.
                    // TODO Check this again before the Serenity release, because all addresses will be
                    // contracts then.
                    // solhint-disable-next-line no-inline-assembly
                    assembly { size := extcodesize(account) }
                    return size > 0;
                }
            }
            
            // File: openzeppelin-solidity/contracts/introspection/ERC165.sol
            
            pragma solidity ^0.5.0;
            
            
            /**
             * @title ERC165
             * @author Matt Condon (@shrugs)
             * @dev Implements ERC165 using a lookup table.
             */
            contract ERC165 is IERC165 {
                bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
                /**
                 * 0x01ffc9a7 ===
                 *     bytes4(keccak256('supportsInterface(bytes4)'))
                 */
            
                /**
                 * @dev a mapping of interface id to whether or not it's supported
                 */
                mapping(bytes4 => bool) private _supportedInterfaces;
            
                /**
                 * @dev A contract implementing SupportsInterfaceWithLookup
                 * implement ERC165 itself
                 */
                constructor () internal {
                    _registerInterface(_INTERFACE_ID_ERC165);
                }
            
                /**
                 * @dev implement supportsInterface(bytes4) using a lookup table
                 */
                function supportsInterface(bytes4 interfaceId) external view returns (bool) {
                    return _supportedInterfaces[interfaceId];
                }
            
                /**
                 * @dev internal method for registering an interface
                 */
                function _registerInterface(bytes4 interfaceId) internal {
                    require(interfaceId != 0xffffffff);
                    _supportedInterfaces[interfaceId] = true;
                }
            }
            
            // File: openzeppelin-solidity/contracts/token/ERC721/ERC721.sol
            
            pragma solidity ^0.5.0;
            
            
            
            
            
            
            /**
             * @title ERC721 Non-Fungible Token Standard basic implementation
             * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
             */
            contract ERC721 is ERC165, IERC721 {
                using SafeMath for uint256;
                using Address for address;
            
                // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
                // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
                bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
            
                // Mapping from token ID to owner
                mapping (uint256 => address) private _tokenOwner;
            
                // Mapping from token ID to approved address
                mapping (uint256 => address) private _tokenApprovals;
            
                // Mapping from owner to number of owned token
                mapping (address => uint256) private _ownedTokensCount;
            
                // Mapping from owner to operator approvals
                mapping (address => mapping (address => bool)) private _operatorApprovals;
            
                bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
                /*
                 * 0x80ac58cd ===
                 *     bytes4(keccak256('balanceOf(address)')) ^
                 *     bytes4(keccak256('ownerOf(uint256)')) ^
                 *     bytes4(keccak256('approve(address,uint256)')) ^
                 *     bytes4(keccak256('getApproved(uint256)')) ^
                 *     bytes4(keccak256('setApprovalForAll(address,bool)')) ^
                 *     bytes4(keccak256('isApprovedForAll(address,address)')) ^
                 *     bytes4(keccak256('transferFrom(address,address,uint256)')) ^
                 *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^
                 *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)'))
                 */
            
                constructor () public {
                    // register the supported interfaces to conform to ERC721 via ERC165
                    _registerInterface(_INTERFACE_ID_ERC721);
                }
            
                /**
                 * @dev Gets the balance of the specified address
                 * @param owner address to query the balance of
                 * @return uint256 representing the amount owned by the passed address
                 */
                function balanceOf(address owner) public view returns (uint256) {
                    require(owner != address(0));
                    return _ownedTokensCount[owner];
                }
            
                /**
                 * @dev Gets the owner of the specified token ID
                 * @param tokenId uint256 ID of the token to query the owner of
                 * @return owner address currently marked as the owner of the given token ID
                 */
                function ownerOf(uint256 tokenId) public view returns (address) {
                    address owner = _tokenOwner[tokenId];
                    require(owner != address(0));
                    return owner;
                }
            
                /**
                 * @dev Approves another address to transfer the given token ID
                 * The zero address indicates there is no approved address.
                 * There can only be one approved address per token at a given time.
                 * Can only be called by the token owner or an approved operator.
                 * @param to address to be approved for the given token ID
                 * @param tokenId uint256 ID of the token to be approved
                 */
                function approve(address to, uint256 tokenId) public {
                    address owner = ownerOf(tokenId);
                    require(to != owner);
                    require(msg.sender == owner || isApprovedForAll(owner, msg.sender));
            
                    _tokenApprovals[tokenId] = to;
                    emit Approval(owner, to, tokenId);
                }
            
                /**
                 * @dev Gets the approved address for a token ID, or zero if no address set
                 * Reverts if the token ID does not exist.
                 * @param tokenId uint256 ID of the token to query the approval of
                 * @return address currently approved for the given token ID
                 */
                function getApproved(uint256 tokenId) public view returns (address) {
                    require(_exists(tokenId));
                    return _tokenApprovals[tokenId];
                }
            
                /**
                 * @dev Sets or unsets the approval of a given operator
                 * An operator is allowed to transfer all tokens of the sender on their behalf
                 * @param to operator address to set the approval
                 * @param approved representing the status of the approval to be set
                 */
                function setApprovalForAll(address to, bool approved) public {
                    require(to != msg.sender);
                    _operatorApprovals[msg.sender][to] = approved;
                    emit ApprovalForAll(msg.sender, to, approved);
                }
            
                /**
                 * @dev Tells whether an operator is approved by a given owner
                 * @param owner owner address which you want to query the approval of
                 * @param operator operator address which you want to query the approval of
                 * @return bool whether the given operator is approved by the given owner
                 */
                function isApprovedForAll(address owner, address operator) public view returns (bool) {
                    return _operatorApprovals[owner][operator];
                }
            
                /**
                 * @dev Transfers the ownership of a given token ID to another address
                 * Usage of this method is discouraged, use `safeTransferFrom` whenever possible
                 * Requires the msg sender to be the owner, approved, or operator
                 * @param from current owner of the token
                 * @param to address to receive the ownership of the given token ID
                 * @param tokenId uint256 ID of the token to be transferred
                */
                function transferFrom(address from, address to, uint256 tokenId) public {
                    require(_isApprovedOrOwner(msg.sender, tokenId));
            
                    _transferFrom(from, to, tokenId);
                }
            
                /**
                 * @dev Safely transfers the ownership of a given token ID to another address
                 * If the target address is a contract, it must implement `onERC721Received`,
                 * which is called upon a safe transfer, and return the magic value
                 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
                 * the transfer is reverted.
                 *
                 * Requires the msg sender to be the owner, approved, or operator
                 * @param from current owner of the token
                 * @param to address to receive the ownership of the given token ID
                 * @param tokenId uint256 ID of the token to be transferred
                */
                function safeTransferFrom(address from, address to, uint256 tokenId) public {
                    safeTransferFrom(from, to, tokenId, "");
                }
            
                /**
                 * @dev Safely transfers the ownership of a given token ID to another address
                 * If the target address is a contract, it must implement `onERC721Received`,
                 * which is called upon a safe transfer, and return the magic value
                 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
                 * the transfer is reverted.
                 * Requires the msg sender to be the owner, approved, or operator
                 * @param from current owner of the token
                 * @param to address to receive the ownership of the given token ID
                 * @param tokenId uint256 ID of the token to be transferred
                 * @param _data bytes data to send along with a safe transfer check
                 */
                function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public {
                    transferFrom(from, to, tokenId);
                    require(_checkOnERC721Received(from, to, tokenId, _data));
                }
            
                /**
                 * @dev Returns whether the specified token exists
                 * @param tokenId uint256 ID of the token to query the existence of
                 * @return whether the token exists
                 */
                function _exists(uint256 tokenId) internal view returns (bool) {
                    address owner = _tokenOwner[tokenId];
                    return owner != address(0);
                }
            
                /**
                 * @dev Returns whether the given spender can transfer a given token ID
                 * @param spender address of the spender to query
                 * @param tokenId uint256 ID of the token to be transferred
                 * @return bool whether the msg.sender is approved for the given token ID,
                 *    is an operator of the owner, or is the owner of the token
                 */
                function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
                    address owner = ownerOf(tokenId);
                    return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
                }
            
                /**
                 * @dev Internal function to mint a new token
                 * Reverts if the given token ID already exists
                 * @param to The address that will own the minted token
                 * @param tokenId uint256 ID of the token to be minted
                 */
                function _mint(address to, uint256 tokenId) internal {
                    require(to != address(0));
                    require(!_exists(tokenId));
            
                    _tokenOwner[tokenId] = to;
                    _ownedTokensCount[to] = _ownedTokensCount[to].add(1);
            
                    emit Transfer(address(0), to, tokenId);
                }
            
                /**
                 * @dev Internal function to burn a specific token
                 * Reverts if the token does not exist
                 * Deprecated, use _burn(uint256) instead.
                 * @param owner owner of the token to burn
                 * @param tokenId uint256 ID of the token being burned
                 */
                function _burn(address owner, uint256 tokenId) internal {
                    require(ownerOf(tokenId) == owner);
            
                    _clearApproval(tokenId);
            
                    _ownedTokensCount[owner] = _ownedTokensCount[owner].sub(1);
                    _tokenOwner[tokenId] = address(0);
            
                    emit Transfer(owner, address(0), tokenId);
                }
            
                /**
                 * @dev Internal function to burn a specific token
                 * Reverts if the token does not exist
                 * @param tokenId uint256 ID of the token being burned
                 */
                function _burn(uint256 tokenId) internal {
                    _burn(ownerOf(tokenId), tokenId);
                }
            
                /**
                 * @dev Internal function to transfer ownership of a given token ID to another address.
                 * As opposed to transferFrom, this imposes no restrictions on msg.sender.
                 * @param from current owner of the token
                 * @param to address to receive the ownership of the given token ID
                 * @param tokenId uint256 ID of the token to be transferred
                */
                function _transferFrom(address from, address to, uint256 tokenId) internal {
                    require(ownerOf(tokenId) == from);
                    require(to != address(0));
            
                    _clearApproval(tokenId);
            
                    _ownedTokensCount[from] = _ownedTokensCount[from].sub(1);
                    _ownedTokensCount[to] = _ownedTokensCount[to].add(1);
            
                    _tokenOwner[tokenId] = to;
            
                    emit Transfer(from, to, tokenId);
                }
            
                /**
                 * @dev Internal function to invoke `onERC721Received` on a target address
                 * The call is not executed if the target address is not a contract
                 * @param from address representing the previous owner of the given token ID
                 * @param to target address that will receive the tokens
                 * @param tokenId uint256 ID of the token to be transferred
                 * @param _data bytes optional data to send along with the call
                 * @return whether the call correctly returned the expected magic value
                 */
                function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
                    internal returns (bool)
                {
                    if (!to.isContract()) {
                        return true;
                    }
            
                    bytes4 retval = IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data);
                    return (retval == _ERC721_RECEIVED);
                }
            
                /**
                 * @dev Private function to clear current approval of a given token ID
                 * @param tokenId uint256 ID of the token to be transferred
                 */
                function _clearApproval(uint256 tokenId) private {
                    if (_tokenApprovals[tokenId] != address(0)) {
                        _tokenApprovals[tokenId] = address(0);
                    }
                }
            }
            
            // 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/BaseRegistrarImplementation.sol
            
            pragma solidity ^0.5.0;
            
            
            
            
            contract BaseRegistrarImplementation is BaseRegistrar, ERC721 {
                // A map of expiry times
                mapping(uint256=>uint) expiries;
            
                bytes4 constant private INTERFACE_META_ID = bytes4(keccak256("supportsInterface(bytes4)"));
                bytes4 constant private ERC721_ID = bytes4(
                    keccak256("balanceOf(address)") ^
                    keccak256("ownerOf(uint256)") ^
                    keccak256("approve(address,uint256)") ^
                    keccak256("getApproved(uint256)") ^
                    keccak256("setApprovalForAll(address,bool)") ^
                    keccak256("isApprovedForAll(address,address)") ^
                    keccak256("transferFrom(address,address,uint256)") ^
                    keccak256("safeTransferFrom(address,address,uint256)") ^
                    keccak256("safeTransferFrom(address,address,uint256,bytes)")
                );
                bytes4 constant private RECLAIM_ID = bytes4(keccak256("reclaim(uint256,address)"));
            
                constructor(ENS _ens, bytes32 _baseNode) public {
                    ens = _ens;
                    baseNode = _baseNode;
                }
            
                modifier live {
                    require(ens.owner(baseNode) == address(this));
                    _;
                }
            
                modifier onlyController {
                    require(controllers[msg.sender]);
                    _;
                }
            
                /**
                 * @dev Gets the owner of the specified token ID. Names become unowned
                 *      when their registration expires.
                 * @param tokenId uint256 ID of the token to query the owner of
                 * @return address currently marked as the owner of the given token ID
                 */
                function ownerOf(uint256 tokenId) public view returns (address) {
                    require(expiries[tokenId] > now);
                    return super.ownerOf(tokenId);
                }
            
                // Authorises a controller, who can register and renew domains.
                function addController(address controller) external onlyOwner {
                    controllers[controller] = true;
                    emit ControllerAdded(controller);
                }
            
                // Revoke controller permission for an address.
                function removeController(address controller) external onlyOwner {
                    controllers[controller] = false;
                    emit ControllerRemoved(controller);
                }
            
                // Set the resolver for the TLD this registrar manages.
                function setResolver(address resolver) external onlyOwner {
                    ens.setResolver(baseNode, resolver);
                }
            
                // Returns the expiration timestamp of the specified id.
                function nameExpires(uint256 id) external view returns(uint) {
                    return expiries[id];
                }
            
                // Returns true iff the specified name is available for registration.
                function available(uint256 id) public view returns(bool) {
                    // Not available if it's registered here or in its grace period.
                    return expiries[id] + GRACE_PERIOD < now;
                }
            
                /**
                 * @dev Register a name.
                 * @param id The token ID (keccak256 of the label).
                 * @param owner The address that should own the registration.
                 * @param duration Duration in seconds for the registration.
                 */
                function register(uint256 id, address owner, uint duration) external returns(uint) {
                  return _register(id, owner, duration, true);
                }
            
                /**
                 * @dev Register a name, without modifying the registry.
                 * @param id The token ID (keccak256 of the label).
                 * @param owner The address that should own the registration.
                 * @param duration Duration in seconds for the registration.
                 */
                function registerOnly(uint256 id, address owner, uint duration) external returns(uint) {
                  return _register(id, owner, duration, false);
                }
            
                function _register(uint256 id, address owner, uint duration, bool updateRegistry) internal live onlyController returns(uint) {
                    require(available(id));
                    require(now + duration + GRACE_PERIOD > now + GRACE_PERIOD); // Prevent future overflow
            
                    expiries[id] = now + duration;
                    if(_exists(id)) {
                        // Name was previously owned, and expired
                        _burn(id);
                    }
                    _mint(owner, id);
                    if(updateRegistry) {
                        ens.setSubnodeOwner(baseNode, bytes32(id), owner);
                    }
            
                    emit NameRegistered(id, owner, now + duration);
            
                    return now + duration;
                }
            
                function renew(uint256 id, uint duration) external live onlyController returns(uint) {
                    require(expiries[id] + GRACE_PERIOD >= now); // Name must be registered here or in grace period
                    require(expiries[id] + duration + GRACE_PERIOD > duration + GRACE_PERIOD); // Prevent future overflow
            
                    expiries[id] += duration;
                    emit NameRenewed(id, expiries[id]);
                    return expiries[id];
                }
            
                /**
                 * @dev Reclaim ownership of a name in ENS, if you own it in the registrar.
                 */
                function reclaim(uint256 id, address owner) external live {
                    require(_isApprovedOrOwner(msg.sender, id));
                    ens.setSubnodeOwner(baseNode, bytes32(id), owner);
                }
            
                function supportsInterface(bytes4 interfaceID) external view returns (bool) {
                    return interfaceID == INTERFACE_META_ID ||
                           interfaceID == ERC721_ID ||
                           interfaceID == RECLAIM_ID;
                }
            }

            File 2 of 4: ExponentialPremiumPriceOracle
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
            pragma solidity ^0.8.0;
            import "../utils/Context.sol";
            /**
             * @dev Contract module which provides a basic access control mechanism, where
             * there is an account (an owner) that can be granted exclusive access to
             * specific functions.
             *
             * By default, the owner account will be the one that deploys the contract. This
             * can later be changed with {transferOwnership}.
             *
             * This module is used through inheritance. It will make available the modifier
             * `onlyOwner`, which can be applied to your functions to restrict their use to
             * the owner.
             */
            abstract contract Ownable is Context {
                address private _owner;
                event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                /**
                 * @dev Initializes the contract setting the deployer as the initial owner.
                 */
                constructor() {
                    _transferOwnership(_msgSender());
                }
                /**
                 * @dev Throws if called by any account other than the owner.
                 */
                modifier onlyOwner() {
                    _checkOwner();
                    _;
                }
                /**
                 * @dev Returns the address of the current owner.
                 */
                function owner() public view virtual returns (address) {
                    return _owner;
                }
                /**
                 * @dev Throws if the sender is not the owner.
                 */
                function _checkOwner() internal view virtual {
                    require(owner() == _msgSender(), "Ownable: caller is not the owner");
                }
                /**
                 * @dev Leaves the contract without owner. It will not be possible to call
                 * `onlyOwner` functions anymore. Can only be called by the current owner.
                 *
                 * NOTE: Renouncing ownership will leave the contract without an owner,
                 * thereby removing any functionality that is only available to the owner.
                 */
                function renounceOwnership() public virtual onlyOwner {
                    _transferOwnership(address(0));
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Can only be called by the current owner.
                 */
                function transferOwnership(address newOwner) public virtual onlyOwner {
                    require(newOwner != address(0), "Ownable: new owner is the zero address");
                    _transferOwnership(newOwner);
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Internal function without access restriction.
                 */
                function _transferOwnership(address newOwner) internal virtual {
                    address oldOwner = _owner;
                    _owner = newOwner;
                    emit OwnershipTransferred(oldOwner, newOwner);
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev Provides information about the current execution context, including the
             * sender of the transaction and its data. While these are generally available
             * via msg.sender and msg.data, they should not be accessed in such a direct
             * manner, since when dealing with meta-transactions the account sending and
             * paying for execution may not be the actual sender (as far as an application
             * is concerned).
             *
             * This contract is only required for intermediate, library-like contracts.
             */
            abstract contract Context {
                function _msgSender() internal view virtual returns (address) {
                    return msg.sender;
                }
                function _msgData() internal view virtual returns (bytes calldata) {
                    return msg.data;
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev Interface of the ERC165 standard, as defined in the
             * https://eips.ethereum.org/EIPS/eip-165[EIP].
             *
             * Implementers can declare support of contract interfaces, which can then be
             * queried by others ({ERC165Checker}).
             *
             * For an implementation, see {ERC165}.
             */
            interface IERC165 {
                /**
                 * @dev Returns true if this contract implements the interface defined by
                 * `interfaceId`. See the corresponding
                 * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
                 * to learn more about how these ids are created.
                 *
                 * This function call must use less than 30 000 gas.
                 */
                function supportsInterface(bytes4 interfaceId) external view returns (bool);
            }
            //SPDX-License-Identifier: MIT
            pragma solidity ~0.8.17;
            import "./StablePriceOracle.sol";
            contract ExponentialPremiumPriceOracle is StablePriceOracle {
                uint256 constant GRACE_PERIOD = 90 days;
                uint256 immutable startPremium;
                uint256 immutable endValue;
                constructor(
                    AggregatorInterface _usdOracle,
                    uint256[] memory _rentPrices,
                    uint256 _startPremium,
                    uint256 totalDays
                ) StablePriceOracle(_usdOracle, _rentPrices) {
                    startPremium = _startPremium;
                    endValue = _startPremium >> totalDays;
                }
                uint256 constant PRECISION = 1e18;
                uint256 constant bit1 = 999989423469314432; // 0.5 ^ 1/65536 * (10 ** 18)
                uint256 constant bit2 = 999978847050491904; // 0.5 ^ 2/65536 * (10 ** 18)
                uint256 constant bit3 = 999957694548431104;
                uint256 constant bit4 = 999915390886613504;
                uint256 constant bit5 = 999830788931929088;
                uint256 constant bit6 = 999661606496243712;
                uint256 constant bit7 = 999323327502650752;
                uint256 constant bit8 = 998647112890970240;
                uint256 constant bit9 = 997296056085470080;
                uint256 constant bit10 = 994599423483633152;
                uint256 constant bit11 = 989228013193975424;
                uint256 constant bit12 = 978572062087700096;
                uint256 constant bit13 = 957603280698573696;
                uint256 constant bit14 = 917004043204671232;
                uint256 constant bit15 = 840896415253714560;
                uint256 constant bit16 = 707106781186547584;
                /**
                 * @dev Returns the pricing premium in internal base units.
                 */
                function _premium(
                    string memory,
                    uint256 expires,
                    uint256
                ) internal view override returns (uint256) {
                    expires = expires + GRACE_PERIOD;
                    if (expires > block.timestamp) {
                        return 0;
                    }
                    uint256 elapsed = block.timestamp - expires;
                    uint256 premium = decayedPremium(startPremium, elapsed);
                    if (premium >= endValue) {
                        return premium - endValue;
                    }
                    return 0;
                }
                /**
                 * @dev Returns the premium price at current time elapsed
                 * @param startPremium starting price
                 * @param elapsed time past since expiry
                 */
                function decayedPremium(
                    uint256 startPremium,
                    uint256 elapsed
                ) public pure returns (uint256) {
                    uint256 daysPast = (elapsed * PRECISION) / 1 days;
                    uint256 intDays = daysPast / PRECISION;
                    uint256 premium = startPremium >> intDays;
                    uint256 partDay = (daysPast - intDays * PRECISION);
                    uint256 fraction = (partDay * (2 ** 16)) / PRECISION;
                    uint256 totalPremium = addFractionalPremium(fraction, premium);
                    return totalPremium;
                }
                function addFractionalPremium(
                    uint256 fraction,
                    uint256 premium
                ) internal pure returns (uint256) {
                    if (fraction & (1 << 0) != 0) {
                        premium = (premium * bit1) / PRECISION;
                    }
                    if (fraction & (1 << 1) != 0) {
                        premium = (premium * bit2) / PRECISION;
                    }
                    if (fraction & (1 << 2) != 0) {
                        premium = (premium * bit3) / PRECISION;
                    }
                    if (fraction & (1 << 3) != 0) {
                        premium = (premium * bit4) / PRECISION;
                    }
                    if (fraction & (1 << 4) != 0) {
                        premium = (premium * bit5) / PRECISION;
                    }
                    if (fraction & (1 << 5) != 0) {
                        premium = (premium * bit6) / PRECISION;
                    }
                    if (fraction & (1 << 6) != 0) {
                        premium = (premium * bit7) / PRECISION;
                    }
                    if (fraction & (1 << 7) != 0) {
                        premium = (premium * bit8) / PRECISION;
                    }
                    if (fraction & (1 << 8) != 0) {
                        premium = (premium * bit9) / PRECISION;
                    }
                    if (fraction & (1 << 9) != 0) {
                        premium = (premium * bit10) / PRECISION;
                    }
                    if (fraction & (1 << 10) != 0) {
                        premium = (premium * bit11) / PRECISION;
                    }
                    if (fraction & (1 << 11) != 0) {
                        premium = (premium * bit12) / PRECISION;
                    }
                    if (fraction & (1 << 12) != 0) {
                        premium = (premium * bit13) / PRECISION;
                    }
                    if (fraction & (1 << 13) != 0) {
                        premium = (premium * bit14) / PRECISION;
                    }
                    if (fraction & (1 << 14) != 0) {
                        premium = (premium * bit15) / PRECISION;
                    }
                    if (fraction & (1 << 15) != 0) {
                        premium = (premium * bit16) / PRECISION;
                    }
                    return premium;
                }
                function supportsInterface(
                    bytes4 interfaceID
                ) public view virtual override returns (bool) {
                    return super.supportsInterface(interfaceID);
                }
            }
            //SPDX-License-Identifier: MIT
            pragma solidity >=0.8.17 <0.9.0;
            interface IPriceOracle {
                struct Price {
                    uint256 base;
                    uint256 premium;
                }
                /**
                 * @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 base premium tuple of base price + premium price
                 */
                function price(
                    string calldata name,
                    uint256 expires,
                    uint256 duration
                ) external view returns (Price calldata);
            }
            //SPDX-License-Identifier: MIT
            pragma solidity ~0.8.17;
            import "./IPriceOracle.sol";
            import "./StringUtils.sol";
            import "@openzeppelin/contracts/access/Ownable.sol";
            import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
            interface AggregatorInterface {
                function latestAnswer() external view returns (int256);
            }
            // StablePriceOracle sets a price in USD, based on an oracle.
            contract StablePriceOracle is IPriceOracle {
                using StringUtils for *;
                // Rent in base price units by length
                uint256 public immutable price1Letter;
                uint256 public immutable price2Letter;
                uint256 public immutable price3Letter;
                uint256 public immutable price4Letter;
                uint256 public immutable price5Letter;
                // Oracle address
                AggregatorInterface public immutable usdOracle;
                event RentPriceChanged(uint256[] prices);
                constructor(AggregatorInterface _usdOracle, uint256[] memory _rentPrices) {
                    usdOracle = _usdOracle;
                    price1Letter = _rentPrices[0];
                    price2Letter = _rentPrices[1];
                    price3Letter = _rentPrices[2];
                    price4Letter = _rentPrices[3];
                    price5Letter = _rentPrices[4];
                }
                function price(
                    string calldata name,
                    uint256 expires,
                    uint256 duration
                ) external view override returns (IPriceOracle.Price memory) {
                    uint256 len = name.strlen();
                    uint256 basePrice;
                    if (len >= 5) {
                        basePrice = price5Letter * duration;
                    } else if (len == 4) {
                        basePrice = price4Letter * duration;
                    } else if (len == 3) {
                        basePrice = price3Letter * duration;
                    } else if (len == 2) {
                        basePrice = price2Letter * duration;
                    } else {
                        basePrice = price1Letter * duration;
                    }
                    return
                        IPriceOracle.Price({
                            base: attoUSDToWei(basePrice),
                            premium: attoUSDToWei(_premium(name, expires, duration))
                        });
                }
                /**
                 * @dev Returns the pricing premium in wei.
                 */
                function premium(
                    string calldata name,
                    uint256 expires,
                    uint256 duration
                ) external view returns (uint256) {
                    return attoUSDToWei(_premium(name, expires, duration));
                }
                /**
                 * @dev Returns the pricing premium in internal base units.
                 */
                function _premium(
                    string memory name,
                    uint256 expires,
                    uint256 duration
                ) internal view virtual returns (uint256) {
                    return 0;
                }
                function attoUSDToWei(uint256 amount) internal view returns (uint256) {
                    uint256 ethPrice = uint256(usdOracle.latestAnswer());
                    return (amount * 1e8) / ethPrice;
                }
                function weiToAttoUSD(uint256 amount) internal view returns (uint256) {
                    uint256 ethPrice = uint256(usdOracle.latestAnswer());
                    return (amount * ethPrice) / 1e8;
                }
                function supportsInterface(
                    bytes4 interfaceID
                ) public view virtual returns (bool) {
                    return
                        interfaceID == type(IERC165).interfaceId ||
                        interfaceID == type(IPriceOracle).interfaceId;
                }
            }
            pragma solidity >=0.8.4;
            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 (uint256) {
                    uint256 len;
                    uint256 i = 0;
                    uint256 bytelength = bytes(s).length;
                    for (len = 0; i < bytelength; len++) {
                        bytes1 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 3 of 4: EACAggregatorProxy
            pragma solidity 0.6.6;
            
            
            /**
             * @title The Owned contract
             * @notice A contract with helpers for basic contract ownership.
             */
            contract Owned {
            
              address payable public owner;
              address private pendingOwner;
            
              event OwnershipTransferRequested(
                address indexed from,
                address indexed to
              );
              event OwnershipTransferred(
                address indexed from,
                address indexed to
              );
            
              constructor() public {
                owner = msg.sender;
              }
            
              /**
               * @dev Allows an owner to begin transferring ownership to a new address,
               * pending.
               */
              function transferOwnership(address _to)
                external
                onlyOwner()
              {
                pendingOwner = _to;
            
                emit OwnershipTransferRequested(owner, _to);
              }
            
              /**
               * @dev Allows an ownership transfer to be completed by the recipient.
               */
              function acceptOwnership()
                external
              {
                require(msg.sender == pendingOwner, "Must be proposed owner");
            
                address oldOwner = owner;
                owner = msg.sender;
                pendingOwner = address(0);
            
                emit OwnershipTransferred(oldOwner, msg.sender);
              }
            
              /**
               * @dev Reverts if called by anyone other than the contract owner.
               */
              modifier onlyOwner() {
                require(msg.sender == owner, "Only callable by owner");
                _;
              }
            
            }
            
            interface AggregatorInterface {
              function latestAnswer() external view returns (int256);
              function latestTimestamp() external view returns (uint256);
              function latestRound() external view returns (uint256);
              function getAnswer(uint256 roundId) external view returns (int256);
              function getTimestamp(uint256 roundId) external view returns (uint256);
            
              event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);
              event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
            }
            
            interface AggregatorV3Interface {
            
              function decimals() external view returns (uint8);
              function description() external view returns (string memory);
              function version() external view returns (uint256);
            
              // getRoundData and latestRoundData should both raise "No data present"
              // if they do not have data to report, instead of returning unset values
              // which could be misinterpreted as actual reported values.
              function getRoundData(uint80 _roundId)
                external
                view
                returns (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 answeredInRound
                );
              function latestRoundData()
                external
                view
                returns (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 answeredInRound
                );
            
            }
            
            interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface
            {
            }
            
            /**
             * @title A trusted proxy for updating where current answers are read from
             * @notice This contract provides a consistent address for the
             * CurrentAnwerInterface but delegates where it reads from to the owner, who is
             * trusted to update it.
             */
            contract AggregatorProxy is AggregatorV2V3Interface, Owned {
            
              struct Phase {
                uint16 id;
                AggregatorV2V3Interface aggregator;
              }
              Phase private currentPhase;
              AggregatorV2V3Interface public proposedAggregator;
              mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators;
            
              uint256 constant private PHASE_OFFSET = 64;
              uint256 constant private PHASE_SIZE = 16;
              uint256 constant private MAX_ID = 2**(PHASE_OFFSET+PHASE_SIZE) - 1;
            
              constructor(address _aggregator) public Owned() {
                setAggregator(_aggregator);
              }
            
              /**
               * @notice Reads the current answer from aggregator delegated to.
               *
               * @dev #[deprecated] Use latestRoundData instead. This does not error if no
               * answer has been reached, it will simply return 0. Either wait to point to
               * an already answered Aggregator or use the recommended latestRoundData
               * instead which includes better verification information.
               */
              function latestAnswer()
                public
                view
                virtual
                override
                returns (int256 answer)
              {
                return currentPhase.aggregator.latestAnswer();
              }
            
              /**
               * @notice Reads the last updated height from aggregator delegated to.
               *
               * @dev #[deprecated] Use latestRoundData instead. This does not error if no
               * answer has been reached, it will simply return 0. Either wait to point to
               * an already answered Aggregator or use the recommended latestRoundData
               * instead which includes better verification information.
               */
              function latestTimestamp()
                public
                view
                virtual
                override
                returns (uint256 updatedAt)
              {
                return currentPhase.aggregator.latestTimestamp();
              }
            
              /**
               * @notice get past rounds answers
               * @param _roundId the answer number to retrieve the answer for
               *
               * @dev #[deprecated] Use getRoundData instead. This does not error if no
               * answer has been reached, it will simply return 0. Either wait to point to
               * an already answered Aggregator or use the recommended getRoundData
               * instead which includes better verification information.
               */
              function getAnswer(uint256 _roundId)
                public
                view
                virtual
                override
                returns (int256 answer)
              {
                if (_roundId > MAX_ID) return 0;
            
                (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
                AggregatorV2V3Interface aggregator = phaseAggregators[phaseId];
                if (address(aggregator) == address(0)) return 0;
            
                return aggregator.getAnswer(aggregatorRoundId);
              }
            
              /**
               * @notice get block timestamp when an answer was last updated
               * @param _roundId the answer number to retrieve the updated timestamp for
               *
               * @dev #[deprecated] Use getRoundData instead. This does not error if no
               * answer has been reached, it will simply return 0. Either wait to point to
               * an already answered Aggregator or use the recommended getRoundData
               * instead which includes better verification information.
               */
              function getTimestamp(uint256 _roundId)
                public
                view
                virtual
                override
                returns (uint256 updatedAt)
              {
                if (_roundId > MAX_ID) return 0;
            
                (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
                AggregatorV2V3Interface aggregator = phaseAggregators[phaseId];
                if (address(aggregator) == address(0)) return 0;
            
                return aggregator.getTimestamp(aggregatorRoundId);
              }
            
              /**
               * @notice get the latest completed round where the answer was updated. This
               * ID includes the proxy's phase, to make sure round IDs increase even when
               * switching to a newly deployed aggregator.
               *
               * @dev #[deprecated] Use latestRoundData instead. This does not error if no
               * answer has been reached, it will simply return 0. Either wait to point to
               * an already answered Aggregator or use the recommended latestRoundData
               * instead which includes better verification information.
               */
              function latestRound()
                public
                view
                virtual
                override
                returns (uint256 roundId)
              {
                Phase memory phase = currentPhase; // cache storage reads
                return addPhase(phase.id, uint64(phase.aggregator.latestRound()));
              }
            
              /**
               * @notice get data about a round. Consumers are encouraged to check
               * that they're receiving fresh data by inspecting the updatedAt and
               * answeredInRound return values.
               * Note that different underlying implementations of AggregatorV3Interface
               * have slightly different semantics for some of the return values. Consumers
               * should determine what implementations they expect to receive
               * data from and validate that they can properly handle return data from all
               * of them.
               * @param _roundId the requested round ID as presented through the proxy, this
               * is made up of the aggregator's round ID with the phase ID encoded in the
               * two highest order bytes
               * @return roundId is the round ID from the aggregator for which the data was
               * retrieved combined with an phase to ensure that round IDs get larger as
               * time moves forward.
               * @return answer is the answer for the given round
               * @return startedAt is the timestamp when the round was started.
               * (Only some AggregatorV3Interface implementations return meaningful values)
               * @return updatedAt is the timestamp when the round last was updated (i.e.
               * answer was last computed)
               * @return answeredInRound is the round ID of the round in which the answer
               * was computed.
               * (Only some AggregatorV3Interface implementations return meaningful values)
               * @dev Note that answer and updatedAt may change between queries.
               */
              function getRoundData(uint80 _roundId)
                public
                view
                virtual
                override
                returns (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 answeredInRound
                )
              {
                (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
            
                (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 ansIn
                ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId);
            
                return addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId);
              }
            
              /**
               * @notice get data about the latest round. Consumers are encouraged to check
               * that they're receiving fresh data by inspecting the updatedAt and
               * answeredInRound return values.
               * Note that different underlying implementations of AggregatorV3Interface
               * have slightly different semantics for some of the return values. Consumers
               * should determine what implementations they expect to receive
               * data from and validate that they can properly handle return data from all
               * of them.
               * @return roundId is the round ID from the aggregator for which the data was
               * retrieved combined with an phase to ensure that round IDs get larger as
               * time moves forward.
               * @return answer is the answer for the given round
               * @return startedAt is the timestamp when the round was started.
               * (Only some AggregatorV3Interface implementations return meaningful values)
               * @return updatedAt is the timestamp when the round last was updated (i.e.
               * answer was last computed)
               * @return answeredInRound is the round ID of the round in which the answer
               * was computed.
               * (Only some AggregatorV3Interface implementations return meaningful values)
               * @dev Note that answer and updatedAt may change between queries.
               */
              function latestRoundData()
                public
                view
                virtual
                override
                returns (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 answeredInRound
                )
              {
                Phase memory current = currentPhase; // cache storage reads
            
                (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 ansIn
                ) = current.aggregator.latestRoundData();
            
                return addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, current.id);
              }
            
              /**
               * @notice Used if an aggregator contract has been proposed.
               * @param _roundId the round ID to retrieve the round data for
               * @return roundId is the round ID for which data was retrieved
               * @return answer is the answer for the given round
               * @return startedAt is the timestamp when the round was started.
               * (Only some AggregatorV3Interface implementations return meaningful values)
               * @return updatedAt is the timestamp when the round last was updated (i.e.
               * answer was last computed)
               * @return answeredInRound is the round ID of the round in which the answer
               * was computed.
              */
              function proposedGetRoundData(uint80 _roundId)
                public
                view
                virtual
                hasProposal()
                returns (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 answeredInRound
                )
              {
                return proposedAggregator.getRoundData(_roundId);
              }
            
              /**
               * @notice Used if an aggregator contract has been proposed.
               * @return roundId is the round ID for which data was retrieved
               * @return answer is the answer for the given round
               * @return startedAt is the timestamp when the round was started.
               * (Only some AggregatorV3Interface implementations return meaningful values)
               * @return updatedAt is the timestamp when the round last was updated (i.e.
               * answer was last computed)
               * @return answeredInRound is the round ID of the round in which the answer
               * was computed.
              */
              function proposedLatestRoundData()
                public
                view
                virtual
                hasProposal()
                returns (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 answeredInRound
                )
              {
                return proposedAggregator.latestRoundData();
              }
            
              /**
               * @notice returns the current phase's aggregator address.
               */
              function aggregator()
                external
                view
                returns (address)
              {
                return address(currentPhase.aggregator);
              }
            
              /**
               * @notice returns the current phase's ID.
               */
              function phaseId()
                external
                view
                returns (uint16)
              {
                return currentPhase.id;
              }
            
              /**
               * @notice represents the number of decimals the aggregator responses represent.
               */
              function decimals()
                external
                view
                override
                returns (uint8)
              {
                return currentPhase.aggregator.decimals();
              }
            
              /**
               * @notice the version number representing the type of aggregator the proxy
               * points to.
               */
              function version()
                external
                view
                override
                returns (uint256)
              {
                return currentPhase.aggregator.version();
              }
            
              /**
               * @notice returns the description of the aggregator the proxy points to.
               */
              function description()
                external
                view
                override
                returns (string memory)
              {
                return currentPhase.aggregator.description();
              }
            
              /**
               * @notice Allows the owner to propose a new address for the aggregator
               * @param _aggregator The new address for the aggregator contract
               */
              function proposeAggregator(address _aggregator)
                external
                onlyOwner()
              {
                proposedAggregator = AggregatorV2V3Interface(_aggregator);
              }
            
              /**
               * @notice Allows the owner to confirm and change the address
               * to the proposed aggregator
               * @dev Reverts if the given address doesn't match what was previously
               * proposed
               * @param _aggregator The new address for the aggregator contract
               */
              function confirmAggregator(address _aggregator)
                external
                onlyOwner()
              {
                require(_aggregator == address(proposedAggregator), "Invalid proposed aggregator");
                delete proposedAggregator;
                setAggregator(_aggregator);
              }
            
            
              /*
               * Internal
               */
            
              function setAggregator(address _aggregator)
                internal
              {
                uint16 id = currentPhase.id + 1;
                currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator));
                phaseAggregators[id] = AggregatorV2V3Interface(_aggregator);
              }
            
              function addPhase(
                uint16 _phase,
                uint64 _originalId
              )
                internal
                view
                returns (uint80)
              {
                return uint80(uint256(_phase) << PHASE_OFFSET | _originalId);
              }
            
              function parseIds(
                uint256 _roundId
              )
                internal
                view
                returns (uint16, uint64)
              {
                uint16 phaseId = uint16(_roundId >> PHASE_OFFSET);
                uint64 aggregatorRoundId = uint64(_roundId);
            
                return (phaseId, aggregatorRoundId);
              }
            
              function addPhaseIds(
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 answeredInRound,
                  uint16 phaseId
              )
                internal
                view
                returns (uint80, int256, uint256, uint256, uint80)
              {
                return (
                  addPhase(phaseId, uint64(roundId)),
                  answer,
                  startedAt,
                  updatedAt,
                  addPhase(phaseId, uint64(answeredInRound))
                );
              }
            
              /*
               * Modifiers
               */
            
              modifier hasProposal() {
                require(address(proposedAggregator) != address(0), "No proposed aggregator present");
                _;
              }
            
            }
            
            interface AccessControllerInterface {
              function hasAccess(address user, bytes calldata data) external view returns (bool);
            }
            
            /**
             * @title External Access Controlled Aggregator Proxy
             * @notice A trusted proxy for updating where current answers are read from
             * @notice This contract provides a consistent address for the
             * Aggregator and AggregatorV3Interface but delegates where it reads from to the owner, who is
             * trusted to update it.
             * @notice Only access enabled addresses are allowed to access getters for
             * aggregated answers and round information.
             */
            contract EACAggregatorProxy is AggregatorProxy {
            
              AccessControllerInterface public accessController;
            
              constructor(
                address _aggregator,
                address _accessController
              )
                public
                AggregatorProxy(_aggregator)
              {
                setController(_accessController);
              }
            
              /**
               * @notice Allows the owner to update the accessController contract address.
               * @param _accessController The new address for the accessController contract
               */
              function setController(address _accessController)
                public
                onlyOwner()
              {
                accessController = AccessControllerInterface(_accessController);
              }
            
              /**
               * @notice Reads the current answer from aggregator delegated to.
               * @dev overridden function to add the checkAccess() modifier
               *
               * @dev #[deprecated] Use latestRoundData instead. This does not error if no
               * answer has been reached, it will simply return 0. Either wait to point to
               * an already answered Aggregator or use the recommended latestRoundData
               * instead which includes better verification information.
               */
              function latestAnswer()
                public
                view
                override
                checkAccess()
                returns (int256)
              {
                return super.latestAnswer();
              }
            
              /**
               * @notice get the latest completed round where the answer was updated. This
               * ID includes the proxy's phase, to make sure round IDs increase even when
               * switching to a newly deployed aggregator.
               *
               * @dev #[deprecated] Use latestRoundData instead. This does not error if no
               * answer has been reached, it will simply return 0. Either wait to point to
               * an already answered Aggregator or use the recommended latestRoundData
               * instead which includes better verification information.
               */
              function latestTimestamp()
                public
                view
                override
                checkAccess()
                returns (uint256)
              {
                return super.latestTimestamp();
              }
            
              /**
               * @notice get past rounds answers
               * @param _roundId the answer number to retrieve the answer for
               * @dev overridden function to add the checkAccess() modifier
               *
               * @dev #[deprecated] Use getRoundData instead. This does not error if no
               * answer has been reached, it will simply return 0. Either wait to point to
               * an already answered Aggregator or use the recommended getRoundData
               * instead which includes better verification information.
               */
              function getAnswer(uint256 _roundId)
                public
                view
                override
                checkAccess()
                returns (int256)
              {
                return super.getAnswer(_roundId);
              }
            
              /**
               * @notice get block timestamp when an answer was last updated
               * @param _roundId the answer number to retrieve the updated timestamp for
               * @dev overridden function to add the checkAccess() modifier
               *
               * @dev #[deprecated] Use getRoundData instead. This does not error if no
               * answer has been reached, it will simply return 0. Either wait to point to
               * an already answered Aggregator or use the recommended getRoundData
               * instead which includes better verification information.
               */
              function getTimestamp(uint256 _roundId)
                public
                view
                override
                checkAccess()
                returns (uint256)
              {
                return super.getTimestamp(_roundId);
              }
            
              /**
               * @notice get the latest completed round where the answer was updated
               * @dev overridden function to add the checkAccess() modifier
               *
               * @dev #[deprecated] Use latestRoundData instead. This does not error if no
               * answer has been reached, it will simply return 0. Either wait to point to
               * an already answered Aggregator or use the recommended latestRoundData
               * instead which includes better verification information.
               */
              function latestRound()
                public
                view
                override
                checkAccess()
                returns (uint256)
              {
                return super.latestRound();
              }
            
              /**
               * @notice get data about a round. Consumers are encouraged to check
               * that they're receiving fresh data by inspecting the updatedAt and
               * answeredInRound return values.
               * Note that different underlying implementations of AggregatorV3Interface
               * have slightly different semantics for some of the return values. Consumers
               * should determine what implementations they expect to receive
               * data from and validate that they can properly handle return data from all
               * of them.
               * @param _roundId the round ID to retrieve the round data for
               * @return roundId is the round ID from the aggregator for which the data was
               * retrieved combined with a phase to ensure that round IDs get larger as
               * time moves forward.
               * @return answer is the answer for the given round
               * @return startedAt is the timestamp when the round was started.
               * (Only some AggregatorV3Interface implementations return meaningful values)
               * @return updatedAt is the timestamp when the round last was updated (i.e.
               * answer was last computed)
               * @return answeredInRound is the round ID of the round in which the answer
               * was computed.
               * (Only some AggregatorV3Interface implementations return meaningful values)
               * @dev Note that answer and updatedAt may change between queries.
               */
              function getRoundData(uint80 _roundId)
                public
                view
                checkAccess()
                override
                returns (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 answeredInRound
                )
              {
                return super.getRoundData(_roundId);
              }
            
              /**
               * @notice get data about the latest round. Consumers are encouraged to check
               * that they're receiving fresh data by inspecting the updatedAt and
               * answeredInRound return values.
               * Note that different underlying implementations of AggregatorV3Interface
               * have slightly different semantics for some of the return values. Consumers
               * should determine what implementations they expect to receive
               * data from and validate that they can properly handle return data from all
               * of them.
               * @return roundId is the round ID from the aggregator for which the data was
               * retrieved combined with a phase to ensure that round IDs get larger as
               * time moves forward.
               * @return answer is the answer for the given round
               * @return startedAt is the timestamp when the round was started.
               * (Only some AggregatorV3Interface implementations return meaningful values)
               * @return updatedAt is the timestamp when the round last was updated (i.e.
               * answer was last computed)
               * @return answeredInRound is the round ID of the round in which the answer
               * was computed.
               * (Only some AggregatorV3Interface implementations return meaningful values)
               * @dev Note that answer and updatedAt may change between queries.
               */
              function latestRoundData()
                public
                view
                checkAccess()
                override
                returns (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 answeredInRound
                )
              {
                return super.latestRoundData();
              }
            
              /**
               * @notice Used if an aggregator contract has been proposed.
               * @param _roundId the round ID to retrieve the round data for
               * @return roundId is the round ID for which data was retrieved
               * @return answer is the answer for the given round
               * @return startedAt is the timestamp when the round was started.
               * (Only some AggregatorV3Interface implementations return meaningful values)
               * @return updatedAt is the timestamp when the round last was updated (i.e.
               * answer was last computed)
               * @return answeredInRound is the round ID of the round in which the answer
               * was computed.
              */
              function proposedGetRoundData(uint80 _roundId)
                public
                view
                checkAccess()
                hasProposal()
                override
                returns (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 answeredInRound
                )
              {
                return super.proposedGetRoundData(_roundId);
              }
            
              /**
               * @notice Used if an aggregator contract has been proposed.
               * @return roundId is the round ID for which data was retrieved
               * @return answer is the answer for the given round
               * @return startedAt is the timestamp when the round was started.
               * (Only some AggregatorV3Interface implementations return meaningful values)
               * @return updatedAt is the timestamp when the round last was updated (i.e.
               * answer was last computed)
               * @return answeredInRound is the round ID of the round in which the answer
               * was computed.
              */
              function proposedLatestRoundData()
                public
                view
                checkAccess()
                hasProposal()
                override
                returns (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 answeredInRound
                )
              {
                return super.proposedLatestRoundData();
              }
            
              /**
               * @dev reverts if the caller does not have access by the accessController
               * contract or is the contract itself.
               */
              modifier checkAccess() {
                AccessControllerInterface ac = accessController;
                require(address(ac) == address(0) || ac.hasAccess(msg.sender, msg.data), "No access");
                _;
              }
            }

            File 4 of 4: ENSRegistryWithFallback
            // 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: @ensdomains/ens/contracts/ENSRegistry.sol
            
            pragma solidity ^0.5.0;
            
            
            /**
             * The ENS registry contract.
             */
            contract ENSRegistry is ENS {
            
                struct Record {
                    address owner;
                    address resolver;
                    uint64 ttl;
                }
            
                mapping (bytes32 => Record) records;
                mapping (address => mapping(address => bool)) operators;
            
                // Permits modifications only by the owner of the specified node.
                modifier authorised(bytes32 node) {
                    address owner = records[node].owner;
                    require(owner == msg.sender || operators[owner][msg.sender]);
                    _;
                }
            
                /**
                 * @dev Constructs a new ENS registrar.
                 */
                constructor() public {
                    records[0x0].owner = msg.sender;
                }
            
                /**
                 * @dev Sets the record for a node.
                 * @param node The node to update.
                 * @param owner The address of the new owner.
                 * @param resolver The address of the resolver.
                 * @param ttl The TTL in seconds.
                 */
                function setRecord(bytes32 node, address owner, address resolver, uint64 ttl) external {
                    setOwner(node, owner);
                    _setResolverAndTTL(node, resolver, ttl);
                }
            
                /**
                 * @dev Sets the record for a subnode.
                 * @param node The parent node.
                 * @param label The hash of the label specifying the subnode.
                 * @param owner The address of the new owner.
                 * @param resolver The address of the resolver.
                 * @param ttl The TTL in seconds.
                 */
                function setSubnodeRecord(bytes32 node, bytes32 label, address owner, address resolver, uint64 ttl) external {
                    bytes32 subnode = setSubnodeOwner(node, label, owner);
                    _setResolverAndTTL(subnode, resolver, ttl);
                }
            
                /**
                 * @dev Transfers ownership of a node to a new address. May only be called by the current owner of the node.
                 * @param node The node to transfer ownership of.
                 * @param owner The address of the new owner.
                 */
                function setOwner(bytes32 node, address owner) public authorised(node) {
                    _setOwner(node, owner);
                    emit Transfer(node, owner);
                }
            
                /**
                 * @dev Transfers ownership of a subnode keccak256(node, label) to a new address. May only be called by the owner of the parent node.
                 * @param node The parent node.
                 * @param label The hash of the label specifying the subnode.
                 * @param owner The address of the new owner.
                 */
                function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public authorised(node) returns(bytes32) {
                    bytes32 subnode = keccak256(abi.encodePacked(node, label));
                    _setOwner(subnode, owner);
                    emit NewOwner(node, label, owner);
                    return subnode;
                }
            
                /**
                 * @dev Sets the resolver address for the specified node.
                 * @param node The node to update.
                 * @param resolver The address of the resolver.
                 */
                function setResolver(bytes32 node, address resolver) public authorised(node) {
                    emit NewResolver(node, resolver);
                    records[node].resolver = resolver;
                }
            
                /**
                 * @dev Sets the TTL for the specified node.
                 * @param node The node to update.
                 * @param ttl The TTL in seconds.
                 */
                function setTTL(bytes32 node, uint64 ttl) public authorised(node) {
                    emit NewTTL(node, ttl);
                    records[node].ttl = ttl;
                }
            
                /**
                 * @dev Enable or disable approval for a third party ("operator") to manage
                 *  all of `msg.sender`'s ENS records. Emits the ApprovalForAll event.
                 * @param operator Address to add to the set of authorized operators.
                 * @param approved True if the operator is approved, false to revoke approval.
                 */
                function setApprovalForAll(address operator, bool approved) external {
                    operators[msg.sender][operator] = approved;
                    emit ApprovalForAll(msg.sender, operator, approved);
                }
            
                /**
                 * @dev Returns the address that owns the specified node.
                 * @param node The specified node.
                 * @return address of the owner.
                 */
                function owner(bytes32 node) public view returns (address) {
                    address addr = records[node].owner;
                    if (addr == address(this)) {
                        return address(0x0);
                    }
            
                    return addr;
                }
            
                /**
                 * @dev Returns the address of the resolver for the specified node.
                 * @param node The specified node.
                 * @return address of the resolver.
                 */
                function resolver(bytes32 node) public view returns (address) {
                    return records[node].resolver;
                }
            
                /**
                 * @dev Returns the TTL of a node, and any records associated with it.
                 * @param node The specified node.
                 * @return ttl of the node.
                 */
                function ttl(bytes32 node) public view returns (uint64) {
                    return records[node].ttl;
                }
            
                /**
                 * @dev Returns whether a record has been imported to the registry.
                 * @param node The specified node.
                 * @return Bool if record exists
                 */
                function recordExists(bytes32 node) public view returns (bool) {
                    return records[node].owner != address(0x0);
                }
            
                /**
                 * @dev Query if an address is an authorized operator for another address.
                 * @param owner The address that owns the records.
                 * @param operator The address that acts on behalf of the owner.
                 * @return True if `operator` is an approved operator for `owner`, false otherwise.
                 */
                function isApprovedForAll(address owner, address operator) external view returns (bool) {
                    return operators[owner][operator];
                }
            
                function _setOwner(bytes32 node, address owner) internal {
                    records[node].owner = owner;
                }
            
                function _setResolverAndTTL(bytes32 node, address resolver, uint64 ttl) internal {
                    if(resolver != records[node].resolver) {
                        records[node].resolver = resolver;
                        emit NewResolver(node, resolver);
                    }
            
                    if(ttl != records[node].ttl) {
                        records[node].ttl = ttl;
                        emit NewTTL(node, ttl);
                    }
                }
            }
            
            // File: @ensdomains/ens/contracts/ENSRegistryWithFallback.sol
            
            pragma solidity ^0.5.0;
            
            
            
            /**
             * The ENS registry contract.
             */
            contract ENSRegistryWithFallback is ENSRegistry {
            
                ENS public old;
            
                /**
                 * @dev Constructs a new ENS registrar.
                 */
                constructor(ENS _old) public ENSRegistry() {
                    old = _old;
                }
            
                /**
                 * @dev Returns the address of the resolver for the specified node.
                 * @param node The specified node.
                 * @return address of the resolver.
                 */
                function resolver(bytes32 node) public view returns (address) {
                    if (!recordExists(node)) {
                        return old.resolver(node);
                    }
            
                    return super.resolver(node);
                }
            
                /**
                 * @dev Returns the address that owns the specified node.
                 * @param node The specified node.
                 * @return address of the owner.
                 */
                function owner(bytes32 node) public view returns (address) {
                    if (!recordExists(node)) {
                        return old.owner(node);
                    }
            
                    return super.owner(node);
                }
            
                /**
                 * @dev Returns the TTL of a node, and any records associated with it.
                 * @param node The specified node.
                 * @return ttl of the node.
                 */
                function ttl(bytes32 node) public view returns (uint64) {
                    if (!recordExists(node)) {
                        return old.ttl(node);
                    }
            
                    return super.ttl(node);
                }
            
                function _setOwner(bytes32 node, address owner) internal {
                    address addr = owner;
                    if (addr == address(0x0)) {
                        addr = address(this);
                    }
            
                    super._setOwner(node, addr);
                }
            }