ETH Price: $1,965.29 (-0.78%)

Transaction Decoder

Block:
24482509 at Feb-18-2026 08:24:59 AM +UTC
Transaction Fee:
0.000186655825708192 ETH $0.37
Gas Used:
91,844 Gas / 2.032313768 Gwei

Emitted Events:

276 BaseRegistrarImplementation.NameRenewed( id=34419449573917233387833017832830560321047379427340927702376763611889045818583, expires=1771593186 )
277 ETHRegistrarController.NameRenewed( name=1201, label=4C18B7D4A0E4F2C46154995D106079228D62C5881D3D1D55517DEAC2D5774CD7, cost=647089899955918, expires=1771593186 )

Account State Difference:

  Address   Before After State Difference Code
0x283Af0B2...A627EB7F5
(ENS: Old ETH Registrar Controller)
772.001228347233462739 Eth772.001875437133418657 Eth0.000647089899955918
(Titan Builder)
19.596340602887216408 Eth19.596524290887216408 Eth0.000183688
0x57f1887a...Af147eA85
0xb7fbe2b5...2BDC7886D
0.08128047933614927 Eth
Nonce: 2685
0.08044673361048516 Eth
Nonce: 2686
0.00083374572566411

Execution Trace

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

          File 2 of 5: 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 3 of 5: ExponentialPremiumPriceOracle
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (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 Returns the address of the current owner.
               */
              function owner() public view virtual returns (address) {
                  return _owner;
              }
              /**
               * @dev Throws if called by any account other than the owner.
               */
              modifier onlyOwner() {
                  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;
              }
          }
          pragma solidity >=0.8.4;
          import "./SafeMath.sol";
          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);
              }
          }
          pragma solidity >=0.8.4;
          interface PriceOracle {
              /**
               * @dev Returns the price to register or renew a name.
               * @param name The name being registered or renewed.
               * @param expires When the name presently expires (0 if this is a new registration).
               * @param duration How long the name is being registered or extended for, in seconds.
               * @return The price of this renewal or registration, in wei.
               */
              function price(string calldata name, uint expires, uint duration) external view returns(uint);
          }
          pragma solidity >=0.8.4;
          /**
           * @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;
              }
          }
          pragma solidity >=0.8.4;
          import "./PriceOracle.sol";
          import "./SafeMath.sol";
          import "./StringUtils.sol";
          import "@openzeppelin/contracts/access/Ownable.sol";
          interface AggregatorInterface {
              function latestAnswer() external view returns (int256);
          }
          // StablePriceOracle sets a price in USD, based on an oracle.
          contract StablePriceOracle is Ownable, PriceOracle {
              using SafeMath for *;
              using StringUtils for *;
              // Rent in base price units by length. Element 0 is for 1-length names, and so on.
              uint256[] public rentPrices;
              // Oracle address
              AggregatorInterface public immutable usdOracle;
              event OracleChanged(address oracle);
              event RentPriceChanged(uint256[] prices);
              bytes4 private constant INTERFACE_META_ID =
                  bytes4(keccak256("supportsInterface(bytes4)"));
              bytes4 private constant ORACLE_ID =
                  bytes4(
                      keccak256("price(string,uint256,uint256)") ^
                          keccak256("premium(string,uint256,uint256)")
                  );
              constructor(AggregatorInterface _usdOracle, uint256[] memory _rentPrices)
                  public
              {
                  usdOracle = _usdOracle;
                  setPrices(_rentPrices);
              }
              function price(
                  string calldata name,
                  uint256 expires,
                  uint256 duration
              ) external view override returns (uint256) {
                  uint256 len = name.strlen();
                  if (len > rentPrices.length) {
                      len = rentPrices.length;
                  }
                  require(len > 0);
                  uint256 basePrice = rentPrices[len - 1].mul(duration);
                  basePrice = basePrice.add(_premium(name, expires, duration));
                  return attoUSDToWei(basePrice);
              }
              /**
               * @dev Sets rent prices.
               * @param _rentPrices The price array. Each element corresponds to a specific
               *                    name length; names longer than the length of the array
               *                    default to the price of the last element. Values are
               *                    in base price units, equal to one attodollar (1e-18
               *                    dollar) each.
               */
              function setPrices(uint256[] memory _rentPrices) public onlyOwner {
                  rentPrices = _rentPrices;
                  emit RentPriceChanged(_rentPrices);
              }
              /**
               * @dev Returns the pricing premium in wei.
               */
              function premium(
                  string calldata name,
                  uint256 expires,
                  uint256 duration
              ) external view returns (uint256) {
                  uint256 weiPrice = attoUSDToWei(_premium(name, expires, duration));
                  return weiPrice;
              }
              /**
               * @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()); //2
                  return amount.mul(1e8).div(ethPrice);
              }
              function weiToAttoUSD(uint256 amount) internal view returns (uint256) {
                  uint256 ethPrice = uint256(usdOracle.latestAnswer());
                  return amount.mul(ethPrice).div(1e8);
              }
              function supportsInterface(bytes4 interfaceID)
                  public
                  view
                  virtual
                  returns (bool)
              {
                  return interfaceID == INTERFACE_META_ID || interfaceID == ORACLE_ID;
              }
          }
          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 (uint) {
                  uint len;
                  uint i = 0;
                  uint 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 4 of 5: 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 5 of 5: 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);
              }
          }