ETH Price: $1,902.01 (-1.09%)

Transaction Decoder

Block:
13424485 at Oct-15-2021 07:25:24 PM +UTC
Transaction Fee:
0.033975743975417824 ETH $64.62
Gas Used:
281,096 Gas / 120.868827644 Gwei

Emitted Events:

97 BaseRegistrarImplementation.Transfer( from=0x00000000...000000000, to=[Receiver] ETHRegistrarController, tokenId=66630243368104181027087566971496236996916937067295560392833879082073134661000 )
98 ENSRegistryWithFallback.NewOwner( node=93CDEB708B7545DC668EB9280176169D1C33CFD8ED6F04690A0BCC88A93FC4AE, label=934F619D3A4BB975433E8ADACB71C97F7B716B0B7DE1795EF8351F35C2FEFD88, owner=[Receiver] ETHRegistrarController )
99 BaseRegistrarImplementation.NameRegistered( id=66630243368104181027087566971496236996916937067295560392833879082073134661000, owner=[Receiver] ETHRegistrarController, expires=1792110684 )
100 ENSRegistryWithFallback.NewResolver( node=6DB653E63074AB279136DDDFC725E8C02DFA4E0F4F4BB054B1B6339872AF6609, resolver=PublicResolver )
101 PublicResolver.AddressChanged( node=6DB653E63074AB279136DDDFC725E8C02DFA4E0F4F4BB054B1B6339872AF6609, coinType=60, newAddress=[Sender] 0x642281af9755ca3576849807fc13f2e3657bd5f7 )
102 PublicResolver.AddrChanged( node=6DB653E63074AB279136DDDFC725E8C02DFA4E0F4F4BB054B1B6339872AF6609, a=[Sender] 0x642281af9755ca3576849807fc13f2e3657bd5f7 )
103 ENSRegistryWithFallback.NewOwner( node=93CDEB708B7545DC668EB9280176169D1C33CFD8ED6F04690A0BCC88A93FC4AE, label=934F619D3A4BB975433E8ADACB71C97F7B716B0B7DE1795EF8351F35C2FEFD88, owner=[Sender] 0x642281af9755ca3576849807fc13f2e3657bd5f7 )
104 BaseRegistrarImplementation.Transfer( from=[Receiver] ETHRegistrarController, to=[Sender] 0x642281af9755ca3576849807fc13f2e3657bd5f7, tokenId=66630243368104181027087566971496236996916937067295560392833879082073134661000 )
105 ETHRegistrarController.NameRegistered( name=jasminetea, label=934F619D3A4BB975433E8ADACB71C97F7B716B0B7DE1795EF8351F35C2FEFD88, owner=[Sender] 0x642281af9755ca3576849807fc13f2e3657bd5f7, cost=6488039438555591, expires=1792110684 )

Account State Difference:

  Address   Before After State Difference Code
0x00000000...A6C7d2e1e
(ENS: Registry with Fallback)
0x283Af0B2...A627EB7F5
(ENS: Old ETH Registrar Controller)
2,806.518212163165895685 Eth2,806.524700202604451276 Eth0.006488039438555591
0x4976fb03...78EBaBa41
(ENS: Public Resolver 2)
0x57f1887a...Af147eA85
0x642281AF...3657BD5F7
0.500352338404455651 Eth
Nonce: 28
0.459888554990482236 Eth
Nonce: 29
0.040463783413973415
(Miner: 0xb7e...707)
19.806909148033375111 Eth19.807345127929375111 Eth0.000435979896

Execution Trace

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

              File 2 of 7: 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 7: 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 4 of 7: PublicResolver
              // 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);
              
              
                  function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external;
                  function setResolver(bytes32 node, address resolver) external;
                  function setOwner(bytes32 node, address owner) external;
                  function setTTL(bytes32 node, uint64 ttl) 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);
              
              }
              
              // File: 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: 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: 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: 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/dnssec-oracle/contracts/BytesUtils.sol
              
              pragma solidity >0.4.23;
              
              library BytesUtils {
                  /*
                  * @dev Returns the keccak-256 hash of a byte range.
                  * @param self The byte string to hash.
                  * @param offset The position to start hashing at.
                  * @param len The number of bytes to hash.
                  * @return The hash of the byte range.
                  */
                  function keccak(bytes memory self, uint offset, uint len) internal pure returns (bytes32 ret) {
                      require(offset + len <= self.length);
                      assembly {
                          ret := keccak256(add(add(self, 32), offset), len)
                      }
                  }
              
              
                  /*
                  * @dev Returns a positive number if `other` comes lexicographically after
                  *      `self`, a negative number if it comes before, or zero if the
                  *      contents of the two bytes are equal.
                  * @param self The first bytes to compare.
                  * @param other The second bytes to compare.
                  * @return The result of the comparison.
                  */
                  function compare(bytes memory self, bytes memory other) internal pure returns (int) {
                      return compare(self, 0, self.length, other, 0, other.length);
                  }
              
                  /*
                  * @dev Returns a positive number if `other` comes lexicographically after
                  *      `self`, a negative number if it comes before, or zero if the
                  *      contents of the two bytes are equal. Comparison is done per-rune,
                  *      on unicode codepoints.
                  * @param self The first bytes to compare.
                  * @param offset The offset of self.
                  * @param len    The length of self.
                  * @param other The second bytes to compare.
                  * @param otheroffset The offset of the other string.
                  * @param otherlen    The length of the other string.
                  * @return The result of the comparison.
                  */
                  function compare(bytes memory self, uint offset, uint len, bytes memory other, uint otheroffset, uint otherlen) internal pure returns (int) {
                      uint shortest = len;
                      if (otherlen < len)
                      shortest = otherlen;
              
                      uint selfptr;
                      uint otherptr;
              
                      assembly {
                          selfptr := add(self, add(offset, 32))
                          otherptr := add(other, add(otheroffset, 32))
                      }
                      for (uint idx = 0; idx < shortest; idx += 32) {
                          uint a;
                          uint b;
                          assembly {
                              a := mload(selfptr)
                              b := mload(otherptr)
                          }
                          if (a != b) {
                              // Mask out irrelevant bytes and check again
                              uint mask;
                              if (shortest > 32) {
                                  mask = uint256(- 1); // aka 0xffffff....
                              } else {
                                  mask = ~(2 ** (8 * (32 - shortest + idx)) - 1);
                              }
                              uint diff = (a & mask) - (b & mask);
                              if (diff != 0)
                              return int(diff);
                          }
                          selfptr += 32;
                          otherptr += 32;
                      }
              
                      return int(len) - int(otherlen);
                  }
              
                  /*
                  * @dev Returns true if the two byte ranges are equal.
                  * @param self The first byte range to compare.
                  * @param offset The offset into the first byte range.
                  * @param other The second byte range to compare.
                  * @param otherOffset The offset into the second byte range.
                  * @param len The number of bytes to compare
                  * @return True if the byte ranges are equal, false otherwise.
                  */
                  function equals(bytes memory self, uint offset, bytes memory other, uint otherOffset, uint len) internal pure returns (bool) {
                      return keccak(self, offset, len) == keccak(other, otherOffset, len);
                  }
              
                  /*
                  * @dev Returns true if the two byte ranges are equal with offsets.
                  * @param self The first byte range to compare.
                  * @param offset The offset into the first byte range.
                  * @param other The second byte range to compare.
                  * @param otherOffset The offset into the second byte range.
                  * @return True if the byte ranges are equal, false otherwise.
                  */
                  function equals(bytes memory self, uint offset, bytes memory other, uint otherOffset) internal pure returns (bool) {
                      return keccak(self, offset, self.length - offset) == keccak(other, otherOffset, other.length - otherOffset);
                  }
              
                  /*
                  * @dev Compares a range of 'self' to all of 'other' and returns True iff
                  *      they are equal.
                  * @param self The first byte range to compare.
                  * @param offset The offset into the first byte range.
                  * @param other The second byte range to compare.
                  * @return True if the byte ranges are equal, false otherwise.
                  */
                  function equals(bytes memory self, uint offset, bytes memory other) internal pure returns (bool) {
                      return self.length >= offset + other.length && equals(self, offset, other, 0, other.length);
                  }
              
                  /*
                  * @dev Returns true if the two byte ranges are equal.
                  * @param self The first byte range to compare.
                  * @param other The second byte range to compare.
                  * @return True if the byte ranges are equal, false otherwise.
                  */
                  function equals(bytes memory self, bytes memory other) internal pure returns(bool) {
                      return self.length == other.length && equals(self, 0, other, 0, self.length);
                  }
              
                  /*
                  * @dev Returns the 8-bit number at the specified index of self.
                  * @param self The byte string.
                  * @param idx The index into the bytes
                  * @return The specified 8 bits of the string, interpreted as an integer.
                  */
                  function readUint8(bytes memory self, uint idx) internal pure returns (uint8 ret) {
                      return uint8(self[idx]);
                  }
              
                  /*
                  * @dev Returns the 16-bit number at the specified index of self.
                  * @param self The byte string.
                  * @param idx The index into the bytes
                  * @return The specified 16 bits of the string, interpreted as an integer.
                  */
                  function readUint16(bytes memory self, uint idx) internal pure returns (uint16 ret) {
                      require(idx + 2 <= self.length);
                      assembly {
                          ret := and(mload(add(add(self, 2), idx)), 0xFFFF)
                      }
                  }
              
                  /*
                  * @dev Returns the 32-bit number at the specified index of self.
                  * @param self The byte string.
                  * @param idx The index into the bytes
                  * @return The specified 32 bits of the string, interpreted as an integer.
                  */
                  function readUint32(bytes memory self, uint idx) internal pure returns (uint32 ret) {
                      require(idx + 4 <= self.length);
                      assembly {
                          ret := and(mload(add(add(self, 4), idx)), 0xFFFFFFFF)
                      }
                  }
              
                  /*
                  * @dev Returns the 32 byte value at the specified index of self.
                  * @param self The byte string.
                  * @param idx The index into the bytes
                  * @return The specified 32 bytes of the string.
                  */
                  function readBytes32(bytes memory self, uint idx) internal pure returns (bytes32 ret) {
                      require(idx + 32 <= self.length);
                      assembly {
                          ret := mload(add(add(self, 32), idx))
                      }
                  }
              
                  /*
                  * @dev Returns the 32 byte value at the specified index of self.
                  * @param self The byte string.
                  * @param idx The index into the bytes
                  * @return The specified 32 bytes of the string.
                  */
                  function readBytes20(bytes memory self, uint idx) internal pure returns (bytes20 ret) {
                      require(idx + 20 <= self.length);
                      assembly {
                          ret := and(mload(add(add(self, 32), idx)), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000)
                      }
                  }
              
                  /*
                  * @dev Returns the n byte value at the specified index of self.
                  * @param self The byte string.
                  * @param idx The index into the bytes.
                  * @param len The number of bytes.
                  * @return The specified 32 bytes of the string.
                  */
                  function readBytesN(bytes memory self, uint idx, uint len) internal pure returns (bytes32 ret) {
                      require(len <= 32);
                      require(idx + len <= self.length);
                      assembly {
                          let mask := not(sub(exp(256, sub(32, len)), 1))
                          ret := and(mload(add(add(self, 32), idx)),  mask)
                      }
                  }
              
                  function memcpy(uint dest, uint src, uint len) private pure {
                      // Copy word-length chunks while possible
                      for (; len >= 32; len -= 32) {
                          assembly {
                              mstore(dest, mload(src))
                          }
                          dest += 32;
                          src += 32;
                      }
              
                      // Copy remaining bytes
                      uint mask = 256 ** (32 - len) - 1;
                      assembly {
                          let srcpart := and(mload(src), not(mask))
                          let destpart := and(mload(dest), mask)
                          mstore(dest, or(destpart, srcpart))
                      }
                  }
              
                  /*
                  * @dev Copies a substring into a new byte string.
                  * @param self The byte string to copy from.
                  * @param offset The offset to start copying at.
                  * @param len The number of bytes to copy.
                  */
                  function substring(bytes memory self, uint offset, uint len) internal pure returns(bytes memory) {
                      require(offset + len <= self.length);
              
                      bytes memory ret = new bytes(len);
                      uint dest;
                      uint src;
              
                      assembly {
                          dest := add(ret, 32)
                          src := add(add(self, 32), offset)
                      }
                      memcpy(dest, src, len);
              
                      return ret;
                  }
              
                  // Maps characters from 0x30 to 0x7A to their base32 values.
                  // 0xFF represents invalid characters in that range.
                  bytes constant base32HexTable = hex'00010203040506070809FFFFFFFFFFFFFF0A0B0C0D0E0F101112131415161718191A1B1C1D1E1FFFFFFFFFFFFFFFFFFFFF0A0B0C0D0E0F101112131415161718191A1B1C1D1E1F';
              
                  /**
                   * @dev Decodes unpadded base32 data of up to one word in length.
                   * @param self The data to decode.
                   * @param off Offset into the string to start at.
                   * @param len Number of characters to decode.
                   * @return The decoded data, left aligned.
                   */
                  function base32HexDecodeWord(bytes memory self, uint off, uint len) internal pure returns(bytes32) {
                      require(len <= 52);
              
                      uint ret = 0;
                      uint8 decoded;
                      for(uint i = 0; i < len; i++) {
                          bytes1 char = self[off + i];
                          require(char >= 0x30 && char <= 0x7A);
                          decoded = uint8(base32HexTable[uint(uint8(char)) - 0x30]);
                          require(decoded <= 0x20);
                          if(i == len - 1) {
                              break;
                          }
                          ret = (ret << 5) | decoded;
                      }
              
                      uint bitlen = len * 5;
                      if(len % 8 == 0) {
                          // Multiple of 8 characters, no padding
                          ret = (ret << 5) | decoded;
                      } else if(len % 8 == 2) {
                          // Two extra characters - 1 byte
                          ret = (ret << 3) | (decoded >> 2);
                          bitlen -= 2;
                      } else if(len % 8 == 4) {
                          // Four extra characters - 2 bytes
                          ret = (ret << 1) | (decoded >> 4);
                          bitlen -= 4;
                      } else if(len % 8 == 5) {
                          // Five extra characters - 3 bytes
                          ret = (ret << 4) | (decoded >> 1);
                          bitlen -= 1;
                      } else if(len % 8 == 7) {
                          // Seven extra characters - 4 bytes
                          ret = (ret << 2) | (decoded >> 3);
                          bitlen -= 3;
                      } else {
                          revert();
                      }
              
                      return bytes32(ret << (256 - bitlen));
                  }
              }
              
              // File: @ensdomains/buffer/contracts/Buffer.sol
              
              pragma solidity >0.4.18;
              
              /**
              * @dev A library for working with mutable byte buffers in Solidity.
              *
              * Byte buffers are mutable and expandable, and provide a variety of primitives
              * for writing to them. At any time you can fetch a bytes object containing the
              * current contents of the buffer. The bytes object should not be stored between
              * operations, as it may change due to resizing of the buffer.
              */
              library Buffer {
                  /**
                  * @dev Represents a mutable buffer. Buffers have a current value (buf) and
                  *      a capacity. The capacity may be longer than the current value, in
                  *      which case it can be extended without the need to allocate more memory.
                  */
                  struct buffer {
                      bytes buf;
                      uint capacity;
                  }
              
                  /**
                  * @dev Initializes a buffer with an initial capacity.
                  * @param buf The buffer to initialize.
                  * @param capacity The number of bytes of space to allocate the buffer.
                  * @return The buffer, for chaining.
                  */
                  function init(buffer memory buf, uint capacity) internal pure returns(buffer memory) {
                      if (capacity % 32 != 0) {
                          capacity += 32 - (capacity % 32);
                      }
                      // Allocate space for the buffer data
                      buf.capacity = capacity;
                      assembly {
                          let ptr := mload(0x40)
                          mstore(buf, ptr)
                          mstore(ptr, 0)
                          mstore(0x40, add(32, add(ptr, capacity)))
                      }
                      return buf;
                  }
              
                  /**
                  * @dev Initializes a new buffer from an existing bytes object.
                  *      Changes to the buffer may mutate the original value.
                  * @param b The bytes object to initialize the buffer with.
                  * @return A new buffer.
                  */
                  function fromBytes(bytes memory b) internal pure returns(buffer memory) {
                      buffer memory buf;
                      buf.buf = b;
                      buf.capacity = b.length;
                      return buf;
                  }
              
                  function resize(buffer memory buf, uint capacity) private pure {
                      bytes memory oldbuf = buf.buf;
                      init(buf, capacity);
                      append(buf, oldbuf);
                  }
              
                  function max(uint a, uint b) private pure returns(uint) {
                      if (a > b) {
                          return a;
                      }
                      return b;
                  }
              
                  /**
                  * @dev Sets buffer length to 0.
                  * @param buf The buffer to truncate.
                  * @return The original buffer, for chaining..
                  */
                  function truncate(buffer memory buf) internal pure returns (buffer memory) {
                      assembly {
                          let bufptr := mload(buf)
                          mstore(bufptr, 0)
                      }
                      return buf;
                  }
              
                  /**
                  * @dev Writes a byte string to a buffer. Resizes if doing so would exceed
                  *      the capacity of the buffer.
                  * @param buf The buffer to append to.
                  * @param off The start offset to write to.
                  * @param data The data to append.
                  * @param len The number of bytes to copy.
                  * @return The original buffer, for chaining.
                  */
                  function write(buffer memory buf, uint off, bytes memory data, uint len) internal pure returns(buffer memory) {
                      require(len <= data.length);
              
                      if (off + len > buf.capacity) {
                          resize(buf, max(buf.capacity, len + off) * 2);
                      }
              
                      uint dest;
                      uint src;
                      assembly {
                          // Memory address of the buffer data
                          let bufptr := mload(buf)
                          // Length of existing buffer data
                          let buflen := mload(bufptr)
                          // Start address = buffer address + offset + sizeof(buffer length)
                          dest := add(add(bufptr, 32), off)
                          // Update buffer length if we're extending it
                          if gt(add(len, off), buflen) {
                              mstore(bufptr, add(len, off))
                          }
                          src := add(data, 32)
                      }
              
                      // Copy word-length chunks while possible
                      for (; len >= 32; len -= 32) {
                          assembly {
                              mstore(dest, mload(src))
                          }
                          dest += 32;
                          src += 32;
                      }
              
                      // Copy remaining bytes
                      uint mask = 256 ** (32 - len) - 1;
                      assembly {
                          let srcpart := and(mload(src), not(mask))
                          let destpart := and(mload(dest), mask)
                          mstore(dest, or(destpart, srcpart))
                      }
              
                      return buf;
                  }
              
                  /**
                  * @dev Appends a byte string to a buffer. Resizes if doing so would exceed
                  *      the capacity of the buffer.
                  * @param buf The buffer to append to.
                  * @param data The data to append.
                  * @param len The number of bytes to copy.
                  * @return The original buffer, for chaining.
                  */
                  function append(buffer memory buf, bytes memory data, uint len) internal pure returns (buffer memory) {
                      return write(buf, buf.buf.length, data, len);
                  }
              
                  /**
                  * @dev Appends a byte string to a buffer. Resizes if doing so would exceed
                  *      the capacity of the buffer.
                  * @param buf The buffer to append to.
                  * @param data The data to append.
                  * @return The original buffer, for chaining.
                  */
                  function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) {
                      return write(buf, buf.buf.length, data, data.length);
                  }
              
                  /**
                  * @dev Writes a byte to the buffer. Resizes if doing so would exceed the
                  *      capacity of the buffer.
                  * @param buf The buffer to append to.
                  * @param off The offset to write the byte at.
                  * @param data The data to append.
                  * @return The original buffer, for chaining.
                  */
                  function writeUint8(buffer memory buf, uint off, uint8 data) internal pure returns(buffer memory) {
                      if (off >= buf.capacity) {
                          resize(buf, buf.capacity * 2);
                      }
              
                      assembly {
                          // Memory address of the buffer data
                          let bufptr := mload(buf)
                          // Length of existing buffer data
                          let buflen := mload(bufptr)
                          // Address = buffer address + sizeof(buffer length) + off
                          let dest := add(add(bufptr, off), 32)
                          mstore8(dest, data)
                          // Update buffer length if we extended it
                          if eq(off, buflen) {
                              mstore(bufptr, add(buflen, 1))
                          }
                      }
                      return buf;
                  }
              
                  /**
                  * @dev Appends a byte to the buffer. Resizes if doing so would exceed the
                  *      capacity of the buffer.
                  * @param buf The buffer to append to.
                  * @param data The data to append.
                  * @return The original buffer, for chaining.
                  */
                  function appendUint8(buffer memory buf, uint8 data) internal pure returns(buffer memory) {
                      return writeUint8(buf, buf.buf.length, data);
                  }
              
                  /**
                  * @dev Writes up to 32 bytes to the buffer. Resizes if doing so would
                  *      exceed the capacity of the buffer.
                  * @param buf The buffer to append to.
                  * @param off The offset to write at.
                  * @param data The data to append.
                  * @param len The number of bytes to write (left-aligned).
                  * @return The original buffer, for chaining.
                  */
                  function write(buffer memory buf, uint off, bytes32 data, uint len) private pure returns(buffer memory) {
                      if (len + off > buf.capacity) {
                          resize(buf, (len + off) * 2);
                      }
              
                      uint mask = 256 ** len - 1;
                      // Right-align data
                      data = data >> (8 * (32 - len));
                      assembly {
                          // Memory address of the buffer data
                          let bufptr := mload(buf)
                          // Address = buffer address + sizeof(buffer length) + off + len
                          let dest := add(add(bufptr, off), len)
                          mstore(dest, or(and(mload(dest), not(mask)), data))
                          // Update buffer length if we extended it
                          if gt(add(off, len), mload(bufptr)) {
                              mstore(bufptr, add(off, len))
                          }
                      }
                      return buf;
                  }
              
                  /**
                  * @dev Writes a bytes20 to the buffer. Resizes if doing so would exceed the
                  *      capacity of the buffer.
                  * @param buf The buffer to append to.
                  * @param off The offset to write at.
                  * @param data The data to append.
                  * @return The original buffer, for chaining.
                  */
                  function writeBytes20(buffer memory buf, uint off, bytes20 data) internal pure returns (buffer memory) {
                      return write(buf, off, bytes32(data), 20);
                  }
              
                  /**
                  * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed
                  *      the capacity of the buffer.
                  * @param buf The buffer to append to.
                  * @param data The data to append.
                  * @return The original buffer, for chhaining.
                  */
                  function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) {
                      return write(buf, buf.buf.length, bytes32(data), 20);
                  }
              
                  /**
                  * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed
                  *      the capacity of the buffer.
                  * @param buf The buffer to append to.
                  * @param data The data to append.
                  * @return The original buffer, for chaining.
                  */
                  function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) {
                      return write(buf, buf.buf.length, data, 32);
                  }
              
                  /**
                  * @dev Writes an integer to the buffer. Resizes if doing so would exceed
                  *      the capacity of the buffer.
                  * @param buf The buffer to append to.
                  * @param off The offset to write at.
                  * @param data The data to append.
                  * @param len The number of bytes to write (right-aligned).
                  * @return The original buffer, for chaining.
                  */
                  function writeInt(buffer memory buf, uint off, uint data, uint len) private pure returns(buffer memory) {
                      if (len + off > buf.capacity) {
                          resize(buf, (len + off) * 2);
                      }
              
                      uint mask = 256 ** len - 1;
                      assembly {
                          // Memory address of the buffer data
                          let bufptr := mload(buf)
                          // Address = buffer address + off + sizeof(buffer length) + len
                          let dest := add(add(bufptr, off), len)
                          mstore(dest, or(and(mload(dest), not(mask)), data))
                          // Update buffer length if we extended it
                          if gt(add(off, len), mload(bufptr)) {
                              mstore(bufptr, add(off, len))
                          }
                      }
                      return buf;
                  }
              
                  /**
                   * @dev Appends a byte to the end of the buffer. Resizes if doing so would
                   * exceed the capacity of the buffer.
                   * @param buf The buffer to append to.
                   * @param data The data to append.
                   * @return The original buffer.
                   */
                  function appendInt(buffer memory buf, uint data, uint len) internal pure returns(buffer memory) {
                      return writeInt(buf, buf.buf.length, data, len);
                  }
              }
              
              // File: @ensdomains/dnssec-oracle/contracts/RRUtils.sol
              
              pragma solidity >0.4.23;
              
              
              
              /**
              * @dev RRUtils is a library that provides utilities for parsing DNS resource records.
              */
              library RRUtils {
                  using BytesUtils for *;
                  using Buffer for *;
              
                  /**
                  * @dev Returns the number of bytes in the DNS name at 'offset' in 'self'.
                  * @param self The byte array to read a name from.
                  * @param offset The offset to start reading at.
                  * @return The length of the DNS name at 'offset', in bytes.
                  */
                  function nameLength(bytes memory self, uint offset) internal pure returns(uint) {
                      uint idx = offset;
                      while (true) {
                          assert(idx < self.length);
                          uint labelLen = self.readUint8(idx);
                          idx += labelLen + 1;
                          if (labelLen == 0) {
                              break;
                          }
                      }
                      return idx - offset;
                  }
              
                  /**
                  * @dev Returns a DNS format name at the specified offset of self.
                  * @param self The byte array to read a name from.
                  * @param offset The offset to start reading at.
                  * @return The name.
                  */
                  function readName(bytes memory self, uint offset) internal pure returns(bytes memory ret) {
                      uint len = nameLength(self, offset);
                      return self.substring(offset, len);
                  }
              
                  /**
                  * @dev Returns the number of labels in the DNS name at 'offset' in 'self'.
                  * @param self The byte array to read a name from.
                  * @param offset The offset to start reading at.
                  * @return The number of labels in the DNS name at 'offset', in bytes.
                  */
                  function labelCount(bytes memory self, uint offset) internal pure returns(uint) {
                      uint count = 0;
                      while (true) {
                          assert(offset < self.length);
                          uint labelLen = self.readUint8(offset);
                          offset += labelLen + 1;
                          if (labelLen == 0) {
                              break;
                          }
                          count += 1;
                      }
                      return count;
                  }
              
                  /**
                  * @dev An iterator over resource records.
                  */
                  struct RRIterator {
                      bytes data;
                      uint offset;
                      uint16 dnstype;
                      uint16 class;
                      uint32 ttl;
                      uint rdataOffset;
                      uint nextOffset;
                  }
              
                  /**
                  * @dev Begins iterating over resource records.
                  * @param self The byte string to read from.
                  * @param offset The offset to start reading at.
                  * @return An iterator object.
                  */
                  function iterateRRs(bytes memory self, uint offset) internal pure returns (RRIterator memory ret) {
                      ret.data = self;
                      ret.nextOffset = offset;
                      next(ret);
                  }
              
                  /**
                  * @dev Returns true iff there are more RRs to iterate.
                  * @param iter The iterator to check.
                  * @return True iff the iterator has finished.
                  */
                  function done(RRIterator memory iter) internal pure returns(bool) {
                      return iter.offset >= iter.data.length;
                  }
              
                  /**
                  * @dev Moves the iterator to the next resource record.
                  * @param iter The iterator to advance.
                  */
                  function next(RRIterator memory iter) internal pure {
                      iter.offset = iter.nextOffset;
                      if (iter.offset >= iter.data.length) {
                          return;
                      }
              
                      // Skip the name
                      uint off = iter.offset + nameLength(iter.data, iter.offset);
              
                      // Read type, class, and ttl
                      iter.dnstype = iter.data.readUint16(off);
                      off += 2;
                      iter.class = iter.data.readUint16(off);
                      off += 2;
                      iter.ttl = iter.data.readUint32(off);
                      off += 4;
              
                      // Read the rdata
                      uint rdataLength = iter.data.readUint16(off);
                      off += 2;
                      iter.rdataOffset = off;
                      iter.nextOffset = off + rdataLength;
                  }
              
                  /**
                  * @dev Returns the name of the current record.
                  * @param iter The iterator.
                  * @return A new bytes object containing the owner name from the RR.
                  */
                  function name(RRIterator memory iter) internal pure returns(bytes memory) {
                      return iter.data.substring(iter.offset, nameLength(iter.data, iter.offset));
                  }
              
                  /**
                  * @dev Returns the rdata portion of the current record.
                  * @param iter The iterator.
                  * @return A new bytes object containing the RR's RDATA.
                  */
                  function rdata(RRIterator memory iter) internal pure returns(bytes memory) {
                      return iter.data.substring(iter.rdataOffset, iter.nextOffset - iter.rdataOffset);
                  }
              
                  /**
                  * @dev Checks if a given RR type exists in a type bitmap.
                  * @param self The byte string to read the type bitmap from.
                  * @param offset The offset to start reading at.
                  * @param rrtype The RR type to check for.
                  * @return True if the type is found in the bitmap, false otherwise.
                  */
                  function checkTypeBitmap(bytes memory self, uint offset, uint16 rrtype) internal pure returns (bool) {
                      uint8 typeWindow = uint8(rrtype >> 8);
                      uint8 windowByte = uint8((rrtype & 0xff) / 8);
                      uint8 windowBitmask = uint8(uint8(1) << (uint8(7) - uint8(rrtype & 0x7)));
                      for (uint off = offset; off < self.length;) {
                          uint8 window = self.readUint8(off);
                          uint8 len = self.readUint8(off + 1);
                          if (typeWindow < window) {
                              // We've gone past our window; it's not here.
                              return false;
                          } else if (typeWindow == window) {
                              // Check this type bitmap
                              if (len * 8 <= windowByte) {
                                  // Our type is past the end of the bitmap
                                  return false;
                              }
                              return (self.readUint8(off + windowByte + 2) & windowBitmask) != 0;
                          } else {
                              // Skip this type bitmap
                              off += len + 2;
                          }
                      }
              
                      return false;
                  }
              
                  function compareNames(bytes memory self, bytes memory other) internal pure returns (int) {
                      if (self.equals(other)) {
                          return 0;
                      }
              
                      uint off;
                      uint otheroff;
                      uint prevoff;
                      uint otherprevoff;
                      uint counts = labelCount(self, 0);
                      uint othercounts = labelCount(other, 0);
              
                      // Keep removing labels from the front of the name until both names are equal length
                      while (counts > othercounts) {
                          prevoff = off;
                          off = progress(self, off);
                          counts--;
                      }
              
                      while (othercounts > counts) {
                          otherprevoff = otheroff;
                          otheroff = progress(other, otheroff);
                          othercounts--;
                      }
              
                      // Compare the last nonequal labels to each other
                      while (counts > 0 && !self.equals(off, other, otheroff)) {
                          prevoff = off;
                          off = progress(self, off);
                          otherprevoff = otheroff;
                          otheroff = progress(other, otheroff);
                          counts -= 1;
                      }
              
                      if (off == 0) {
                          return -1;
                      }
                      if(otheroff == 0) {
                          return 1;
                      }
              
                      return self.compare(prevoff + 1, self.readUint8(prevoff), other, otherprevoff + 1, other.readUint8(otherprevoff));
                  }
              
                  function progress(bytes memory body, uint off) internal pure returns(uint) {
                      return off + 1 + body.readUint8(off);
                  }
              }
              
              // File: contracts/profiles/DNSResolver.sol
              
              pragma solidity ^0.5.0;
              
              
              
              contract DNSResolver is ResolverBase {
                  using RRUtils for *;
                  using BytesUtils for bytes;
              
                  bytes4 constant private DNS_RECORD_INTERFACE_ID = 0xa8fa5682;
              
                  // DNSRecordChanged is emitted whenever a given node/name/resource's RRSET is updated.
                  event DNSRecordChanged(bytes32 indexed node, bytes name, uint16 resource, bytes record);
                  // DNSRecordDeleted is emitted whenever a given node/name/resource's RRSET is deleted.
                  event DNSRecordDeleted(bytes32 indexed node, bytes name, uint16 resource);
                  // DNSZoneCleared is emitted whenever a given node's zone information is cleared.
                  event DNSZoneCleared(bytes32 indexed node);
              
                  // Version the mapping for each zone.  This allows users who have lost
                  // track of their entries to effectively delete an entire zone by bumping
                  // the version number.
                  // node => version
                  mapping(bytes32=>uint256) private versions;
              
                  // The records themselves.  Stored as binary RRSETs
                  // node => version => name => resource => data
                  mapping(bytes32=>mapping(uint256=>mapping(bytes32=>mapping(uint16=>bytes)))) private records;
              
                  // Count of number of entries for a given name.  Required for DNS resolvers
                  // when resolving wildcards.
                  // node => version => name => number of records
                  mapping(bytes32=>mapping(uint256=>mapping(bytes32=>uint16))) private nameEntriesCount;
              
                  /**
                   * Set one or more DNS records.  Records are supplied in wire-format.
                   * Records with the same node/name/resource must be supplied one after the
                   * other to ensure the data is updated correctly. For example, if the data
                   * was supplied:
                   *     a.example.com IN A 1.2.3.4
                   *     a.example.com IN A 5.6.7.8
                   *     www.example.com IN CNAME a.example.com.
                   * then this would store the two A records for a.example.com correctly as a
                   * single RRSET, however if the data was supplied:
                   *     a.example.com IN A 1.2.3.4
                   *     www.example.com IN CNAME a.example.com.
                   *     a.example.com IN A 5.6.7.8
                   * then this would store the first A record, the CNAME, then the second A
                   * record which would overwrite the first.
                   *
                   * @param node the namehash of the node for which to set the records
                   * @param data the DNS wire format records to set
                   */
                  function setDNSRecords(bytes32 node, bytes calldata data) external authorised(node) {
                      uint16 resource = 0;
                      uint256 offset = 0;
                      bytes memory name;
                      bytes memory value;
                      bytes32 nameHash;
                      // Iterate over the data to add the resource records
                      for (RRUtils.RRIterator memory iter = data.iterateRRs(0); !iter.done(); iter.next()) {
                          if (resource == 0) {
                              resource = iter.dnstype;
                              name = iter.name();
                              nameHash = keccak256(abi.encodePacked(name));
                              value = bytes(iter.rdata());
                          } else {
                              bytes memory newName = iter.name();
                              if (resource != iter.dnstype || !name.equals(newName)) {
                                  setDNSRRSet(node, name, resource, data, offset, iter.offset - offset, value.length == 0);
                                  resource = iter.dnstype;
                                  offset = iter.offset;
                                  name = newName;
                                  nameHash = keccak256(name);
                                  value = bytes(iter.rdata());
                              }
                          }
                      }
                      if (name.length > 0) {
                          setDNSRRSet(node, name, resource, data, offset, data.length - offset, value.length == 0);
                      }
                  }
              
                  /**
                   * Obtain a DNS record.
                   * @param node the namehash of the node for which to fetch the record
                   * @param name the keccak-256 hash of the fully-qualified name for which to fetch the record
                   * @param resource the ID of the resource as per https://en.wikipedia.org/wiki/List_of_DNS_record_types
                   * @return the DNS record in wire format if present, otherwise empty
                   */
                  function dnsRecord(bytes32 node, bytes32 name, uint16 resource) public view returns (bytes memory) {
                      return records[node][versions[node]][name][resource];
                  }
              
                  /**
                   * Check if a given node has records.
                   * @param node the namehash of the node for which to check the records
                   * @param name the namehash of the node for which to check the records
                   */
                  function hasDNSRecords(bytes32 node, bytes32 name) public view returns (bool) {
                      return (nameEntriesCount[node][versions[node]][name] != 0);
                  }
              
                  /**
                   * Clear all information for a DNS zone.
                   * @param node the namehash of the node for which to clear the zone
                   */
                  function clearDNSZone(bytes32 node) public authorised(node) {
                      versions[node]++;
                      emit DNSZoneCleared(node);
                  }
              
                  function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
                      return interfaceID == DNS_RECORD_INTERFACE_ID || super.supportsInterface(interfaceID);
                  }
              
                  function setDNSRRSet(
                      bytes32 node,
                      bytes memory name,
                      uint16 resource,
                      bytes memory data,
                      uint256 offset,
                      uint256 size,
                      bool deleteRecord) private
                  {
                      uint256 version = versions[node];
                      bytes32 nameHash = keccak256(name);
                      bytes memory rrData = data.substring(offset, size);
                      if (deleteRecord) {
                          if (records[node][version][nameHash][resource].length != 0) {
                              nameEntriesCount[node][version][nameHash]--;
                          }
                          delete(records[node][version][nameHash][resource]);
                          emit DNSRecordDeleted(node, name, resource);
                      } else {
                          if (records[node][version][nameHash][resource].length == 0) {
                              nameEntriesCount[node][version][nameHash]++;
                          }
                          records[node][version][nameHash][resource] = rrData;
                          emit DNSRecordChanged(node, name, resource, rrData);
                      }
                  }
              }
              
              // File: 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: 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: 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: 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: contracts/PublicResolver.sol
              
              pragma solidity ^0.5.0;
              pragma experimental ABIEncoderV2;
              
              
              
              
              
              
              
              
              
              
              /**
               * A simple resolver anyone can use; only allows the owner of a node to set its
               * address.
               */
              contract PublicResolver is ABIResolver, AddrResolver, ContentHashResolver, DNSResolver, InterfaceResolver, NameResolver, PubkeyResolver, TextResolver {
                  ENS ens;
              
                  /**
                   * A mapping of authorisations. An address that is authorised for a name
                   * may make any changes to the name that the owner could, but may not update
                   * the set of authorisations.
                   * (node, owner, caller) => isAuthorised
                   */
                  mapping(bytes32=>mapping(address=>mapping(address=>bool))) public authorisations;
              
                  event AuthorisationChanged(bytes32 indexed node, address indexed owner, address indexed target, bool isAuthorised);
              
                  constructor(ENS _ens) public {
                      ens = _ens;
                  }
              
                  /**
                   * @dev Sets or clears an authorisation.
                   * Authorisations are specific to the caller. Any account can set an authorisation
                   * for any name, but the authorisation that is checked will be that of the
                   * current owner of a name. Thus, transferring a name effectively clears any
                   * existing authorisations, and new authorisations can be set in advance of
                   * an ownership transfer if desired.
                   *
                   * @param node The name to change the authorisation on.
                   * @param target The address that is to be authorised or deauthorised.
                   * @param isAuthorised True if the address should be authorised, or false if it should be deauthorised.
                   */
                  function setAuthorisation(bytes32 node, address target, bool isAuthorised) external {
                      authorisations[node][msg.sender][target] = isAuthorised;
                      emit AuthorisationChanged(node, msg.sender, target, isAuthorised);
                  }
              
                  function isAuthorised(bytes32 node) internal view returns(bool) {
                      address owner = ens.owner(node);
                      return owner == msg.sender || authorisations[node][owner][msg.sender];
                  }
              
                  function multicall(bytes[] calldata data) external returns(bytes[] memory results) {
                      results = new bytes[](data.length);
                      for(uint i = 0; i < data.length; i++) {
                          (bool success, bytes memory result) = address(this).delegatecall(data[i]);
                          require(success);
                          results[i] = result;
                      }
                      return results;
                  }
              }

              File 5 of 7: LinearPremiumPriceOracle
              // File: contracts/SafeMath.sol
              
              pragma solidity >=0.4.24;
              
              /**
               * @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: 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: 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: 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/StablePriceOracle.sol
              
              pragma solidity >=0.5.0;
              
              
              
              
              
              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.
                  uint[] public rentPrices;
              
                  // Oracle address
                  AggregatorInterface public usdOracle;
              
                  event OracleChanged(address oracle);
              
                  event RentPriceChanged(uint[] prices);
              
                  bytes4 constant private INTERFACE_META_ID = bytes4(keccak256("supportsInterface(bytes4)"));
                  bytes4 constant private ORACLE_ID = bytes4(keccak256("price(string,uint256,uint256)") ^ keccak256("premium(string,uint256,uint256)"));
              
                  constructor(AggregatorInterface _usdOracle, uint[] memory _rentPrices) public {
                      usdOracle = _usdOracle;
                      setPrices(_rentPrices);
                  }
              
                  function price(string calldata name, uint expires, uint duration) external view returns(uint) {
                      uint len = name.strlen();
                      if(len > rentPrices.length) {
                          len = rentPrices.length;
                      }
                      require(len > 0);
                      
                      uint 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(uint[] memory _rentPrices) public onlyOwner {
                      rentPrices = _rentPrices;
                      emit RentPriceChanged(_rentPrices);
                  }
              
                  /**
                   * @dev Sets the price oracle address
                   * @param _usdOracle The address of the price oracle to use.
                   */
                  function setOracle(AggregatorInterface _usdOracle) public onlyOwner {
                      usdOracle = _usdOracle;
                      emit OracleChanged(address(_usdOracle));
                  }
              
                  /**
                   * @dev Returns the pricing premium in wei.
                   */
                  function premium(string calldata name, uint expires, uint duration) external view returns(uint) {
                      return attoUSDToWei(_premium(name, expires, duration));
                  }
              
                  /**
                   * @dev Returns the pricing premium in internal base units.
                   */
                  function _premium(string memory name, uint expires, uint duration) internal view returns(uint) {
                      return 0;
                  }
              
                  function attoUSDToWei(uint amount) internal view returns(uint) {
                      uint ethPrice = uint(usdOracle.latestAnswer());
                      return amount.mul(1e8).div(ethPrice);
                  }
              
                  function weiToAttoUSD(uint amount) internal view returns(uint) {
                      uint ethPrice = uint(usdOracle.latestAnswer());
                      return amount.mul(ethPrice).div(1e8);
                  }
              
                  function supportsInterface(bytes4 interfaceID) public view returns (bool) {
                      return interfaceID == INTERFACE_META_ID || interfaceID == ORACLE_ID;
                  }
              }
              
              // File: contracts/LinearPremiumPriceOracle.sol
              
              pragma solidity >=0.5.0;
              
              
              
              contract LinearPremiumPriceOracle is StablePriceOracle {
                  using SafeMath for *;
              
                  uint GRACE_PERIOD = 90 days;
              
                  uint public initialPremium;
                  uint public premiumDecreaseRate;
              
                  bytes4 constant private TIME_UNTIL_PREMIUM_ID = bytes4(keccak256("timeUntilPremium(uint,uint"));
              
                  constructor(AggregatorInterface _usdOracle, uint[] memory _rentPrices, uint _initialPremium, uint _premiumDecreaseRate) public
                      StablePriceOracle(_usdOracle, _rentPrices)
                  {
                      initialPremium = _initialPremium;
                      premiumDecreaseRate = _premiumDecreaseRate;
                  }
              
                  function _premium(string memory name, uint expires, uint /*duration*/) internal view returns(uint) {
                      expires = expires.add(GRACE_PERIOD);
                      if(expires > now) {
                          // No premium for renewals
                          return 0;
                      }
              
                      // Calculate the discount off the maximum premium
                      uint discount = premiumDecreaseRate.mul(now.sub(expires));
              
                      // If we've run out the premium period, return 0.
                      if(discount > initialPremium) {
                          return 0;
                      }
                      
                      return initialPremium - discount;
                  }
              
                  /**
                   * @dev Returns the timestamp at which a name with the specified expiry date will have
                   *      the specified re-registration price premium.
                   * @param expires The timestamp at which the name expires.
                   * @param amount The amount, in wei, the caller is willing to pay
                   * @return The timestamp at which the premium for this domain will be `amount`.
                   */
                  function timeUntilPremium(uint expires, uint amount) external view returns(uint) {
                      amount = weiToAttoUSD(amount);
                      require(amount <= initialPremium);
              
                      expires = expires.add(GRACE_PERIOD);
              
                      uint discount = initialPremium.sub(amount);
                      uint duration = discount.div(premiumDecreaseRate);
                      return expires.add(duration);
                  }
              
                  function supportsInterface(bytes4 interfaceID) public view returns (bool) {
                      return (interfaceID == TIME_UNTIL_PREMIUM_ID) || super.supportsInterface(interfaceID);
                  }
              }

              File 6 of 7: 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 7 of 7: 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;
                }
              }