ETH Price: $2,537.47 (+1.67%)

Transaction Decoder

Block:
14889737 at Jun-02-2022 07:41:21 AM +UTC
Transaction Fee:
0.010654841059009182 ETH $27.04
Gas Used:
126,693 Gas / 84.099682374 Gwei

Emitted Events:

109 BaseRegistrarImplementation.NameRenewed( id=77235228805990988932561261383787002754675180070502267945881681346873128706341, expires=2288149218 )
110 ETHRegistrarController.NameRenewed( name=davewaslen, label=AAC197215E8BCF00F494C76E367339F3043ABA778E8FAACA82C5F1983C6CE125, cost=54632153892837095, expires=2288149218 )

Account State Difference:

  Address   Before After State Difference Code
0x283Af0B2...A627EB7F5
(ENS: Old ETH Registrar Controller)
16,699.240556151762774478 Eth16,699.295188305655611573 Eth0.054632153892837095
0x57f1887a...Af147eA85
0x72c6C631...721b9226A
5.461901088837044387 Eth
Nonce: 190
5.39661409388519811 Eth
Nonce: 191
0.065286994951846277
(Miner: 0xb7e...707)
28.988834800805221064 Eth28.989024840305221064 Eth0.0001900395

Execution Trace

ETH 0.060095369282120804 BulkRenewal.renewAll( names=[davewaslen], duration=631139040 )
  • ENSRegistryWithFallback.resolver( node=93CDEB708B7545DC668EB9280176169D1C33CFD8ED6F04690A0BCC88A93FC4AE ) => ( 0x30200E0cb040F38E474E53EF437c95A1bE723b2B )
  • OwnedResolver.interfaceImplementer( node=93CDEB708B7545DC668EB9280176169D1C33CFD8ED6F04690A0BCC88A93FC4AE, interfaceID=System.Byte[] ) => ( 0x283Af0B28c62C092C9727F1Ee09c02CA627EB7F5 )
  • ETHRegistrarController.rentPrice( name=davewaslen, duration=631139040 ) => ( 54632153892837095 )
    • BaseRegistrarImplementation.nameExpires( id=77235228805990988932561261383787002754675180070502267945881681346873128706341 ) => ( 1657010178 )
    • ExponentialPremiumPriceOracle.price( name=davewaslen, expires=1657010178, duration=631139040 ) => ( 54632153892837095 )
      • EACAggregatorProxy.STATICCALL( )
        • AccessControlledOffchainAggregator.STATICCALL( )
        • ETH 0.054632153892837095 ETHRegistrarController.renew( name=davewaslen, duration=631139040 )
          • BaseRegistrarImplementation.nameExpires( id=77235228805990988932561261383787002754675180070502267945881681346873128706341 ) => ( 1657010178 )
          • ExponentialPremiumPriceOracle.price( name=davewaslen, expires=1657010178, duration=631139040 ) => ( 54632153892837095 )
            • EACAggregatorProxy.STATICCALL( )
              • AccessControlledOffchainAggregator.STATICCALL( )
              • BaseRegistrarImplementation.renew( id=77235228805990988932561261383787002754675180070502267945881681346873128706341, duration=631139040 ) => ( 2288149218 )
                • ENSRegistryWithFallback.owner( node=93CDEB708B7545DC668EB9280176169D1C33CFD8ED6F04690A0BCC88A93FC4AE ) => ( 0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85 )
                • ETH 0.005463215389283709 0x72c6c6310535edbd273957d476c4c4f721b9226a.CALL( )
                  File 1 of 8: BulkRenewal
                  // 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: 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: 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: 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: 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: 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: contracts/BulkRenewal.sol
                  
                  pragma solidity >=0.5.0;
                  pragma experimental ABIEncoderV2;
                  
                  
                  
                  
                  contract BulkRenewal {
                      bytes32 constant private ETH_NAMEHASH = 0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae;
                      bytes4 constant private REGISTRAR_CONTROLLER_ID = 0x018fac06;
                      bytes4 constant private INTERFACE_META_ID = bytes4(keccak256("supportsInterface(bytes4)"));
                      bytes4 constant public BULK_RENEWAL_ID = bytes4(
                          keccak256("rentPrice(string[],uint)") ^
                          keccak256("renewAll(string[],uint")
                      );
                  
                      ENS public ens;
                  
                      constructor(ENS _ens) public {
                          ens = _ens;
                      }
                  
                      function getController() internal view returns(ETHRegistrarController) {
                          Resolver r = Resolver(ens.resolver(ETH_NAMEHASH));
                          return ETHRegistrarController(r.interfaceImplementer(ETH_NAMEHASH, REGISTRAR_CONTROLLER_ID));
                      }
                  
                      function rentPrice(string[] calldata names, uint duration) external view returns(uint total) {
                          ETHRegistrarController controller = getController();
                          for(uint i = 0; i < names.length; i++) {
                              total += controller.rentPrice(names[i], duration);
                          }
                      }
                  
                      function renewAll(string[] calldata names, uint duration) external payable {
                          ETHRegistrarController controller = getController();
                          for(uint i = 0; i < names.length; i++) {
                              uint cost = controller.rentPrice(names[i], duration);
                              controller.renew.value(cost)(names[i], duration);
                          }
                          // Send any excess funds back
                          msg.sender.transfer(address(this).balance);
                      }
                  
                      function supportsInterface(bytes4 interfaceID) external pure returns (bool) {
                           return interfaceID == INTERFACE_META_ID || interfaceID == BULK_RENEWAL_ID;
                      }
                  }

                  File 2 of 8: 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 8: 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 4 of 8: 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);
                      }
                  }

                  File 5 of 8: OwnedResolver
                  // 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/resolver/contracts/ResolverBase.sol
                  
                  pragma solidity ^0.5.0;
                  
                  contract ResolverBase {
                      bytes4 private constant INTERFACE_META_ID = 0x01ffc9a7;
                  
                      function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
                          return interfaceID == INTERFACE_META_ID;
                      }
                  
                      function isAuthorised(bytes32 node) internal view returns(bool);
                  
                      modifier authorised(bytes32 node) {
                          require(isAuthorised(node));
                          _;
                      }
                  
                      function bytesToAddress(bytes memory b) internal pure returns(address payable a) {
                          require(b.length == 20);
                          assembly {
                              a := div(mload(add(b, 32)), exp(256, 12))
                          }
                      }
                  
                      function addressToBytes(address a) internal pure returns(bytes memory b) {
                          b = new bytes(20);
                          assembly {
                              mstore(add(b, 32), mul(a, exp(256, 12)))
                          }
                      }
                  }
                  
                  // File: @ensdomains/resolver/contracts/profiles/ABIResolver.sol
                  
                  pragma solidity ^0.5.0;
                  
                  
                  contract ABIResolver is ResolverBase {
                      bytes4 constant private ABI_INTERFACE_ID = 0x2203ab56;
                  
                      event ABIChanged(bytes32 indexed node, uint256 indexed contentType);
                  
                      mapping(bytes32=>mapping(uint256=>bytes)) abis;
                  
                      /**
                       * Sets the ABI associated with an ENS node.
                       * Nodes may have one ABI of each content type. To remove an ABI, set it to
                       * the empty string.
                       * @param node The node to update.
                       * @param contentType The content type of the ABI
                       * @param data The ABI data.
                       */
                      function setABI(bytes32 node, uint256 contentType, bytes calldata data) external authorised(node) {
                          // Content types must be powers of 2
                          require(((contentType - 1) & contentType) == 0);
                  
                          abis[node][contentType] = data;
                          emit ABIChanged(node, contentType);
                      }
                  
                      /**
                       * Returns the ABI associated with an ENS node.
                       * Defined in EIP205.
                       * @param node The ENS node to query
                       * @param contentTypes A bitwise OR of the ABI formats accepted by the caller.
                       * @return contentType The content type of the return value
                       * @return data The ABI data
                       */
                      function ABI(bytes32 node, uint256 contentTypes) external view returns (uint256, bytes memory) {
                          mapping(uint256=>bytes) storage abiset = abis[node];
                  
                          for (uint256 contentType = 1; contentType <= contentTypes; contentType <<= 1) {
                              if ((contentType & contentTypes) != 0 && abiset[contentType].length > 0) {
                                  return (contentType, abiset[contentType]);
                              }
                          }
                  
                          return (0, bytes(""));
                      }
                  
                      function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
                          return interfaceID == ABI_INTERFACE_ID || super.supportsInterface(interfaceID);
                      }
                  }
                  
                  // File: @ensdomains/resolver/contracts/profiles/AddrResolver.sol
                  
                  pragma solidity ^0.5.0;
                  
                  
                  contract AddrResolver is ResolverBase {
                      bytes4 constant private ADDR_INTERFACE_ID = 0x3b3b57de;
                      bytes4 constant private ADDRESS_INTERFACE_ID = 0xf1cb7e06;
                      uint constant private COIN_TYPE_ETH = 60;
                  
                      event AddrChanged(bytes32 indexed node, address a);
                      event AddressChanged(bytes32 indexed node, uint coinType, bytes newAddress);
                  
                      mapping(bytes32=>mapping(uint=>bytes)) _addresses;
                  
                      /**
                       * Sets the address associated with an ENS node.
                       * May only be called by the owner of that node in the ENS registry.
                       * @param node The node to update.
                       * @param a The address to set.
                       */
                      function setAddr(bytes32 node, address a) external authorised(node) {
                          setAddr(node, COIN_TYPE_ETH, addressToBytes(a));
                      }
                  
                      /**
                       * Returns the address associated with an ENS node.
                       * @param node The ENS node to query.
                       * @return The associated address.
                       */
                      function addr(bytes32 node) public view returns (address payable) {
                          bytes memory a = addr(node, COIN_TYPE_ETH);
                          if(a.length == 0) {
                              return address(0);
                          }
                          return bytesToAddress(a);
                      }
                  
                      function setAddr(bytes32 node, uint coinType, bytes memory a) public authorised(node) {
                          emit AddressChanged(node, coinType, a);
                          if(coinType == COIN_TYPE_ETH) {
                              emit AddrChanged(node, bytesToAddress(a));
                          }
                          _addresses[node][coinType] = a;
                      }
                  
                      function addr(bytes32 node, uint coinType) public view returns(bytes memory) {
                          return _addresses[node][coinType];
                      }
                  
                      function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
                          return interfaceID == ADDR_INTERFACE_ID || interfaceID == ADDRESS_INTERFACE_ID || super.supportsInterface(interfaceID);
                      }
                  }
                  
                  // File: @ensdomains/resolver/contracts/profiles/ContentHashResolver.sol
                  
                  pragma solidity ^0.5.0;
                  
                  
                  contract ContentHashResolver is ResolverBase {
                      bytes4 constant private CONTENT_HASH_INTERFACE_ID = 0xbc1c58d1;
                  
                      event ContenthashChanged(bytes32 indexed node, bytes hash);
                  
                      mapping(bytes32=>bytes) hashes;
                  
                      /**
                       * Sets the contenthash associated with an ENS node.
                       * May only be called by the owner of that node in the ENS registry.
                       * @param node The node to update.
                       * @param hash The contenthash to set
                       */
                      function setContenthash(bytes32 node, bytes calldata hash) external authorised(node) {
                          hashes[node] = hash;
                          emit ContenthashChanged(node, hash);
                      }
                  
                      /**
                       * Returns the contenthash associated with an ENS node.
                       * @param node The ENS node to query.
                       * @return The associated contenthash.
                       */
                      function contenthash(bytes32 node) external view returns (bytes memory) {
                          return hashes[node];
                      }
                  
                      function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
                          return interfaceID == CONTENT_HASH_INTERFACE_ID || super.supportsInterface(interfaceID);
                      }
                  }
                  
                  // File: @ensdomains/resolver/contracts/profiles/InterfaceResolver.sol
                  
                  pragma solidity ^0.5.0;
                  
                  
                  
                  contract InterfaceResolver is ResolverBase, AddrResolver {
                      bytes4 constant private INTERFACE_INTERFACE_ID = bytes4(keccak256("interfaceImplementer(bytes32,bytes4)"));
                      bytes4 private constant INTERFACE_META_ID = 0x01ffc9a7;
                  
                      event InterfaceChanged(bytes32 indexed node, bytes4 indexed interfaceID, address implementer);
                  
                      mapping(bytes32=>mapping(bytes4=>address)) interfaces;
                  
                      /**
                       * Sets an interface associated with a name.
                       * Setting the address to 0 restores the default behaviour of querying the contract at `addr()` for interface support.
                       * @param node The node to update.
                       * @param interfaceID The EIP 168 interface ID.
                       * @param implementer The address of a contract that implements this interface for this node.
                       */
                      function setInterface(bytes32 node, bytes4 interfaceID, address implementer) external authorised(node) {
                          interfaces[node][interfaceID] = implementer;
                          emit InterfaceChanged(node, interfaceID, implementer);
                      }
                  
                      /**
                       * Returns the address of a contract that implements the specified interface for this name.
                       * If an implementer has not been set for this interfaceID and name, the resolver will query
                       * the contract at `addr()`. If `addr()` is set, a contract exists at that address, and that
                       * contract implements EIP168 and returns `true` for the specified interfaceID, its address
                       * will be returned.
                       * @param node The ENS node to query.
                       * @param interfaceID The EIP 168 interface ID to check for.
                       * @return The address that implements this interface, or 0 if the interface is unsupported.
                       */
                      function interfaceImplementer(bytes32 node, bytes4 interfaceID) external view returns (address) {
                          address implementer = interfaces[node][interfaceID];
                          if(implementer != address(0)) {
                              return implementer;
                          }
                  
                          address a = addr(node);
                          if(a == address(0)) {
                              return address(0);
                          }
                  
                          (bool success, bytes memory returnData) = a.staticcall(abi.encodeWithSignature("supportsInterface(bytes4)", INTERFACE_META_ID));
                          if(!success || returnData.length < 32 || returnData[31] == 0) {
                              // EIP 168 not supported by target
                              return address(0);
                          }
                  
                          (success, returnData) = a.staticcall(abi.encodeWithSignature("supportsInterface(bytes4)", interfaceID));
                          if(!success || returnData.length < 32 || returnData[31] == 0) {
                              // Specified interface not supported by target
                              return address(0);
                          }
                  
                          return a;
                      }
                  
                      function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
                          return interfaceID == INTERFACE_INTERFACE_ID || super.supportsInterface(interfaceID);
                      }
                  }
                  
                  // File: @ensdomains/resolver/contracts/profiles/NameResolver.sol
                  
                  pragma solidity ^0.5.0;
                  
                  
                  contract NameResolver is ResolverBase {
                      bytes4 constant private NAME_INTERFACE_ID = 0x691f3431;
                  
                      event NameChanged(bytes32 indexed node, string name);
                  
                      mapping(bytes32=>string) names;
                  
                      /**
                       * Sets the name associated with an ENS node, for reverse records.
                       * May only be called by the owner of that node in the ENS registry.
                       * @param node The node to update.
                       * @param name The name to set.
                       */
                      function setName(bytes32 node, string calldata name) external authorised(node) {
                          names[node] = name;
                          emit NameChanged(node, name);
                      }
                  
                      /**
                       * Returns the name associated with an ENS node, for reverse records.
                       * Defined in EIP181.
                       * @param node The ENS node to query.
                       * @return The associated name.
                       */
                      function name(bytes32 node) external view returns (string memory) {
                          return names[node];
                      }
                  
                      function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
                          return interfaceID == NAME_INTERFACE_ID || super.supportsInterface(interfaceID);
                      }
                  }
                  
                  // File: @ensdomains/resolver/contracts/profiles/PubkeyResolver.sol
                  
                  pragma solidity ^0.5.0;
                  
                  
                  contract PubkeyResolver is ResolverBase {
                      bytes4 constant private PUBKEY_INTERFACE_ID = 0xc8690233;
                  
                      event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y);
                  
                      struct PublicKey {
                          bytes32 x;
                          bytes32 y;
                      }
                  
                      mapping(bytes32=>PublicKey) pubkeys;
                  
                      /**
                       * Sets the SECP256k1 public key associated with an ENS node.
                       * @param node The ENS node to query
                       * @param x the X coordinate of the curve point for the public key.
                       * @param y the Y coordinate of the curve point for the public key.
                       */
                      function setPubkey(bytes32 node, bytes32 x, bytes32 y) external authorised(node) {
                          pubkeys[node] = PublicKey(x, y);
                          emit PubkeyChanged(node, x, y);
                      }
                  
                      /**
                       * Returns the SECP256k1 public key associated with an ENS node.
                       * Defined in EIP 619.
                       * @param node The ENS node to query
                       * @return x, y the X and Y coordinates of the curve point for the public key.
                       */
                      function pubkey(bytes32 node) external view returns (bytes32 x, bytes32 y) {
                          return (pubkeys[node].x, pubkeys[node].y);
                      }
                  
                      function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
                          return interfaceID == PUBKEY_INTERFACE_ID || super.supportsInterface(interfaceID);
                      }
                  }
                  
                  // File: @ensdomains/resolver/contracts/profiles/TextResolver.sol
                  
                  pragma solidity ^0.5.0;
                  
                  
                  contract TextResolver is ResolverBase {
                      bytes4 constant private TEXT_INTERFACE_ID = 0x59d1d43c;
                  
                      event TextChanged(bytes32 indexed node, string indexed indexedKey, string key);
                  
                      mapping(bytes32=>mapping(string=>string)) texts;
                  
                      /**
                       * Sets the text data associated with an ENS node and key.
                       * May only be called by the owner of that node in the ENS registry.
                       * @param node The node to update.
                       * @param key The key to set.
                       * @param value The text data value to set.
                       */
                      function setText(bytes32 node, string calldata key, string calldata value) external authorised(node) {
                          texts[node][key] = value;
                          emit TextChanged(node, key, key);
                      }
                  
                      /**
                       * Returns the text data associated with an ENS node and key.
                       * @param node The ENS node to query.
                       * @param key The text data key to query.
                       * @return The associated text data.
                       */
                      function text(bytes32 node, string calldata key) external view returns (string memory) {
                          return texts[node][key];
                      }
                  
                      function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
                          return interfaceID == TEXT_INTERFACE_ID || super.supportsInterface(interfaceID);
                      }
                  }
                  
                  // File: @ensdomains/resolver/contracts/OwnedResolver.sol
                  
                  pragma solidity ^0.5.0;
                  
                  
                  
                  
                  
                  
                  
                  
                  
                  /**
                   * A simple resolver anyone can use; only allows the owner of a node to set its
                   * address.
                   */
                  contract OwnedResolver is Ownable, ABIResolver, AddrResolver, ContentHashResolver, InterfaceResolver, NameResolver, PubkeyResolver, TextResolver {
                      function isAuthorised(bytes32 node) internal view returns(bool) {
                          return msg.sender == owner();
                      }
                  }

                  File 6 of 8: 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 7 of 8: 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 8 of 8: AccessControlledOffchainAggregator
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.7.1;
                  import "./OffchainAggregator.sol";
                  import "./SimpleReadAccessController.sol";
                  /**
                   * @notice Wrapper of OffchainAggregator which checks read access on Aggregator-interface methods
                   */
                  contract AccessControlledOffchainAggregator is OffchainAggregator, SimpleReadAccessController {
                    constructor(
                      uint32 _maximumGasPrice,
                      uint32 _reasonableGasPrice,
                      uint32 _microLinkPerEth,
                      uint32 _linkGweiPerObservation,
                      uint32 _linkGweiPerTransmission,
                      address _link,
                      int192 _minAnswer,
                      int192 _maxAnswer,
                      AccessControllerInterface _billingAccessController,
                      AccessControllerInterface _requesterAccessController,
                      uint8 _decimals,
                      string memory description
                    )
                      OffchainAggregator(
                        _maximumGasPrice,
                        _reasonableGasPrice,
                        _microLinkPerEth,
                        _linkGweiPerObservation,
                        _linkGweiPerTransmission,
                        _link,
                        _minAnswer,
                        _maxAnswer,
                        _billingAccessController,
                        _requesterAccessController,
                        _decimals,
                        description
                      ) {
                      }
                    /*
                     * Versioning
                     */
                    function typeAndVersion()
                      external
                      override
                      pure
                      virtual
                      returns (string memory)
                    {
                      return "AccessControlledOffchainAggregator 2.0.0";
                    }
                    /*
                     * v2 Aggregator interface
                     */
                    /// @inheritdoc OffchainAggregator
                    function latestAnswer()
                      public
                      override
                      view
                      checkAccess()
                      returns (int256)
                    {
                      return super.latestAnswer();
                    }
                    /// @inheritdoc OffchainAggregator
                    function latestTimestamp()
                      public
                      override
                      view
                      checkAccess()
                      returns (uint256)
                    {
                      return super.latestTimestamp();
                    }
                    /// @inheritdoc OffchainAggregator
                    function latestRound()
                      public
                      override
                      view
                      checkAccess()
                      returns (uint256)
                    {
                      return super.latestRound();
                    }
                    /// @inheritdoc OffchainAggregator
                    function getAnswer(uint256 _roundId)
                      public
                      override
                      view
                      checkAccess()
                      returns (int256)
                    {
                      return super.getAnswer(_roundId);
                    }
                    /// @inheritdoc OffchainAggregator
                    function getTimestamp(uint256 _roundId)
                      public
                      override
                      view
                      checkAccess()
                      returns (uint256)
                    {
                      return super.getTimestamp(_roundId);
                    }
                    /*
                     * v3 Aggregator interface
                     */
                    /// @inheritdoc OffchainAggregator
                    function description()
                      public
                      override
                      view
                      checkAccess()
                      returns (string memory)
                    {
                      return super.description();
                    }
                    /// @inheritdoc OffchainAggregator
                    function getRoundData(uint80 _roundId)
                      public
                      override
                      view
                      checkAccess()
                      returns (
                        uint80 roundId,
                        int256 answer,
                        uint256 startedAt,
                        uint256 updatedAt,
                        uint80 answeredInRound
                      )
                    {
                      return super.getRoundData(_roundId);
                    }
                    /// @inheritdoc OffchainAggregator
                    function latestRoundData()
                      public
                      override
                      view
                      checkAccess()
                      returns (
                        uint80 roundId,
                        int256 answer,
                        uint256 startedAt,
                        uint256 updatedAt,
                        uint80 answeredInRound
                      )
                    {
                      return super.latestRoundData();
                    }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.7.0;
                  import "./AccessControllerInterface.sol";
                  import "./AggregatorV2V3Interface.sol";
                  import "./AggregatorValidatorInterface.sol";
                  import "./LinkTokenInterface.sol";
                  import "./Owned.sol";
                  import "./OffchainAggregatorBilling.sol";
                  import "./TypeAndVersionInterface.sol";
                  /**
                    * @notice Onchain verification of reports from the offchain reporting protocol
                    * @dev For details on its operation, see the offchain reporting protocol design
                    * @dev doc, which refers to this contract as simply the "contract".
                  */
                  contract OffchainAggregator is Owned, OffchainAggregatorBilling, AggregatorV2V3Interface, TypeAndVersionInterface {
                    uint256 constant private maxUint32 = (1 << 32) - 1;
                    // Storing these fields used on the hot path in a HotVars variable reduces the
                    // retrieval of all of them to a single SLOAD. If any further fields are
                    // added, make sure that storage of the struct still takes at most 32 bytes.
                    struct HotVars {
                      // Provides 128 bits of security against 2nd pre-image attacks, but only
                      // 64 bits against collisions. This is acceptable, since a malicious owner has
                      // easier way of messing up the protocol than to find hash collisions.
                      bytes16 latestConfigDigest;
                      uint40 latestEpochAndRound; // 32 most sig bits for epoch, 8 least sig bits for round
                      // Current bound assumed on number of faulty/dishonest oracles participating
                      // in the protocol, this value is referred to as f in the design
                      uint8 threshold;
                      // Chainlink Aggregators expose a roundId to consumers. The offchain reporting
                      // protocol does not use this id anywhere. We increment it whenever a new
                      // transmission is made to provide callers with contiguous ids for successive
                      // reports.
                      uint32 latestAggregatorRoundId;
                    }
                    HotVars internal s_hotVars;
                    // Transmission records the median answer from the transmit transaction at
                    // time timestamp
                    struct Transmission {
                      int192 answer; // 192 bits ought to be enough for anyone
                      uint64 timestamp;
                    }
                    mapping(uint32 /* aggregator round ID */ => Transmission) internal s_transmissions;
                    // incremented each time a new config is posted. This count is incorporated
                    // into the config digest, to prevent replay attacks.
                    uint32 internal s_configCount;
                    uint32 internal s_latestConfigBlockNumber; // makes it easier for offchain systems
                                                               // to extract config from logs.
                    // Lowest answer the system is allowed to report in response to transmissions
                    int192 immutable public minAnswer;
                    // Highest answer the system is allowed to report in response to transmissions
                    int192 immutable public maxAnswer;
                    /*
                     * @param _maximumGasPrice highest gas price for which transmitter will be compensated
                     * @param _reasonableGasPrice transmitter will receive reward for gas prices under this value
                     * @param _microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
                     * @param _linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
                     * @param _linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
                     * @param _link address of the LINK contract
                     * @param _minAnswer lowest answer the median of a report is allowed to be
                     * @param _maxAnswer highest answer the median of a report is allowed to be
                     * @param _billingAccessController access controller for billing admin functions
                     * @param _requesterAccessController access controller for requesting new rounds
                     * @param _decimals answers are stored in fixed-point format, with this many digits of precision
                     * @param _description short human-readable description of observable this contract's answers pertain to
                     */
                    constructor(
                      uint32 _maximumGasPrice,
                      uint32 _reasonableGasPrice,
                      uint32 _microLinkPerEth,
                      uint32 _linkGweiPerObservation,
                      uint32 _linkGweiPerTransmission,
                      address _link,
                      int192 _minAnswer,
                      int192 _maxAnswer,
                      AccessControllerInterface _billingAccessController,
                      AccessControllerInterface _requesterAccessController,
                      uint8 _decimals,
                      string memory _description
                    )
                      OffchainAggregatorBilling(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
                        _linkGweiPerObservation, _linkGweiPerTransmission, _link,
                        _billingAccessController
                      )
                    {
                      decimals = _decimals;
                      s_description = _description;
                      setRequesterAccessController(_requesterAccessController);
                      setValidatorConfig(AggregatorValidatorInterface(0x0), 0);
                      minAnswer = _minAnswer;
                      maxAnswer = _maxAnswer;
                    }
                    /*
                     * Versioning
                     */
                    function typeAndVersion()
                      external
                      override
                      pure
                      virtual
                      returns (string memory)
                    {
                      return "OffchainAggregator 2.0.0";
                    }
                    /*
                     * Config logic
                     */
                    /**
                     * @notice triggers a new run of the offchain reporting protocol
                     * @param previousConfigBlockNumber block in which the previous config was set, to simplify historic analysis
                     * @param configCount ordinal number of this config setting among all config settings over the life of this contract
                     * @param signers ith element is address ith oracle uses to sign a report
                     * @param transmitters ith element is address ith oracle uses to transmit a report via the transmit method
                     * @param threshold maximum number of faulty/dishonest oracles the protocol can tolerate while still working correctly
                     * @param encodedConfigVersion version of the serialization format used for "encoded" parameter
                     * @param encoded serialized data used by oracles to configure their offchain operation
                     */
                    event ConfigSet(
                      uint32 previousConfigBlockNumber,
                      uint64 configCount,
                      address[] signers,
                      address[] transmitters,
                      uint8 threshold,
                      uint64 encodedConfigVersion,
                      bytes encoded
                    );
                    // Reverts transaction if config args are invalid
                    modifier checkConfigValid (
                      uint256 _numSigners, uint256 _numTransmitters, uint256 _threshold
                    ) {
                      require(_numSigners <= maxNumOracles, "too many signers");
                      require(_threshold > 0, "threshold must be positive");
                      require(
                        _numSigners == _numTransmitters,
                        "oracle addresses out of registration"
                      );
                      require(_numSigners > 3*_threshold, "faulty-oracle threshold too high");
                      _;
                    }
                    /**
                     * @notice sets offchain reporting protocol configuration incl. participating oracles
                     * @param _signers addresses with which oracles sign the reports
                     * @param _transmitters addresses oracles use to transmit the reports
                     * @param _threshold number of faulty oracles the system can tolerate
                     * @param _encodedConfigVersion version number for offchainEncoding schema
                     * @param _encoded encoded off-chain oracle configuration
                     */
                    function setConfig(
                      address[] calldata _signers,
                      address[] calldata _transmitters,
                      uint8 _threshold,
                      uint64 _encodedConfigVersion,
                      bytes calldata _encoded
                    )
                      external
                      checkConfigValid(_signers.length, _transmitters.length, _threshold)
                      onlyOwner()
                    {
                      while (s_signers.length != 0) { // remove any old signer/transmitter addresses
                        uint lastIdx = s_signers.length - 1;
                        address signer = s_signers[lastIdx];
                        address transmitter = s_transmitters[lastIdx];
                        payOracle(transmitter);
                        delete s_oracles[signer];
                        delete s_oracles[transmitter];
                        s_signers.pop();
                        s_transmitters.pop();
                      }
                      for (uint i = 0; i < _signers.length; i++) { // add new signer/transmitter addresses
                        require(
                          s_oracles[_signers[i]].role == Role.Unset,
                          "repeated signer address"
                        );
                        s_oracles[_signers[i]] = Oracle(uint8(i), Role.Signer);
                        require(s_payees[_transmitters[i]] != address(0), "payee must be set");
                        require(
                          s_oracles[_transmitters[i]].role == Role.Unset,
                          "repeated transmitter address"
                        );
                        s_oracles[_transmitters[i]] = Oracle(uint8(i), Role.Transmitter);
                        s_signers.push(_signers[i]);
                        s_transmitters.push(_transmitters[i]);
                      }
                      s_hotVars.threshold = _threshold;
                      uint32 previousConfigBlockNumber = s_latestConfigBlockNumber;
                      s_latestConfigBlockNumber = uint32(block.number);
                      s_configCount += 1;
                      uint64 configCount = s_configCount;
                      {
                        s_hotVars.latestConfigDigest = configDigestFromConfigData(
                          address(this),
                          configCount,
                          _signers,
                          _transmitters,
                          _threshold,
                          _encodedConfigVersion,
                          _encoded
                        );
                        s_hotVars.latestEpochAndRound = 0;
                      }
                      emit ConfigSet(
                        previousConfigBlockNumber,
                        configCount,
                        _signers,
                        _transmitters,
                        _threshold,
                        _encodedConfigVersion,
                        _encoded
                      );
                    }
                    function configDigestFromConfigData(
                      address _contractAddress,
                      uint64 _configCount,
                      address[] calldata _signers,
                      address[] calldata _transmitters,
                      uint8 _threshold,
                      uint64 _encodedConfigVersion,
                      bytes calldata _encodedConfig
                    ) internal pure returns (bytes16) {
                      return bytes16(keccak256(abi.encode(_contractAddress, _configCount,
                        _signers, _transmitters, _threshold, _encodedConfigVersion, _encodedConfig
                      )));
                    }
                    /**
                     * @notice information about current offchain reporting protocol configuration
                     * @return configCount ordinal number of current config, out of all configs applied to this contract so far
                     * @return blockNumber block at which this config was set
                     * @return configDigest domain-separation tag for current config (see configDigestFromConfigData)
                     */
                    function latestConfigDetails()
                      external
                      view
                      returns (
                        uint32 configCount,
                        uint32 blockNumber,
                        bytes16 configDigest
                      )
                    {
                      return (s_configCount, s_latestConfigBlockNumber, s_hotVars.latestConfigDigest);
                    }
                    /**
                     * @return list of addresses permitted to transmit reports to this contract
                     * @dev The list will match the order used to specify the transmitter during setConfig
                     */
                    function transmitters()
                      external
                      view
                      returns(address[] memory)
                    {
                        return s_transmitters;
                    }
                    /*
                     * On-chain validation logc
                     */
                    // Configuration for validator
                    struct ValidatorConfig {
                      AggregatorValidatorInterface validator;
                      uint32 gasLimit;
                    }
                    ValidatorConfig private s_validatorConfig;
                    /**
                     * @notice indicates that the validator configuration has been set
                     * @param previousValidator previous validator contract
                     * @param previousGasLimit previous gas limit for validate calls
                     * @param currentValidator current validator contract
                     * @param currentGasLimit current gas limit for validate calls
                     */
                    event ValidatorConfigSet(
                      AggregatorValidatorInterface indexed previousValidator,
                      uint32 previousGasLimit,
                      AggregatorValidatorInterface indexed currentValidator,
                      uint32 currentGasLimit
                    );
                    /**
                     * @notice validator configuration
                     * @return validator validator contract
                     * @return gasLimit gas limit for validate calls
                     */
                    function validatorConfig()
                      external
                      view
                      returns (AggregatorValidatorInterface validator, uint32 gasLimit)
                    {
                      ValidatorConfig memory vc = s_validatorConfig;
                      return (vc.validator, vc.gasLimit);
                    }
                    /**
                     * @notice sets validator configuration
                     * @dev set _newValidator to 0x0 to disable validate calls
                     * @param _newValidator address of the new validator contract
                     * @param _newGasLimit new gas limit for validate calls
                     */
                    function setValidatorConfig(AggregatorValidatorInterface _newValidator, uint32 _newGasLimit)
                      public
                      onlyOwner()
                    {
                      ValidatorConfig memory previous = s_validatorConfig;
                      if (previous.validator != _newValidator || previous.gasLimit != _newGasLimit) {
                        s_validatorConfig = ValidatorConfig({
                          validator: _newValidator,
                          gasLimit: _newGasLimit
                        });
                        emit ValidatorConfigSet(previous.validator, previous.gasLimit, _newValidator, _newGasLimit);
                      }
                    }
                    function validateAnswer(
                      uint32 _aggregatorRoundId,
                      int256 _answer
                    )
                      private
                    {
                      ValidatorConfig memory vc = s_validatorConfig;
                      if (address(vc.validator) == address(0)) {
                        return;
                      }
                      uint32 prevAggregatorRoundId = _aggregatorRoundId - 1;
                      int256 prevAggregatorRoundAnswer = s_transmissions[prevAggregatorRoundId].answer;
                      // We do not want the validator to ever prevent reporting, so we limit its
                      // gas usage and catch any errors that may arise.
                      try vc.validator.validate{gas: vc.gasLimit}(
                        prevAggregatorRoundId,
                        prevAggregatorRoundAnswer,
                        _aggregatorRoundId,
                        _answer
                      ) {} catch {}
                    }
                    /*
                     * requestNewRound logic
                     */
                    AccessControllerInterface internal s_requesterAccessController;
                    /**
                     * @notice emitted when a new requester access controller contract is set
                     * @param old the address prior to the current setting
                     * @param current the address of the new access controller contract
                     */
                    event RequesterAccessControllerSet(AccessControllerInterface old, AccessControllerInterface current);
                    /**
                     * @notice emitted to immediately request a new round
                     * @param requester the address of the requester
                     * @param configDigest the latest transmission's configDigest
                     * @param epoch the latest transmission's epoch
                     * @param round the latest transmission's round
                     */
                    event RoundRequested(address indexed requester, bytes16 configDigest, uint32 epoch, uint8 round);
                    /**
                     * @notice address of the requester access controller contract
                     * @return requester access controller address
                     */
                    function requesterAccessController()
                      external
                      view
                      returns (AccessControllerInterface)
                    {
                      return s_requesterAccessController;
                    }
                    /**
                     * @notice sets the requester access controller
                     * @param _requesterAccessController designates the address of the new requester access controller
                     */
                    function setRequesterAccessController(AccessControllerInterface _requesterAccessController)
                      public
                      onlyOwner()
                    {
                      AccessControllerInterface oldController = s_requesterAccessController;
                      if (_requesterAccessController != oldController) {
                        s_requesterAccessController = AccessControllerInterface(_requesterAccessController);
                        emit RequesterAccessControllerSet(oldController, _requesterAccessController);
                      }
                    }
                    /**
                     * @notice immediately requests a new round
                     * @return the aggregatorRoundId of the next round. Note: The report for this round may have been
                     * transmitted (but not yet mined) *before* requestNewRound() was even called. There is *no*
                     * guarantee of causality between the request and the report at aggregatorRoundId.
                     */
                    function requestNewRound() external returns (uint80) {
                      require(msg.sender == owner || s_requesterAccessController.hasAccess(msg.sender, msg.data),
                        "Only owner&requester can call");
                      HotVars memory hotVars = s_hotVars;
                      emit RoundRequested(
                        msg.sender,
                        hotVars.latestConfigDigest,
                        uint32(s_hotVars.latestEpochAndRound >> 8),
                        uint8(s_hotVars.latestEpochAndRound)
                      );
                      return hotVars.latestAggregatorRoundId + 1;
                    }
                    /*
                     * Transmission logic
                     */
                    /**
                     * @notice indicates that a new report was transmitted
                     * @param aggregatorRoundId the round to which this report was assigned
                     * @param answer median of the observations attached this report
                     * @param transmitter address from which the report was transmitted
                     * @param observations observations transmitted with this report
                     * @param rawReportContext signature-replay-prevention domain-separation tag
                     */
                    event NewTransmission(
                      uint32 indexed aggregatorRoundId,
                      int192 answer,
                      address transmitter,
                      int192[] observations,
                      bytes observers,
                      bytes32 rawReportContext
                    );
                    // decodeReport is used to check that the solidity and go code are using the
                    // same format. See TestOffchainAggregator.testDecodeReport and TestReportParsing
                    function decodeReport(bytes memory _report)
                      internal
                      pure
                      returns (
                        bytes32 rawReportContext,
                        bytes32 rawObservers,
                        int192[] memory observations
                      )
                    {
                      (rawReportContext, rawObservers, observations) = abi.decode(_report,
                        (bytes32, bytes32, int192[]));
                    }
                    // Used to relieve stack pressure in transmit
                    struct ReportData {
                      HotVars hotVars; // Only read from storage once
                      bytes observers; // ith element is the index of the ith observer
                      int192[] observations; // ith element is the ith observation
                      bytes vs; // jth element is the v component of the jth signature
                      bytes32 rawReportContext;
                    }
                    /*
                     * @notice details about the most recent report
                     * @return configDigest domain separation tag for the latest report
                     * @return epoch epoch in which the latest report was generated
                     * @return round OCR round in which the latest report was generated
                     * @return latestAnswer median value from latest report
                     * @return latestTimestamp when the latest report was transmitted
                     */
                    function latestTransmissionDetails()
                      external
                      view
                      returns (
                        bytes16 configDigest,
                        uint32 epoch,
                        uint8 round,
                        int192 latestAnswer,
                        uint64 latestTimestamp
                      )
                    {
                      require(msg.sender == tx.origin, "Only callable by EOA");
                      return (
                        s_hotVars.latestConfigDigest,
                        uint32(s_hotVars.latestEpochAndRound >> 8),
                        uint8(s_hotVars.latestEpochAndRound),
                        s_transmissions[s_hotVars.latestAggregatorRoundId].answer,
                        s_transmissions[s_hotVars.latestAggregatorRoundId].timestamp
                      );
                    }
                    // The constant-length components of the msg.data sent to transmit.
                    // See the "If we wanted to call sam" example on for example reasoning
                    // https://solidity.readthedocs.io/en/v0.7.2/abi-spec.html
                    uint16 private constant TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT =
                      4 + // function selector
                      32 + // word containing start location of abiencoded _report value
                      32 + // word containing location start of abiencoded  _rs value
                      32 + // word containing start location of abiencoded _ss value
                      32 + // _rawVs value
                      32 + // word containing length of _report
                      32 + // word containing length _rs
                      32 + // word containing length of _ss
                      0; // placeholder
                    function expectedMsgDataLength(
                      bytes calldata _report, bytes32[] calldata _rs, bytes32[] calldata _ss
                    ) private pure returns (uint256 length)
                    {
                      // calldata will never be big enough to make this overflow
                      return uint256(TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT) +
                        _report.length + // one byte pure entry in _report
                        _rs.length * 32 + // 32 bytes per entry in _rs
                        _ss.length * 32 + // 32 bytes per entry in _ss
                        0; // placeholder
                    }
                    /**
                     * @notice transmit is called to post a new report to the contract
                     * @param _report serialized report, which the signatures are signing. See parsing code below for format. The ith element of the observers component must be the index in s_signers of the address for the ith signature
                     * @param _rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries
                     * @param _ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries
                     * @param _rawVs ith element is the the V component of the ith signature
                     */
                    function transmit(
                      // NOTE: If these parameters are changed, expectedMsgDataLength and/or
                      // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly
                      bytes calldata _report,
                      bytes32[] calldata _rs, bytes32[] calldata _ss, bytes32 _rawVs // signatures
                    )
                      external
                    {
                      uint256 initialGas = gasleft(); // This line must come first
                      // Make sure the transmit message-length matches the inputs. Otherwise, the
                      // transmitter could append an arbitrarily long (up to gas-block limit)
                      // string of 0 bytes, which we would reimburse at a rate of 16 gas/byte, but
                      // which would only cost the transmitter 4 gas/byte. (Appendix G of the
                      // yellow paper, p. 25, for G_txdatazero and EIP 2028 for G_txdatanonzero.)
                      // This could amount to reimbursement profit of 36 million gas, given a 3MB
                      // zero tail.
                      require(msg.data.length == expectedMsgDataLength(_report, _rs, _ss),
                        "transmit message too long");
                      ReportData memory r; // Relieves stack pressure
                      {
                        r.hotVars = s_hotVars; // cache read from storage
                        bytes32 rawObservers;
                        (r.rawReportContext, rawObservers, r.observations) = abi.decode(
                          _report, (bytes32, bytes32, int192[])
                        );
                        // rawReportContext consists of:
                        // 11-byte zero padding
                        // 16-byte configDigest
                        // 4-byte epoch
                        // 1-byte round
                        bytes16 configDigest = bytes16(r.rawReportContext << 88);
                        require(
                          r.hotVars.latestConfigDigest == configDigest,
                          "configDigest mismatch"
                        );
                        uint40 epochAndRound = uint40(uint256(r.rawReportContext));
                        // direct numerical comparison works here, because
                        //
                        //   ((e,r) <= (e',r')) implies (epochAndRound <= epochAndRound')
                        //
                        // because alphabetic ordering implies e <= e', and if e = e', then r<=r',
                        // so e*256+r <= e'*256+r', because r, r' < 256
                        require(r.hotVars.latestEpochAndRound < epochAndRound, "stale report");
                        require(_rs.length > r.hotVars.threshold, "not enough signatures");
                        require(_rs.length <= maxNumOracles, "too many signatures");
                        require(_ss.length == _rs.length, "signatures out of registration");
                        require(r.observations.length <= maxNumOracles,
                                "num observations out of bounds");
                        require(r.observations.length > 2 * r.hotVars.threshold,
                                "too few values to trust median");
                        // Copy signature parities in bytes32 _rawVs to bytes r.v
                        r.vs = new bytes(_rs.length);
                        for (uint8 i = 0; i < _rs.length; i++) {
                          r.vs[i] = _rawVs[i];
                        }
                        // Copy observer identities in bytes32 rawObservers to bytes r.observers
                        r.observers = new bytes(r.observations.length);
                        bool[maxNumOracles] memory seen;
                        for (uint8 i = 0; i < r.observations.length; i++) {
                          uint8 observerIdx = uint8(rawObservers[i]);
                          require(!seen[observerIdx], "observer index repeated");
                          seen[observerIdx] = true;
                          r.observers[i] = rawObservers[i];
                        }
                        Oracle memory transmitter = s_oracles[msg.sender];
                        require( // Check that sender is authorized to report
                          transmitter.role == Role.Transmitter &&
                          msg.sender == s_transmitters[transmitter.index],
                          "unauthorized transmitter"
                        );
                        // record epochAndRound here, so that we don't have to carry the local
                        // variable in transmit. The change is reverted if something fails later.
                        r.hotVars.latestEpochAndRound = epochAndRound;
                      }
                      { // Verify signatures attached to report
                        bytes32 h = keccak256(_report);
                        bool[maxNumOracles] memory signed;
                        Oracle memory o;
                        for (uint i = 0; i < _rs.length; i++) {
                          address signer = ecrecover(h, uint8(r.vs[i])+27, _rs[i], _ss[i]);
                          o = s_oracles[signer];
                          require(o.role == Role.Signer, "address not authorized to sign");
                          require(!signed[o.index], "non-unique signature");
                          signed[o.index] = true;
                        }
                      }
                      { // Check the report contents, and record the result
                        for (uint i = 0; i < r.observations.length - 1; i++) {
                          bool inOrder = r.observations[i] <= r.observations[i+1];
                          require(inOrder, "observations not sorted");
                        }
                        int192 median = r.observations[r.observations.length/2];
                        require(minAnswer <= median && median <= maxAnswer, "median is out of min-max range");
                        r.hotVars.latestAggregatorRoundId++;
                        s_transmissions[r.hotVars.latestAggregatorRoundId] =
                          Transmission(median, uint64(block.timestamp));
                        emit NewTransmission(
                          r.hotVars.latestAggregatorRoundId,
                          median,
                          msg.sender,
                          r.observations,
                          r.observers,
                          r.rawReportContext
                        );
                        // Emit these for backwards compatability with offchain consumers
                        // that only support legacy events
                        emit NewRound(
                          r.hotVars.latestAggregatorRoundId,
                          address(0x0), // use zero address since we don't have anybody "starting" the round here
                          block.timestamp
                        );
                        emit AnswerUpdated(
                          median,
                          r.hotVars.latestAggregatorRoundId,
                          block.timestamp
                        );
                        validateAnswer(r.hotVars.latestAggregatorRoundId, median);
                      }
                      s_hotVars = r.hotVars;
                      assert(initialGas < maxUint32);
                      reimburseAndRewardOracles(uint32(initialGas), r.observers);
                    }
                    /*
                     * v2 Aggregator interface
                     */
                    /**
                     * @notice median from the most recent report
                     */
                    function latestAnswer()
                      public
                      override
                      view
                      virtual
                      returns (int256)
                    {
                      return s_transmissions[s_hotVars.latestAggregatorRoundId].answer;
                    }
                    /**
                     * @notice timestamp of block in which last report was transmitted
                     */
                    function latestTimestamp()
                      public
                      override
                      view
                      virtual
                      returns (uint256)
                    {
                      return s_transmissions[s_hotVars.latestAggregatorRoundId].timestamp;
                    }
                    /**
                     * @notice Aggregator round (NOT OCR round) in which last report was transmitted
                     */
                    function latestRound()
                      public
                      override
                      view
                      virtual
                      returns (uint256)
                    {
                      return s_hotVars.latestAggregatorRoundId;
                    }
                    /**
                     * @notice median of report from given aggregator round (NOT OCR round)
                     * @param _roundId the aggregator round of the target report
                     */
                    function getAnswer(uint256 _roundId)
                      public
                      override
                      view
                      virtual
                      returns (int256)
                    {
                      if (_roundId > 0xFFFFFFFF) { return 0; }
                      return s_transmissions[uint32(_roundId)].answer;
                    }
                    /**
                     * @notice timestamp of block in which report from given aggregator round was transmitted
                     * @param _roundId aggregator round (NOT OCR round) of target report
                     */
                    function getTimestamp(uint256 _roundId)
                      public
                      override
                      view
                      virtual
                      returns (uint256)
                    {
                      if (_roundId > 0xFFFFFFFF) { return 0; }
                      return s_transmissions[uint32(_roundId)].timestamp;
                    }
                    /*
                     * v3 Aggregator interface
                     */
                    string constant private V3_NO_DATA_ERROR = "No data present";
                    /**
                     * @return answers are stored in fixed-point format, with this many digits of precision
                     */
                    uint8 immutable public override decimals;
                    /**
                     * @notice aggregator contract version
                     */
                    uint256 constant public override version = 4;
                    string internal s_description;
                    /**
                     * @notice human-readable description of observable this contract is reporting on
                     */
                    function description()
                      public
                      override
                      view
                      virtual
                      returns (string memory)
                    {
                      return s_description;
                    }
                    /**
                     * @notice details for the given aggregator round
                     * @param _roundId target aggregator round (NOT OCR round). Must fit in uint32
                     * @return roundId _roundId
                     * @return answer median of report from given _roundId
                     * @return startedAt timestamp of block in which report from given _roundId was transmitted
                     * @return updatedAt timestamp of block in which report from given _roundId was transmitted
                     * @return answeredInRound _roundId
                     */
                    function getRoundData(uint80 _roundId)
                      public
                      override
                      view
                      virtual
                      returns (
                        uint80 roundId,
                        int256 answer,
                        uint256 startedAt,
                        uint256 updatedAt,
                        uint80 answeredInRound
                      )
                    {
                      require(_roundId <= 0xFFFFFFFF, V3_NO_DATA_ERROR);
                      Transmission memory transmission = s_transmissions[uint32(_roundId)];
                      return (
                        _roundId,
                        transmission.answer,
                        transmission.timestamp,
                        transmission.timestamp,
                        _roundId
                      );
                    }
                    /**
                     * @notice aggregator details for the most recently transmitted report
                     * @return roundId aggregator round of latest report (NOT OCR round)
                     * @return answer median of latest report
                     * @return startedAt timestamp of block containing latest report
                     * @return updatedAt timestamp of block containing latest report
                     * @return answeredInRound aggregator round of latest report
                     */
                    function latestRoundData()
                      public
                      override
                      view
                      virtual
                      returns (
                        uint80 roundId,
                        int256 answer,
                        uint256 startedAt,
                        uint256 updatedAt,
                        uint80 answeredInRound
                      )
                    {
                      roundId = s_hotVars.latestAggregatorRoundId;
                      // Skipped for compatability with existing FluxAggregator in which latestRoundData never reverts.
                      // require(roundId != 0, V3_NO_DATA_ERROR);
                      Transmission memory transmission = s_transmissions[uint32(roundId)];
                      return (
                        roundId,
                        transmission.answer,
                        transmission.timestamp,
                        transmission.timestamp,
                        roundId
                      );
                    }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.7.1;
                  import "./SimpleWriteAccessController.sol";
                  /**
                   * @title SimpleReadAccessController
                   * @notice Gives access to:
                   * - any externally owned account (note that offchain actors can always read
                   * any contract storage regardless of onchain access control measures, so this
                   * does not weaken the access control while improving usability)
                   * - accounts explicitly added to an access list
                   * @dev SimpleReadAccessController is not suitable for access controlling writes
                   * since it grants any externally owned account access! See
                   * SimpleWriteAccessController for that.
                   */
                  contract SimpleReadAccessController is SimpleWriteAccessController {
                    /**
                     * @notice Returns the access of an address
                     * @param _user The address to query
                     */
                    function hasAccess(
                      address _user,
                      bytes memory _calldata
                    )
                      public
                      view
                      virtual
                      override
                      returns (bool)
                    {
                      return super.hasAccess(_user, _calldata) || _user == tx.origin;
                    }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.7.0;
                  interface AccessControllerInterface {
                    function hasAccess(address user, bytes calldata data) external view returns (bool);
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.7.0;
                  import "./AggregatorInterface.sol";
                  import "./AggregatorV3Interface.sol";
                  interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface
                  {
                  }// SPDX-License-Identifier: MIT
                  pragma solidity ^0.7.0;
                  interface AggregatorValidatorInterface {
                    function validate(
                      uint256 previousRoundId,
                      int256 previousAnswer,
                      uint256 currentRoundId,
                      int256 currentAnswer
                    ) external returns (bool);
                  }// SPDX-License-Identifier: MIT
                  pragma solidity ^0.7.1;
                  interface LinkTokenInterface {
                    function allowance(address owner, address spender) external view returns (uint256 remaining);
                    function approve(address spender, uint256 value) external returns (bool success);
                    function balanceOf(address owner) external view returns (uint256 balance);
                    function decimals() external view returns (uint8 decimalPlaces);
                    function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);
                    function increaseApproval(address spender, uint256 subtractedValue) external;
                    function name() external view returns (string memory tokenName);
                    function symbol() external view returns (string memory tokenSymbol);
                    function totalSupply() external view returns (uint256 totalTokensIssued);
                    function transfer(address to, uint256 value) external returns (bool success);
                    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool success);
                    function transferFrom(address from, address to, uint256 value) external returns (bool success);
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.7.0;
                  /**
                   * @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() {
                      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");
                      _;
                    }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.7.0;
                  import "./AccessControllerInterface.sol";
                  import "./LinkTokenInterface.sol";
                  import "./Owned.sol";
                  /**
                   * @notice tracks administration of oracle-reward and gas-reimbursement parameters.
                   * @dev
                   * If you read or change this, be sure to read or adjust the comments. They
                   * track the units of the values under consideration, and are crucial to
                   * the readability of the operations it specifies.
                   * @notice
                   * Trust Model:
                   * Nothing in this contract prevents a billing admin from setting insane
                   * values for the billing parameters in setBilling. Oracles
                   * participating in this contract should regularly check that the
                   * parameters make sense. Similarly, the outstanding obligations of this
                   * contract to the oracles can exceed the funds held by the contract.
                   * Oracles participating in this contract should regularly check that it
                   * holds sufficient funds and stop interacting with it if funding runs
                   * out.
                   * This still leaves oracles with some risk due to TOCTOU issues.
                   * However, since the sums involved are pretty small (Ethereum
                   * transactions aren't that expensive in the end) and an oracle would
                   * likely stop participating in a contract it repeatedly lost money on,
                   * this risk is deemed acceptable. Oracles should also regularly
                   * withdraw any funds in the contract to prevent issues where the
                   * contract becomes underfunded at a later time, and different oracles
                   * are competing for the left-over funds.
                   * Finally, note that any change to the set of oracles or to the billing
                   * parameters will trigger payout of all oracles first (using the old
                   * parameters), a billing admin cannot take away funds that are already
                   * marked for payment.
                  */
                  contract OffchainAggregatorBilling is Owned {
                    // Maximum number of oracles the offchain reporting protocol is designed for
                    uint256 constant internal maxNumOracles = 31;
                    // Parameters for oracle payments
                    struct Billing {
                      // Highest compensated gas price, in ETH-gwei uints
                      uint32 maximumGasPrice;
                      // If gas price is less (in ETH-gwei units), transmitter gets half the savings
                      uint32 reasonableGasPrice;
                      // Pay transmitter back this much LINK per unit eth spent on gas
                      // (1e-6LINK/ETH units)
                      uint32 microLinkPerEth;
                      // Fixed LINK reward for each observer, in LINK-gwei units
                      uint32 linkGweiPerObservation;
                      // Fixed reward for transmitter, in linkGweiPerObservation units
                      uint32 linkGweiPerTransmission;
                    }
                    Billing internal s_billing;
                    /**
                    * @return LINK token contract used for billing
                    */
                    LinkTokenInterface immutable public LINK;
                    AccessControllerInterface internal s_billingAccessController;
                    // ith element is number of observation rewards due to ith process, plus one.
                    // This is expected to saturate after an oracle has submitted 65,535
                    // observations, or about 65535/(3*24*20) = 45 days, given a transmission
                    // every 3 minutes.
                    //
                    // This is always one greater than the actual value, so that when the value is
                    // reset to zero, we don't end up with a zero value in storage (which would
                    // result in a higher gas cost, the next time the value is incremented.)
                    // Calculations using this variable need to take that offset into account.
                    uint16[maxNumOracles] internal s_oracleObservationsCounts;
                    // Addresses at which oracles want to receive payments, by transmitter address
                    mapping (address /* transmitter */ => address /* payment address */)
                      internal
                      s_payees;
                    // Payee addresses which must be approved by the owner
                    mapping (address /* transmitter */ => address /* payment address */)
                      internal
                      s_proposedPayees;
                    // LINK-wei-denominated reimbursements for gas used by transmitters.
                    //
                    // This is always one greater than the actual value, so that when the value is
                    // reset to zero, we don't end up with a zero value in storage (which would
                    // result in a higher gas cost, the next time the value is incremented.)
                    // Calculations using this variable need to take that offset into account.
                    //
                    // Argument for overflow safety:
                    // We have the following maximum intermediate values:
                    // - 2**40 additions to this variable (epochAndRound is a uint40)
                    // - 2**32 gas price in ethgwei/gas
                    // - 1e9 ethwei/ethgwei
                    // - 2**32 gas since the block gas limit is at ~20 million
                    // - 2**32 (microlink/eth)
                    // And we have 2**40 * 2**32 * 1e9 * 2**32 * 2**32 < 2**166
                    // (we also divide in some places, but that only makes the value smaller)
                    // We can thus safely use uint256 intermediate values for the computation
                    // updating this variable.
                    uint256[maxNumOracles] internal s_gasReimbursementsLinkWei;
                    // Used for s_oracles[a].role, where a is an address, to track the purpose
                    // of the address, or to indicate that the address is unset.
                    enum Role {
                      // No oracle role has been set for address a
                      Unset,
                      // Signing address for the s_oracles[a].index'th oracle. I.e., report
                      // signatures from this oracle should ecrecover back to address a.
                      Signer,
                      // Transmission address for the s_oracles[a].index'th oracle. I.e., if a
                      // report is received by OffchainAggregator.transmit in which msg.sender is
                      // a, it is attributed to the s_oracles[a].index'th oracle.
                      Transmitter
                    }
                    struct Oracle {
                      uint8 index; // Index of oracle in s_signers/s_transmitters
                      Role role;   // Role of the address which mapped to this struct
                    }
                    mapping (address /* signer OR transmitter address */ => Oracle)
                      internal s_oracles;
                    // s_signers contains the signing address of each oracle
                    address[] internal s_signers;
                    // s_transmitters contains the transmission address of each oracle,
                    // i.e. the address the oracle actually sends transactions to the contract from
                    address[] internal s_transmitters;
                    uint256 constant private  maxUint16 = (1 << 16) - 1;
                    uint256 constant internal maxUint128 = (1 << 128) - 1;
                    constructor(
                      uint32 _maximumGasPrice,
                      uint32 _reasonableGasPrice,
                      uint32 _microLinkPerEth,
                      uint32 _linkGweiPerObservation,
                      uint32 _linkGweiPerTransmission,
                      address _link,
                      AccessControllerInterface _billingAccessController
                    )
                    {
                      setBillingInternal(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
                        _linkGweiPerObservation, _linkGweiPerTransmission);
                      setBillingAccessControllerInternal(_billingAccessController);
                      LINK = LinkTokenInterface(_link);
                      uint16[maxNumOracles] memory counts; // See s_oracleObservationsCounts docstring
                      uint256[maxNumOracles] memory gas; // see s_gasReimbursementsLinkWei docstring
                      for (uint8 i = 0; i < maxNumOracles; i++) {
                        counts[i] = 1;
                        gas[i] = 1;
                      }
                      s_oracleObservationsCounts = counts;
                      s_gasReimbursementsLinkWei = gas;
                    }
                    /**
                     * @notice emitted when billing parameters are set
                     * @param maximumGasPrice highest gas price for which transmitter will be compensated
                     * @param reasonableGasPrice transmitter will receive reward for gas prices under this value
                     * @param microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
                     * @param linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
                     * @param linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
                     */
                    event BillingSet(
                      uint32 maximumGasPrice,
                      uint32 reasonableGasPrice,
                      uint32 microLinkPerEth,
                      uint32 linkGweiPerObservation,
                      uint32 linkGweiPerTransmission
                    );
                    function setBillingInternal(
                      uint32 _maximumGasPrice,
                      uint32 _reasonableGasPrice,
                      uint32 _microLinkPerEth,
                      uint32 _linkGweiPerObservation,
                      uint32 _linkGweiPerTransmission
                    )
                      internal
                    {
                      s_billing = Billing(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
                        _linkGweiPerObservation, _linkGweiPerTransmission);
                      emit BillingSet(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
                        _linkGweiPerObservation, _linkGweiPerTransmission);
                    }
                    /**
                     * @notice sets billing parameters
                     * @param _maximumGasPrice highest gas price for which transmitter will be compensated
                     * @param _reasonableGasPrice transmitter will receive reward for gas prices under this value
                     * @param _microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
                     * @param _linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
                     * @param _linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
                     * @dev access control provided by billingAccessController
                     */
                    function setBilling(
                      uint32 _maximumGasPrice,
                      uint32 _reasonableGasPrice,
                      uint32 _microLinkPerEth,
                      uint32 _linkGweiPerObservation,
                      uint32 _linkGweiPerTransmission
                    )
                      external
                    {
                      AccessControllerInterface access = s_billingAccessController;
                      require(msg.sender == owner || access.hasAccess(msg.sender, msg.data),
                        "Only owner&billingAdmin can call");
                      payOracles();
                      setBillingInternal(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
                        _linkGweiPerObservation, _linkGweiPerTransmission);
                    }
                    /**
                     * @notice gets billing parameters
                     * @param maximumGasPrice highest gas price for which transmitter will be compensated
                     * @param reasonableGasPrice transmitter will receive reward for gas prices under this value
                     * @param microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
                     * @param linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
                     * @param linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
                     */
                    function getBilling()
                      external
                      view
                      returns (
                        uint32 maximumGasPrice,
                        uint32 reasonableGasPrice,
                        uint32 microLinkPerEth,
                        uint32 linkGweiPerObservation,
                        uint32 linkGweiPerTransmission
                      )
                    {
                      Billing memory billing = s_billing;
                      return (
                        billing.maximumGasPrice,
                        billing.reasonableGasPrice,
                        billing.microLinkPerEth,
                        billing.linkGweiPerObservation,
                        billing.linkGweiPerTransmission
                      );
                    }
                    /**
                     * @notice emitted when a new access-control contract is set
                     * @param old the address prior to the current setting
                     * @param current the address of the new access-control contract
                     */
                    event BillingAccessControllerSet(AccessControllerInterface old, AccessControllerInterface current);
                    function setBillingAccessControllerInternal(AccessControllerInterface _billingAccessController)
                      internal
                    {
                      AccessControllerInterface oldController = s_billingAccessController;
                      if (_billingAccessController != oldController) {
                        s_billingAccessController = _billingAccessController;
                        emit BillingAccessControllerSet(
                          oldController,
                          _billingAccessController
                        );
                      }
                    }
                    /**
                     * @notice sets billingAccessController
                     * @param _billingAccessController new billingAccessController contract address
                     * @dev only owner can call this
                     */
                    function setBillingAccessController(AccessControllerInterface _billingAccessController)
                      external
                      onlyOwner
                    {
                      setBillingAccessControllerInternal(_billingAccessController);
                    }
                    /**
                     * @notice gets billingAccessController
                     * @return address of billingAccessController contract
                     */
                    function billingAccessController()
                      external
                      view
                      returns (AccessControllerInterface)
                    {
                      return s_billingAccessController;
                    }
                    /**
                     * @notice withdraws an oracle's payment from the contract
                     * @param _transmitter the transmitter address of the oracle
                     * @dev must be called by oracle's payee address
                     */
                    function withdrawPayment(address _transmitter)
                      external
                    {
                      require(msg.sender == s_payees[_transmitter], "Only payee can withdraw");
                      payOracle(_transmitter);
                    }
                    /**
                     * @notice query an oracle's payment amount
                     * @param _transmitter the transmitter address of the oracle
                     */
                    function owedPayment(address _transmitter)
                      public
                      view
                      returns (uint256)
                    {
                      Oracle memory oracle = s_oracles[_transmitter];
                      if (oracle.role == Role.Unset) { return 0; }
                      Billing memory billing = s_billing;
                      uint256 linkWeiAmount =
                        uint256(s_oracleObservationsCounts[oracle.index] - 1) *
                        uint256(billing.linkGweiPerObservation) *
                        (1 gwei);
                      linkWeiAmount += s_gasReimbursementsLinkWei[oracle.index] - 1;
                      return linkWeiAmount;
                    }
                    /**
                     * @notice emitted when an oracle has been paid LINK
                     * @param transmitter address from which the oracle sends reports to the transmit method
                     * @param payee address to which the payment is sent
                     * @param amount amount of LINK sent
                     */
                    event OraclePaid(address transmitter, address payee, uint256 amount);
                    // payOracle pays out _transmitter's balance to the corresponding payee, and zeros it out
                    function payOracle(address _transmitter)
                      internal
                    {
                      Oracle memory oracle = s_oracles[_transmitter];
                      uint256 linkWeiAmount = owedPayment(_transmitter);
                      if (linkWeiAmount > 0) {
                        address payee = s_payees[_transmitter];
                        // Poses no re-entrancy issues, because LINK.transfer does not yield
                        // control flow.
                        require(LINK.transfer(payee, linkWeiAmount), "insufficient funds");
                        s_oracleObservationsCounts[oracle.index] = 1; // "zero" the counts. see var's docstring
                        s_gasReimbursementsLinkWei[oracle.index] = 1; // "zero" the counts. see var's docstring
                        emit OraclePaid(_transmitter, payee, linkWeiAmount);
                      }
                    }
                    // payOracles pays out all transmitters, and zeros out their balances.
                    //
                    // It's much more gas-efficient to do this as a single operation, to avoid
                    // hitting storage too much.
                    function payOracles()
                      internal
                    {
                      Billing memory billing = s_billing;
                      uint16[maxNumOracles] memory observationsCounts = s_oracleObservationsCounts;
                      uint256[maxNumOracles] memory gasReimbursementsLinkWei =
                        s_gasReimbursementsLinkWei;
                      address[] memory transmitters = s_transmitters;
                      for (uint transmitteridx = 0; transmitteridx < transmitters.length; transmitteridx++) {
                        uint256 reimbursementAmountLinkWei = gasReimbursementsLinkWei[transmitteridx] - 1;
                        uint256 obsCount = observationsCounts[transmitteridx] - 1;
                        uint256 linkWeiAmount =
                          obsCount * uint256(billing.linkGweiPerObservation) * (1 gwei) + reimbursementAmountLinkWei;
                        if (linkWeiAmount > 0) {
                            address payee = s_payees[transmitters[transmitteridx]];
                            // Poses no re-entrancy issues, because LINK.transfer does not yield
                            // control flow.
                            require(LINK.transfer(payee, linkWeiAmount), "insufficient funds");
                            observationsCounts[transmitteridx] = 1;       // "zero" the counts.
                            gasReimbursementsLinkWei[transmitteridx] = 1; // "zero" the counts.
                            emit OraclePaid(transmitters[transmitteridx], payee, linkWeiAmount);
                          }
                      }
                      // "Zero" the accounting storage variables
                      s_oracleObservationsCounts = observationsCounts;
                      s_gasReimbursementsLinkWei = gasReimbursementsLinkWei;
                    }
                    function oracleRewards(
                      bytes memory observers,
                      uint16[maxNumOracles] memory observations
                    )
                      internal
                      pure
                      returns (uint16[maxNumOracles] memory)
                    {
                      // reward each observer-participant with the observer reward
                      for (uint obsIdx = 0; obsIdx < observers.length; obsIdx++) {
                        uint8 observer = uint8(observers[obsIdx]);
                        observations[observer] = saturatingAddUint16(observations[observer], 1);
                      }
                      return observations;
                    }
                    // This value needs to change if maxNumOracles is increased, or the accounting
                    // calculations at the bottom of reimburseAndRewardOracles change.
                    //
                    // To recalculate it, run the profiler as described in
                    // ../../profile/README.md, and add up the gas-usage values reported for the
                    // lines in reimburseAndRewardOracles following the "gasLeft = gasleft()"
                    // line. E.g., you will see output like this:
                    //
                    //      7        uint256 gasLeft = gasleft();
                    //     29        uint256 gasCostEthWei = transmitterGasCostEthWei(
                    //      9          uint256(initialGas),
                    //      3          gasPrice,
                    //      3          callDataGasCost,
                    //      3          gasLeft
                    //      .
                    //      .
                    //      .
                    //     59        uint256 gasCostLinkWei = (gasCostEthWei * billing.microLinkPerEth)/ 1e6;
                    //      .
                    //      .
                    //      .
                    //   5047        s_gasReimbursementsLinkWei[txOracle.index] =
                    //    856          s_gasReimbursementsLinkWei[txOracle.index] + gasCostLinkWei +
                    //     26          uint256(billing.linkGweiPerTransmission) * (1 gwei);
                    //
                    // If those were the only lines to be accounted for, you would add up
                    // 29+9+3+3+3+59+5047+856+26=6035.
                    uint256 internal constant accountingGasCost = 6035;
                    // Uncomment the following declaration to compute the remaining gas cost after
                    // above gasleft(). (This must exist in a base class to OffchainAggregator, so
                    // it can't go in TestOffchainAggregator.)
                    //
                    // uint256 public gasUsedInAccounting;
                    // Gas price at which the transmitter should be reimbursed, in ETH-gwei/gas
                    function impliedGasPrice(
                      uint256 txGasPrice,         // ETH-gwei/gas units
                      uint256 reasonableGasPrice, // ETH-gwei/gas units
                      uint256 maximumGasPrice     // ETH-gwei/gas units
                    )
                      internal
                      pure
                      returns (uint256)
                    {
                      // Reward the transmitter for choosing an efficient gas price: if they manage
                      // to come in lower than considered reasonable, give them half the savings.
                      //
                      // The following calculations are all in units of gwei/gas, i.e. 1e-9ETH/gas
                      uint256 gasPrice = txGasPrice;
                      if (txGasPrice < reasonableGasPrice) {
                        // Give transmitter half the savings for coming in under the reasonable gas price
                        gasPrice += (reasonableGasPrice - txGasPrice) / 2;
                      }
                      // Don't reimburse a gas price higher than maximumGasPrice
                      return min(gasPrice, maximumGasPrice);
                    }
                    // gas reimbursement due the transmitter, in ETH-wei
                    //
                    // If this function is changed, accountingGasCost needs to change, too. See
                    // its docstring
                    function transmitterGasCostEthWei(
                      uint256 initialGas,
                      uint256 gasPrice, // ETH-gwei/gas units
                      uint256 callDataCost, // gas units
                      uint256 gasLeft
                    )
                      internal
                      pure
                      returns (uint128 gasCostEthWei)
                    {
                      require(initialGas >= gasLeft, "gasLeft cannot exceed initialGas");
                      uint256 gasUsed = // gas units
                        initialGas - gasLeft + // observed gas usage
                        callDataCost + accountingGasCost; // estimated gas usage
                      // gasUsed is in gas units, gasPrice is in ETH-gwei/gas units; convert to ETH-wei
                      uint256 fullGasCostEthWei = gasUsed * gasPrice * (1 gwei);
                      assert(fullGasCostEthWei < maxUint128); // the entire ETH supply fits in a uint128...
                      return uint128(fullGasCostEthWei);
                    }
                    /**
                     * @notice withdraw any available funds left in the contract, up to _amount, after accounting for the funds due to participants in past reports
                     * @param _recipient address to send funds to
                     * @param _amount maximum amount to withdraw, denominated in LINK-wei.
                     * @dev access control provided by billingAccessController
                     */
                    function withdrawFunds(address _recipient, uint256 _amount)
                      external
                    {
                      require(msg.sender == owner || s_billingAccessController.hasAccess(msg.sender, msg.data),
                        "Only owner&billingAdmin can call");
                      uint256 linkDue = totalLINKDue();
                      uint256 linkBalance = LINK.balanceOf(address(this));
                      require(linkBalance >= linkDue, "insufficient balance");
                      require(LINK.transfer(_recipient, min(linkBalance - linkDue, _amount)), "insufficient funds");
                    }
                    // Total LINK due to participants in past reports.
                    function totalLINKDue()
                      internal
                      view
                      returns (uint256 linkDue)
                    {
                      // Argument for overflow safety: We do all computations in
                      // uint256s. The inputs to linkDue are:
                      // - the <= 31 observation rewards each of which has less than
                      //   64 bits (32 bits for billing.linkGweiPerObservation, 32 bits
                      //   for wei/gwei conversion). Hence 69 bits are sufficient for this part.
                      // - the <= 31 gas reimbursements, each of which consists of at most 166
                      //   bits (see s_gasReimbursementsLinkWei docstring). Hence 171 bits are
                      //   sufficient for this part
                      // In total, 172 bits are enough.
                      uint16[maxNumOracles] memory observationCounts = s_oracleObservationsCounts;
                      for (uint i = 0; i < maxNumOracles; i++) {
                        linkDue += observationCounts[i] - 1; // Stored value is one greater than actual value
                      }
                      Billing memory billing = s_billing;
                      // Convert linkGweiPerObservation to uint256, or this overflows!
                      linkDue *= uint256(billing.linkGweiPerObservation) * (1 gwei);
                      address[] memory transmitters = s_transmitters;
                      uint256[maxNumOracles] memory gasReimbursementsLinkWei =
                        s_gasReimbursementsLinkWei;
                      for (uint i = 0; i < transmitters.length; i++) {
                        linkDue += uint256(gasReimbursementsLinkWei[i]-1); // Stored value is one greater than actual value
                      }
                    }
                    /**
                     * @notice allows oracles to check that sufficient LINK balance is available
                     * @return availableBalance LINK available on this contract, after accounting for outstanding obligations. can become negative
                     */
                    function linkAvailableForPayment()
                      external
                      view
                      returns (int256 availableBalance)
                    {
                      // there are at most one billion LINK, so this cast is safe
                      int256 balance = int256(LINK.balanceOf(address(this)));
                      // according to the argument in the definition of totalLINKDue,
                      // totalLINKDue is never greater than 2**172, so this cast is safe
                      int256 due = int256(totalLINKDue());
                      // safe from overflow according to above sizes
                      return int256(balance) - int256(due);
                    }
                    /**
                     * @notice number of observations oracle is due to be reimbursed for
                     * @param _signerOrTransmitter address used by oracle for signing or transmitting reports
                     */
                    function oracleObservationCount(address _signerOrTransmitter)
                      external
                      view
                      returns (uint16)
                    {
                      Oracle memory oracle = s_oracles[_signerOrTransmitter];
                      if (oracle.role == Role.Unset) { return 0; }
                      return s_oracleObservationsCounts[oracle.index] - 1;
                    }
                    function reimburseAndRewardOracles(
                      uint32 initialGas,
                      bytes memory observers
                    )
                      internal
                    {
                      Oracle memory txOracle = s_oracles[msg.sender];
                      Billing memory billing = s_billing;
                      // Reward oracles for providing observations. Oracles are not rewarded
                      // for providing signatures, because signing is essentially free.
                      s_oracleObservationsCounts =
                        oracleRewards(observers, s_oracleObservationsCounts);
                      // Reimburse transmitter of the report for gas usage
                      require(txOracle.role == Role.Transmitter,
                        "sent by undesignated transmitter"
                      );
                      uint256 gasPrice = impliedGasPrice(
                        tx.gasprice / (1 gwei), // convert to ETH-gwei units
                        billing.reasonableGasPrice,
                        billing.maximumGasPrice
                      );
                      // The following is only an upper bound, as it ignores the cheaper cost for
                      // 0 bytes. Safe from overflow, because calldata just isn't that long.
                      uint256 callDataGasCost = 16 * msg.data.length;
                      // If any changes are made to subsequent calculations, accountingGasCost
                      // needs to change, too.
                      uint256 gasLeft = gasleft();
                      uint256 gasCostEthWei = transmitterGasCostEthWei(
                        uint256(initialGas),
                        gasPrice,
                        callDataGasCost,
                        gasLeft
                      );
                      // microLinkPerEth is 1e-6LINK/ETH units, gasCostEthWei is 1e-18ETH units
                      // (ETH-wei), product is 1e-24LINK-wei units, dividing by 1e6 gives
                      // 1e-18LINK units, i.e. LINK-wei units
                      // Safe from over/underflow, since all components are non-negative,
                      // gasCostEthWei will always fit into uint128 and microLinkPerEth is a
                      // uint32 (128+32 < 256!).
                      uint256 gasCostLinkWei = (gasCostEthWei * billing.microLinkPerEth)/ 1e6;
                      // Safe from overflow, because gasCostLinkWei < 2**160 and
                      // billing.linkGweiPerTransmission * (1 gwei) < 2**64 and we increment
                      // s_gasReimbursementsLinkWei[txOracle.index] at most 2**40 times.
                      s_gasReimbursementsLinkWei[txOracle.index] =
                        s_gasReimbursementsLinkWei[txOracle.index] + gasCostLinkWei +
                        uint256(billing.linkGweiPerTransmission) * (1 gwei); // convert from linkGwei to linkWei
                      // Uncomment next line to compute the remaining gas cost after above gasleft().
                      // See OffchainAggregatorBilling.accountingGasCost docstring for more information.
                      //
                      // gasUsedInAccounting = gasLeft - gasleft();
                    }
                    /*
                     * Payee management
                     */
                    /**
                     * @notice emitted when a transfer of an oracle's payee address has been initiated
                     * @param transmitter address from which the oracle sends reports to the transmit method
                     * @param current the payeee address for the oracle, prior to this setting
                     * @param proposed the proposed new payee address for the oracle
                     */
                    event PayeeshipTransferRequested(
                      address indexed transmitter,
                      address indexed current,
                      address indexed proposed
                    );
                    /**
                     * @notice emitted when a transfer of an oracle's payee address has been completed
                     * @param transmitter address from which the oracle sends reports to the transmit method
                     * @param current the payeee address for the oracle, prior to this setting
                     */
                    event PayeeshipTransferred(
                      address indexed transmitter,
                      address indexed previous,
                      address indexed current
                    );
                    /**
                     * @notice sets the payees for transmitting addresses
                     * @param _transmitters addresses oracles use to transmit the reports
                     * @param _payees addresses of payees corresponding to list of transmitters
                     * @dev must be called by owner
                     * @dev cannot be used to change payee addresses, only to initially populate them
                     */
                    function setPayees(
                      address[] calldata _transmitters,
                      address[] calldata _payees
                    )
                      external
                      onlyOwner()
                    {
                      require(_transmitters.length == _payees.length, "transmitters.size != payees.size");
                      for (uint i = 0; i < _transmitters.length; i++) {
                        address transmitter = _transmitters[i];
                        address payee = _payees[i];
                        address currentPayee = s_payees[transmitter];
                        bool zeroedOut = currentPayee == address(0);
                        require(zeroedOut || currentPayee == payee, "payee already set");
                        s_payees[transmitter] = payee;
                        if (currentPayee != payee) {
                          emit PayeeshipTransferred(transmitter, currentPayee, payee);
                        }
                      }
                    }
                    /**
                     * @notice first step of payeeship transfer (safe transfer pattern)
                     * @param _transmitter transmitter address of oracle whose payee is changing
                     * @param _proposed new payee address
                     * @dev can only be called by payee address
                     */
                    function transferPayeeship(
                      address _transmitter,
                      address _proposed
                    )
                      external
                    {
                        require(msg.sender == s_payees[_transmitter], "only current payee can update");
                        require(msg.sender != _proposed, "cannot transfer to self");
                        address previousProposed = s_proposedPayees[_transmitter];
                        s_proposedPayees[_transmitter] = _proposed;
                        if (previousProposed != _proposed) {
                          emit PayeeshipTransferRequested(_transmitter, msg.sender, _proposed);
                        }
                    }
                    /**
                     * @notice second step of payeeship transfer (safe transfer pattern)
                     * @param _transmitter transmitter address of oracle whose payee is changing
                     * @dev can only be called by proposed new payee address
                     */
                    function acceptPayeeship(
                      address _transmitter
                    )
                      external
                    {
                      require(msg.sender == s_proposedPayees[_transmitter], "only proposed payees can accept");
                      address currentPayee = s_payees[_transmitter];
                      s_payees[_transmitter] = msg.sender;
                      s_proposedPayees[_transmitter] = address(0);
                      emit PayeeshipTransferred(_transmitter, currentPayee, msg.sender);
                    }
                    /*
                     * Helper functions
                     */
                    function saturatingAddUint16(uint16 _x, uint16 _y)
                      internal
                      pure
                      returns (uint16)
                    {
                      return uint16(min(uint256(_x)+uint256(_y), maxUint16));
                    }
                    function min(uint256 a, uint256 b)
                      internal
                      pure
                      returns (uint256)
                    {
                      if (a < b) { return a; }
                      return b;
                    }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.7.0;
                  abstract contract TypeAndVersionInterface{
                    function typeAndVersion()
                      external
                      pure
                      virtual
                      returns (string memory);
                  }// SPDX-License-Identifier: MIT
                  pragma solidity ^0.7.0;
                  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);
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.7.0;
                  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
                      );
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.7.0;
                  import "./Owned.sol";
                  import "./AccessControllerInterface.sol";
                  /**
                   * @title SimpleWriteAccessController
                   * @notice Gives access to accounts explicitly added to an access list by the
                   * controller's owner.
                   * @dev does not make any special permissions for externally, see
                   * SimpleReadAccessController for that.
                   */
                  contract SimpleWriteAccessController is AccessControllerInterface, Owned {
                    bool public checkEnabled;
                    mapping(address => bool) internal accessList;
                    event AddedAccess(address user);
                    event RemovedAccess(address user);
                    event CheckAccessEnabled();
                    event CheckAccessDisabled();
                    constructor()
                    {
                      checkEnabled = true;
                    }
                    /**
                     * @notice Returns the access of an address
                     * @param _user The address to query
                     */
                    function hasAccess(
                      address _user,
                      bytes memory
                    )
                      public
                      view
                      virtual
                      override
                      returns (bool)
                    {
                      return accessList[_user] || !checkEnabled;
                    }
                    /**
                     * @notice Adds an address to the access list
                     * @param _user The address to add
                     */
                    function addAccess(address _user) external onlyOwner() {
                      addAccessInternal(_user);
                    }
                    function addAccessInternal(address _user) internal {
                      if (!accessList[_user]) {
                        accessList[_user] = true;
                        emit AddedAccess(_user);
                      }
                    }
                    /**
                     * @notice Removes an address from the access list
                     * @param _user The address to remove
                     */
                    function removeAccess(address _user)
                      external
                      onlyOwner()
                    {
                      if (accessList[_user]) {
                        accessList[_user] = false;
                        emit RemovedAccess(_user);
                      }
                    }
                    /**
                     * @notice makes the access check enforced
                     */
                    function enableAccessCheck()
                      external
                      onlyOwner()
                    {
                      if (!checkEnabled) {
                        checkEnabled = true;
                        emit CheckAccessEnabled();
                      }
                    }
                    /**
                     * @notice makes the access check unenforced
                     */
                    function disableAccessCheck()
                      external
                      onlyOwner()
                    {
                      if (checkEnabled) {
                        checkEnabled = false;
                        emit CheckAccessDisabled();
                      }
                    }
                    /**
                     * @dev reverts if the caller does not have access
                     */
                    modifier checkAccess() {
                      require(hasAccess(msg.sender, msg.data), "No access");
                      _;
                    }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.7.0;
                  import "./AccessControlledOffchainAggregator.sol";
                  import "./AccessControlTestHelper.sol";
                  contract TestOffchainAggregator is AccessControlledOffchainAggregator {
                    function testDecodeReport(
                      bytes memory report
                    ) public pure returns (bytes32, bytes32, int192[] memory)
                    {
                      return decodeReport(report);
                    }
                    constructor(
                      uint32 _maximumGasPrice,
                      uint32 _reasonableGasPrice,
                      uint32 _microLinkPerEth,
                      uint32 _linkGweiPerObservation,
                      uint32 _linkGweiPerTransmission,
                      address _link,
                      int192 _minAnswer, int192 _maxAnswer,
                      AccessControllerInterface _billingAccessController,
                      AccessControllerInterface _requesterAdminAccessController
                    )
                      AccessControlledOffchainAggregator(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
                        _linkGweiPerObservation, _linkGweiPerTransmission, _link,
                        _minAnswer, _maxAnswer, _billingAccessController, _requesterAdminAccessController, 0, "TEST"
                      )
                    {}
                    function testPayee(
                      address _transmitter
                    )
                      external
                      view
                      returns (address)
                    {
                      return s_payees[_transmitter];
                    }
                    function getConfigDigest() public view returns (bytes16) {
                      return s_hotVars.latestConfigDigest;
                    }
                    function testSaturatingAddUint16(uint16 _x, uint16 _y)
                      external pure returns (uint16)
                    {
                      return saturatingAddUint16(_x, _y);
                    }
                    function testImpliedGasPrice(uint256 txGasPrice, uint256 reasonableGasPrice,
                      uint256 maximumGasPrice
                    ) external pure returns (uint256) {
                      return impliedGasPrice(txGasPrice, reasonableGasPrice, maximumGasPrice);
                    }
                    function testTransmitterGasCostEthWei(uint256 initialGas, uint256 gasPrice,
                      uint256 callDataCost, uint256 gasLeft
                    ) external pure returns (uint128) {
                      return transmitterGasCostEthWei(
                        initialGas, gasPrice, callDataCost, gasLeft
                      );
                    }
                    function testSetOracleObservationCount(address _oracle, uint16 _amount) external {
                      s_oracleObservationsCounts[s_oracles[_oracle].index] = _amount + 1;
                    }
                    function testTotalLinkDue()
                      external view returns (uint256 linkDue)
                    {
                      return totalLINKDue();
                    }
                    function billingData() external view returns (
                      uint16[maxNumOracles] memory observationsCounts,
                      uint256[maxNumOracles] memory gasReimbursements,
                      uint32 maximumGasPrice,
                      uint32 reasonableGasPrice,
                      uint32 microLinkPerEth,
                      uint32 linkGweiPerObservation,
                      uint32 linkGweiPerTransmission
                    ) {
                      Billing memory b = s_billing;
                      return (s_oracleObservationsCounts, s_gasReimbursementsLinkWei,
                        b.maximumGasPrice, b.reasonableGasPrice, b.microLinkPerEth,
                        b.linkGweiPerObservation, b.linkGweiPerTransmission);
                    }
                    function testSetGasReimbursements(address _transmitterOrSigner, uint256 _amountLinkWei)
                      external
                    {
                      require(s_oracles[_transmitterOrSigner].role != Role.Unset, "address unknown");
                      s_gasReimbursementsLinkWei[s_oracles[_transmitterOrSigner].index] = _amountLinkWei + 1;
                    }
                    function testAccountingGasCost() public pure returns (uint256) {
                      return accountingGasCost;
                    }
                    function testBurnLINK(uint256 amount) public {
                        LINK.transfer(address(1), amount);
                    }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.7.1;
                  import "./AccessControlledOffchainAggregator.sol";
                  contract AccessControlTestHelper {
                    event Dummy(); // Used to silence warning that these methods are pure
                    function readGetRoundData(address _aggregator, uint80 _roundID)
                      external
                    {
                      AccessControlledOffchainAggregator(_aggregator).getRoundData(_roundID);
                      emit Dummy();
                    }
                    function readLatestRoundData(address _aggregator)
                      external
                    {
                      AccessControlledOffchainAggregator(_aggregator).latestRoundData();
                      emit Dummy();
                    }
                    function readLatestAnswer(address _aggregator)
                      external
                    {
                      AccessControlledOffchainAggregator(_aggregator).latestAnswer();
                      emit Dummy();
                    }
                    function readLatestTimestamp(address _aggregator)
                      external
                    {
                      AccessControlledOffchainAggregator(_aggregator).latestTimestamp();
                      emit Dummy();
                    }
                    function readLatestRound(address _aggregator)
                      external
                    {
                      AccessControlledOffchainAggregator(_aggregator).latestRound();
                      emit Dummy();
                    }
                    function readGetAnswer(address _aggregator, uint256 _roundID)
                      external
                    {
                      AccessControlledOffchainAggregator(_aggregator).getAnswer(_roundID);
                      emit Dummy();
                    }
                    function readGetTimestamp(address _aggregator, uint256 _roundID)
                      external
                    {
                      AccessControlledOffchainAggregator(_aggregator).getTimestamp(_roundID);
                      emit Dummy();
                    }
                    function testLatestTransmissionDetails(address _aggregator) external view {
                        OffchainAggregator(_aggregator).latestTransmissionDetails();
                    }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.7.0;
                  import "./OffchainAggregator.sol";
                  // ExposedOffchainAggregator exposes certain internal OffchainAggregator
                  // methods/structures so that golang code can access them, and we get
                  // reliable type checking on their usage
                  contract ExposedOffchainAggregator is OffchainAggregator {
                    constructor()
                      OffchainAggregator(
                        0, 0, 0, 0, 0, address(0), 0, 0, AccessControllerInterface(address(0)), AccessControllerInterface(address(0)), 0, ""
                      )
                      {}
                    function exposedConfigDigestFromConfigData(
                      address _contractAddress,
                      uint64 _configCount,
                      address[] calldata _signers,
                      address[] calldata _transmitters,
                      uint8 _threshold,
                      uint64 _encodedConfigVersion,
                      bytes calldata _encodedConfig
                    ) external pure returns (bytes16) {
                      return configDigestFromConfigData(_contractAddress, _configCount,
                        _signers, _transmitters, _threshold, _encodedConfigVersion,
                        _encodedConfig);
                    }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity ^0.7.0;
                  import "./AggregatorValidatorInterface.sol";
                  contract TestValidator is AggregatorValidatorInterface {
                    uint32 s_minGasUse;
                    uint256 s_latestRoundId;
                    event Validated(
                      uint256 previousRoundId,
                      int256 previousAnswer,
                      uint256 currentRoundId,
                      int256 currentAnswer,
                      uint256 initialGas
                    );
                    function validate(
                      uint256 previousRoundId,
                      int256 previousAnswer,
                      uint256 currentRoundId,
                      int256 currentAnswer
                    ) external override returns (bool) {
                      uint256 initialGas = gasleft();
                      emit Validated(
                        previousRoundId,
                        previousAnswer,
                        currentRoundId,
                        currentAnswer,
                        initialGas
                      );
                      s_latestRoundId = currentRoundId;
                      uint256 minGasUse = s_minGasUse;
                      while (initialGas - gasleft() < minGasUse) {}
                      return true;
                    }
                    function setMinGasUse(uint32 minGasUse) external {
                      s_minGasUse = minGasUse;
                    }
                    function latestRoundId() external view returns (uint256) {
                      return s_latestRoundId;
                    }
                  }