ETH Price: $2,180.00 (-6.34%)

Transaction Decoder

Block:
17530839 at Jun-21-2023 09:54:11 PM +UTC
Transaction Fee:
0.003497567574187183 ETH $7.62
Gas Used:
194,719 Gas / 17.962127857 Gwei

Emitted Events:

270 BaseRegistrarImplementation.Transfer( from=0x00000000...000000000, to=[Sender] 0xa38ff9fd6f5449a5bb3f046a6325143871948097, tokenId=89119901800573845076424688899806704590737483791497100932338075262523154254291 )
271 ENSRegistryWithFallback.NewOwner( node=93CDEB708B7545DC668EB9280176169D1C33CFD8ED6F04690A0BCC88A93FC4AE, label=C50813AF12CF42F72649626F003016D549BAE0ACBAE4E118FFE02E3A420A49D3, owner=[Sender] 0xa38ff9fd6f5449a5bb3f046a6325143871948097 )
272 BaseRegistrarImplementation.NameRegistered( id=89119901800573845076424688899806704590737483791497100932338075262523154254291, owner=[Sender] 0xa38ff9fd6f5449a5bb3f046a6325143871948097, expires=1703162927 )
273 ETHRegistrarController.NameRegistered( name=$paola, label=C50813AF12CF42F72649626F003016D549BAE0ACBAE4E118FFE02E3A420A49D3, owner=[Sender] 0xa38ff9fd6f5449a5bb3f046a6325143871948097, cost=1332969243937180, expires=1703162927 )

Account State Difference:

  Address   Before After State Difference Code
0x00000000...A6C7d2e1e
(ENS: Registry with Fallback)
0x00000000...Ec09DE67C 3.584511403120116355 Eth3.584777996968903791 Eth0.000266593848787436
0x283Af0B2...A627EB7F5
(ENS: Old ETH Registrar Controller)
3,099.110843364940063677 Eth3,099.112176334184000857 Eth0.00133296924393718
0x57f1887a...Af147eA85
(builder0x69)
1.922600064111558641 Eth1.922619536011558641 Eth0.0000194719
0xA38Ff9Fd...871948097
0.155723775025512881 Eth
Nonce: 374
0.150626644358601082 Eth
Nonce: 375
0.005097130666911799

Execution Trace

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

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

            File 4 of 6: ExponentialPremiumPriceOracle
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)
            pragma solidity ^0.8.0;
            import "../utils/Context.sol";
            /**
             * @dev Contract module which provides a basic access control mechanism, where
             * there is an account (an owner) that can be granted exclusive access to
             * specific functions.
             *
             * By default, the owner account will be the one that deploys the contract. This
             * can later be changed with {transferOwnership}.
             *
             * This module is used through inheritance. It will make available the modifier
             * `onlyOwner`, which can be applied to your functions to restrict their use to
             * the owner.
             */
            abstract contract Ownable is Context {
                address private _owner;
                event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                /**
                 * @dev Initializes the contract setting the deployer as the initial owner.
                 */
                constructor() {
                    _transferOwnership(_msgSender());
                }
                /**
                 * @dev Returns the address of the current owner.
                 */
                function owner() public view virtual returns (address) {
                    return _owner;
                }
                /**
                 * @dev Throws if called by any account other than the owner.
                 */
                modifier onlyOwner() {
                    require(owner() == _msgSender(), "Ownable: caller is not the owner");
                    _;
                }
                /**
                 * @dev Leaves the contract without owner. It will not be possible to call
                 * `onlyOwner` functions anymore. Can only be called by the current owner.
                 *
                 * NOTE: Renouncing ownership will leave the contract without an owner,
                 * thereby removing any functionality that is only available to the owner.
                 */
                function renounceOwnership() public virtual onlyOwner {
                    _transferOwnership(address(0));
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Can only be called by the current owner.
                 */
                function transferOwnership(address newOwner) public virtual onlyOwner {
                    require(newOwner != address(0), "Ownable: new owner is the zero address");
                    _transferOwnership(newOwner);
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Internal function without access restriction.
                 */
                function _transferOwnership(address newOwner) internal virtual {
                    address oldOwner = _owner;
                    _owner = newOwner;
                    emit OwnershipTransferred(oldOwner, newOwner);
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev Provides information about the current execution context, including the
             * sender of the transaction and its data. While these are generally available
             * via msg.sender and msg.data, they should not be accessed in such a direct
             * manner, since when dealing with meta-transactions the account sending and
             * paying for execution may not be the actual sender (as far as an application
             * is concerned).
             *
             * This contract is only required for intermediate, library-like contracts.
             */
            abstract contract Context {
                function _msgSender() internal view virtual returns (address) {
                    return msg.sender;
                }
                function _msgData() internal view virtual returns (bytes calldata) {
                    return msg.data;
                }
            }
            pragma solidity >=0.8.4;
            import "./SafeMath.sol";
            import "./StablePriceOracle.sol";
            contract ExponentialPremiumPriceOracle is StablePriceOracle {
                uint256 constant GRACE_PERIOD = 90 days;
                uint256 immutable startPremium;
                uint256 immutable endValue;
                constructor(
                    AggregatorInterface _usdOracle,
                    uint256[] memory _rentPrices,
                    uint256 _startPremium,
                    uint256 totalDays
                ) StablePriceOracle(_usdOracle, _rentPrices) {
                    startPremium = _startPremium;
                    endValue = _startPremium >> totalDays;
                }
                uint256 constant PRECISION = 1e18;
                uint256 constant bit1 = 999989423469314432; // 0.5 ^ 1/65536 * (10 ** 18)
                uint256 constant bit2 = 999978847050491904; // 0.5 ^ 2/65536 * (10 ** 18)
                uint256 constant bit3 = 999957694548431104;
                uint256 constant bit4 = 999915390886613504;
                uint256 constant bit5 = 999830788931929088;
                uint256 constant bit6 = 999661606496243712;
                uint256 constant bit7 = 999323327502650752;
                uint256 constant bit8 = 998647112890970240;
                uint256 constant bit9 = 997296056085470080;
                uint256 constant bit10 = 994599423483633152;
                uint256 constant bit11 = 989228013193975424;
                uint256 constant bit12 = 978572062087700096;
                uint256 constant bit13 = 957603280698573696;
                uint256 constant bit14 = 917004043204671232;
                uint256 constant bit15 = 840896415253714560;
                uint256 constant bit16 = 707106781186547584;
                /**
                 * @dev Returns the pricing premium in internal base units.
                 */
                function _premium(
                    string memory,
                    uint256 expires,
                    uint256
                ) internal view override returns (uint256) {
                    expires = expires + GRACE_PERIOD;
                    if (expires > block.timestamp) {
                        return 0;
                    }
                    uint256 elapsed = block.timestamp - expires;
                    uint256 premium = decayedPremium(startPremium, elapsed);
                    if (premium >= endValue) {
                        return premium - endValue;
                    }
                    return 0;
                }
                /**
                 * @dev Returns the premium price at current time elapsed
                 * @param startPremium starting price
                 * @param elapsed time past since expiry
                 */
                function decayedPremium(uint256 startPremium, uint256 elapsed)
                    public
                    pure
                    returns (uint256)
                {
                    uint256 daysPast = (elapsed * PRECISION) / 1 days;
                    uint256 intDays = daysPast / PRECISION;
                    uint256 premium = startPremium >> intDays;
                    uint256 partDay = (daysPast - intDays * PRECISION);
                    uint256 fraction = (partDay * (2**16)) / PRECISION;
                    uint256 totalPremium = addFractionalPremium(fraction, premium);
                    return totalPremium;
                }
                function addFractionalPremium(uint256 fraction, uint256 premium)
                    internal
                    pure
                    returns (uint256)
                {
                    if (fraction & (1 << 0) != 0) {
                        premium = (premium * bit1) / PRECISION;
                    }
                    if (fraction & (1 << 1) != 0) {
                        premium = (premium * bit2) / PRECISION;
                    }
                    if (fraction & (1 << 2) != 0) {
                        premium = (premium * bit3) / PRECISION;
                    }
                    if (fraction & (1 << 3) != 0) {
                        premium = (premium * bit4) / PRECISION;
                    }
                    if (fraction & (1 << 4) != 0) {
                        premium = (premium * bit5) / PRECISION;
                    }
                    if (fraction & (1 << 5) != 0) {
                        premium = (premium * bit6) / PRECISION;
                    }
                    if (fraction & (1 << 6) != 0) {
                        premium = (premium * bit7) / PRECISION;
                    }
                    if (fraction & (1 << 7) != 0) {
                        premium = (premium * bit8) / PRECISION;
                    }
                    if (fraction & (1 << 8) != 0) {
                        premium = (premium * bit9) / PRECISION;
                    }
                    if (fraction & (1 << 9) != 0) {
                        premium = (premium * bit10) / PRECISION;
                    }
                    if (fraction & (1 << 10) != 0) {
                        premium = (premium * bit11) / PRECISION;
                    }
                    if (fraction & (1 << 11) != 0) {
                        premium = (premium * bit12) / PRECISION;
                    }
                    if (fraction & (1 << 12) != 0) {
                        premium = (premium * bit13) / PRECISION;
                    }
                    if (fraction & (1 << 13) != 0) {
                        premium = (premium * bit14) / PRECISION;
                    }
                    if (fraction & (1 << 14) != 0) {
                        premium = (premium * bit15) / PRECISION;
                    }
                    if (fraction & (1 << 15) != 0) {
                        premium = (premium * bit16) / PRECISION;
                    }
                    return premium;
                }
                function supportsInterface(bytes4 interfaceID)
                    public
                    view
                    virtual
                    override
                    returns (bool)
                {
                    return super.supportsInterface(interfaceID);
                }
            }
            pragma solidity >=0.8.4;
            interface PriceOracle {
                /**
                 * @dev Returns the price to register or renew a name.
                 * @param name The name being registered or renewed.
                 * @param expires When the name presently expires (0 if this is a new registration).
                 * @param duration How long the name is being registered or extended for, in seconds.
                 * @return The price of this renewal or registration, in wei.
                 */
                function price(string calldata name, uint expires, uint duration) external view returns(uint);
            }
            pragma solidity >=0.8.4;
            /**
             * @title SafeMath
             * @dev Unsigned math operations with safety checks that revert on error
             */
            library SafeMath {
                /**
                * @dev Multiplies two unsigned integers, reverts on overflow.
                */
                function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                    // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                    // benefit is lost if 'b' is also tested.
                    // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                    if (a == 0) {
                        return 0;
                    }
                    uint256 c = a * b;
                    require(c / a == b);
                    return c;
                }
                /**
                * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
                */
                function div(uint256 a, uint256 b) internal pure returns (uint256) {
                    // Solidity only automatically asserts when dividing by 0
                    require(b > 0);
                    uint256 c = a / b;
                    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
                    return c;
                }
                /**
                * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
                */
                function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                    require(b <= a);
                    uint256 c = a - b;
                    return c;
                }
                /**
                * @dev Adds two unsigned integers, reverts on overflow.
                */
                function add(uint256 a, uint256 b) internal pure returns (uint256) {
                    uint256 c = a + b;
                    require(c >= a);
                    return c;
                }
                /**
                * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
                * reverts when dividing by zero.
                */
                function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                    require(b != 0);
                    return a % b;
                }
            }
            pragma solidity >=0.8.4;
            import "./PriceOracle.sol";
            import "./SafeMath.sol";
            import "./StringUtils.sol";
            import "@openzeppelin/contracts/access/Ownable.sol";
            interface AggregatorInterface {
                function latestAnswer() external view returns (int256);
            }
            // StablePriceOracle sets a price in USD, based on an oracle.
            contract StablePriceOracle is Ownable, PriceOracle {
                using SafeMath for *;
                using StringUtils for *;
                // Rent in base price units by length. Element 0 is for 1-length names, and so on.
                uint256[] public rentPrices;
                // Oracle address
                AggregatorInterface public immutable usdOracle;
                event OracleChanged(address oracle);
                event RentPriceChanged(uint256[] prices);
                bytes4 private constant INTERFACE_META_ID =
                    bytes4(keccak256("supportsInterface(bytes4)"));
                bytes4 private constant ORACLE_ID =
                    bytes4(
                        keccak256("price(string,uint256,uint256)") ^
                            keccak256("premium(string,uint256,uint256)")
                    );
                constructor(AggregatorInterface _usdOracle, uint256[] memory _rentPrices)
                    public
                {
                    usdOracle = _usdOracle;
                    setPrices(_rentPrices);
                }
                function price(
                    string calldata name,
                    uint256 expires,
                    uint256 duration
                ) external view override returns (uint256) {
                    uint256 len = name.strlen();
                    if (len > rentPrices.length) {
                        len = rentPrices.length;
                    }
                    require(len > 0);
                    uint256 basePrice = rentPrices[len - 1].mul(duration);
                    basePrice = basePrice.add(_premium(name, expires, duration));
                    return attoUSDToWei(basePrice);
                }
                /**
                 * @dev Sets rent prices.
                 * @param _rentPrices The price array. Each element corresponds to a specific
                 *                    name length; names longer than the length of the array
                 *                    default to the price of the last element. Values are
                 *                    in base price units, equal to one attodollar (1e-18
                 *                    dollar) each.
                 */
                function setPrices(uint256[] memory _rentPrices) public onlyOwner {
                    rentPrices = _rentPrices;
                    emit RentPriceChanged(_rentPrices);
                }
                /**
                 * @dev Returns the pricing premium in wei.
                 */
                function premium(
                    string calldata name,
                    uint256 expires,
                    uint256 duration
                ) external view returns (uint256) {
                    uint256 weiPrice = attoUSDToWei(_premium(name, expires, duration));
                    return weiPrice;
                }
                /**
                 * @dev Returns the pricing premium in internal base units.
                 */
                function _premium(
                    string memory name,
                    uint256 expires,
                    uint256 duration
                ) internal view virtual returns (uint256) {
                    return 0;
                }
                function attoUSDToWei(uint256 amount) internal view returns (uint256) {
                    uint256 ethPrice = uint256(usdOracle.latestAnswer()); //2
                    return amount.mul(1e8).div(ethPrice);
                }
                function weiToAttoUSD(uint256 amount) internal view returns (uint256) {
                    uint256 ethPrice = uint256(usdOracle.latestAnswer());
                    return amount.mul(ethPrice).div(1e8);
                }
                function supportsInterface(bytes4 interfaceID)
                    public
                    view
                    virtual
                    returns (bool)
                {
                    return interfaceID == INTERFACE_META_ID || interfaceID == ORACLE_ID;
                }
            }
            pragma solidity >=0.8.4;
            library StringUtils {
                /**
                 * @dev Returns the length of a given string
                 *
                 * @param s The string to measure the length of
                 * @return The length of the input string
                 */
                function strlen(string memory s) internal pure returns (uint) {
                    uint len;
                    uint i = 0;
                    uint bytelength = bytes(s).length;
                    for(len = 0; i < bytelength; len++) {
                        bytes1 b = bytes(s)[i];
                        if(b < 0x80) {
                            i += 1;
                        } else if (b < 0xE0) {
                            i += 2;
                        } else if (b < 0xF0) {
                            i += 3;
                        } else if (b < 0xF8) {
                            i += 4;
                        } else if (b < 0xFC) {
                            i += 5;
                        } else {
                            i += 6;
                        }
                    }
                    return len;
                }
            }
            

            File 5 of 6: 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 6 of 6: AccessControlledOffchainAggregator
            // SPDX-License-Identifier: MIT
            pragma solidity 0.7.6;
            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,
                LinkTokenInterface _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 4.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;
            interface AccessControllerInterface {
              function hasAccess(address user, bytes calldata data) external view returns (bool);
            }
            // 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;
            import "./AggregatorInterface.sol";
            import "./AggregatorV3Interface.sol";
            interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface
            {
            }// 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);
              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;
            interface AggregatorValidatorInterface {
              function validate(
                uint256 previousRoundId,
                int256 previousAnswer,
                uint256 currentRoundId,
                int256 currentAnswer
              ) external returns (bool);
            }// SPDX-License-Identifier: MIT
            pragma solidity ^0.7.0;
            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.6;
            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,
                LinkTokenInterface _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 4.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;
                require(
                  callWithExactGasEvenIfTargetIsNoContract(
                    vc.gasLimit,
                    address(vc.validator),
                    abi.encodeWithSignature(
                      "validate(uint256,int256,uint256,int256)",
                      uint256(prevAggregatorRoundId),
                      prevAggregatorRoundAnswer,
                      uint256(_aggregatorRoundId),
                      _answer
                    )
                  ),
                  "insufficient gas"
                );
              }
              uint256 private constant CALL_WITH_EXACT_GAS_CUSHION = 5_000;
              /**
               * @dev calls target address with exactly gasAmount gas and data as calldata
               * or reverts if at least gasAmount gas is not available.
               */
              function callWithExactGasEvenIfTargetIsNoContract(
                uint256 _gasAmount,
                address _target,
                bytes memory _data
              )
                private
                returns (bool sufficientGas)
              {
                // solhint-disable-next-line no-inline-assembly
                assembly {
                  let g := gas()
                  // Compute g -= CALL_WITH_EXACT_GAS_CUSHION and check for underflow. We
                  // need the cushion since the logic following the above call to gas also
                  // costs gas which we cannot account for exactly. So cushion is a
                  // conservative upper bound for the cost of this logic.
                  if iszero(lt(g, CALL_WITH_EXACT_GAS_CUSHION)) {
                    g := sub(g, CALL_WITH_EXACT_GAS_CUSHION)
                    // If g - g//64 <= _gasAmount, we don't have enough gas. (We subtract g//64
                    // because of EIP-150.)
                    if gt(sub(g, div(g, 64)), _gasAmount) {
                      // Call and ignore success/return data. Note that we did not check
                      // whether a contract actually exists at the _target address.
                      pop(call(_gasAmount, _target, 0, add(_data, 0x20), mload(_data), 0, 0))
                      sufficientGas := true
                    }
                  }
                }
              }
              /*
               * 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.6;
            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;
              // We assume that the token contract is correct. This contract is not written
              // to handle misbehaving ERC20 tokens!
              LinkTokenInterface internal s_linkToken;
              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,
                LinkTokenInterface _link,
                AccessControllerInterface _billingAccessController
              )
              {
                setBillingInternal(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
                  _linkGweiPerObservation, _linkGweiPerTransmission);
                s_linkToken = _link;
                emit LinkTokenSet(LinkTokenInterface(address(0)), _link);
                setBillingAccessControllerInternal(_billingAccessController);
                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 the LINK token contract is set
               * @param _oldLinkToken the address of the old LINK token contract
               * @param _newLinkToken the address of the new LINK token contract
               */
              event LinkTokenSet(
                LinkTokenInterface indexed _oldLinkToken,
                LinkTokenInterface indexed _newLinkToken
              );
              /*
               * @notice sets the LINK token contract used for paying oracles
               * @param _linkToken the address of the LINK token contract
               * @param _recipient remaining funds from the previous token contract are transfered
               * here
               * @dev this function will return early (without an error) without changing any state
               * if _linkToken equals getLinkToken().
               * @dev this will trigger a payout so that a malicious owner cannot take from oracles
               * what is already owed to them.
               * @dev we assume that the token contract is correct. This contract is not written
               * to handle misbehaving ERC20 tokens!
               */
              function setLinkToken(
                LinkTokenInterface _linkToken,
                address _recipient
              ) external
                onlyOwner()
              {
                LinkTokenInterface oldLinkToken = s_linkToken;
                if (_linkToken == oldLinkToken) {
                  // No change, nothing to be done
                  return;
                }
                // call balanceOf as a sanity check on whether we're talking to a token
                // contract
                _linkToken.balanceOf(address(this));
                // we break CEI here, but that's okay because we're dealing with a correct
                // token contract (by assumption).
                payOracles();
                uint256 remainingBalance = oldLinkToken.balanceOf(address(this));
                require(oldLinkToken.transfer(_recipient, remainingBalance), "transfer remaining funds failed");
                s_linkToken = _linkToken;
                emit LinkTokenSet(oldLinkToken, _linkToken);
              }
              /*
               * @notice gets the LINK token contract used for paying oracles
               * @return linkToken the address of the LINK token contract
               */
              function getLinkToken()
                external
                view
                returns(LinkTokenInterface linkToken)
              {
                return s_linkToken;
              }
              /**
               * @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
               * @param linkToken address of the LINK token contract
               */
              event OraclePaid(
                address indexed transmitter,
                address indexed payee,
                uint256 amount,
                LinkTokenInterface indexed linkToken
              );
              // 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(s_linkToken.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, s_linkToken);
                }
              }
              // 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;
                LinkTokenInterface linkToken = s_linkToken;
                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(linkToken.transfer(payee, linkWeiAmount), "insufficient funds");
                      observationsCounts[transmitteridx] = 1;       // "zero" the counts.
                      gasReimbursementsLinkWei[transmitteridx] = 1; // "zero" the counts.
                      emit OraclePaid(transmitters[transmitteridx], payee, linkWeiAmount, linkToken);
                    }
                }
                // "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 = s_linkToken.balanceOf(address(this));
                require(linkBalance >= linkDue, "insufficient balance");
                require(s_linkToken.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(s_linkToken.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.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() {
                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.6;
            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.6;
            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;
            abstract contract TypeAndVersionInterface{
              function typeAndVersion()
                external
                pure
                virtual
                returns (string memory);
            }