ETH Price: $1,826.76 (-4.54%)

Transaction Decoder

Block:
20226287 at Jul-03-2024 01:29:47 PM +UTC
Transaction Fee:
0.0027184988209893 ETH $4.97
Gas Used:
134,700 Gas / 20.181876919 Gwei

Emitted Events:

185 TetherToken.Transfer( from=[Sender] 0x4e64c2d06d19d13061e62e291b2c4e9fe5679b93, to=0xC6C84554dD6006D3b6319094e635E9335F6A4683, value=1079302 )
186 ERC20ConversionProxy.0x9f16cbcc523c67a60c450e5ffe4f3b7b6dbe772e7abcadb2686ce029a9a0a2b6( 0x9f16cbcc523c67a60c450e5ffe4f3b7b6dbe772e7abcadb2686ce029a9a0a2b6, 0xe41153e43581a4951ad2e15f79c697d9ca33ba95388b65bfc28e5404aefc7292, 000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7, 000000000000000000000000c6c84554dd6006d3b6319094e635e9335f6a4683, 0000000000000000000000000000000000000000000000000000000000107806, 0000000000000000000000000000000000000000000000000000000000000000, 00000000000000000000000035d0e078755cd84d3e0656caab417dee1d7939c7 )
187 ERC20ConversionProxy.TransferWithConversionAndReference( 0x96d0d1d75923f40b50f6fe74613b2c23239149607848fbca3941fee7ac041cdc, 0xe41153e43581a4951ad2e15f79c697d9ca33ba95388b65bfc28e5404aefc7292, 0000000000000000000000000000000000000000000000000000000005f5e100, 00000000000000000000000017b4158805772ced11225e77339f90beb5aae968, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
4.279442648147030822 Eth4.279569387377030822 Eth0.00012673923
0x4E64C2d0...fe5679b93
0.18746232978929276 Eth
Nonce: 558
0.18474383096830346 Eth
Nonce: 559
0.0027184988209893
0xdAC17F95...13D831ec7

Execution Trace

ERC20ConversionProxy.transferFromWithReferenceAndFee( _to=0xC6C84554dD6006D3b6319094e635E9335F6A4683, _requestAmount=100000000, _path=[0x17B4158805772Ced11225E77339F90BeB5aAE968, 0x775EB53d00DD0Acd3EC1696472105d579B9b386b, 0xdAC17F958D2ee523a2206206994597C13D831ec7], _paymentReference=0x4E4869D108A33494, _feeAmount=0, _feeAddress=0x35d0e078755Cd84D3E0656cAaB417Dee1d7939c7, _maxToSpend=1090095, _maxRateTimespan=0 )
  • ChainlinkConversionPath.getRate( _path=[0x17B4158805772Ced11225E77339F90BeB5aAE968, 0x775EB53d00DD0Acd3EC1696472105d579B9b386b, 0xdAC17F958D2ee523a2206206994597C13D831ec7] ) => ( rate=10793022999669573, oldestRateTimestamp=1719927443, decimals=1000000000000000000 )
    • EACAggregatorProxy.STATICCALL( )
      • AccessControlledOffchainAggregator.STATICCALL( )
      • EACAggregatorProxy.STATICCALL( )
        • AccessControlledOffchainAggregator.STATICCALL( )
        • EACAggregatorProxy.STATICCALL( )
          • AccessControlledOffchainAggregator.STATICCALL( )
          • TetherToken.STATICCALL( )
          • EACAggregatorProxy.STATICCALL( )
            • AccessControlledOffchainAggregator.STATICCALL( )
            • EACAggregatorProxy.STATICCALL( )
              • AccessControlledOffchainAggregator.STATICCALL( )
              • EACAggregatorProxy.STATICCALL( )
                • AccessControlledOffchainAggregator.STATICCALL( )
                • ERC20FeeProxy.transferFromWithReferenceAndFee( _tokenAddress=0xdAC17F958D2ee523a2206206994597C13D831ec7, _to=0xC6C84554dD6006D3b6319094e635E9335F6A4683, _amount=1079302, _paymentReference=0x4E4869D108A33494, _feeAmount=0, _feeAddress=0x35d0e078755Cd84D3E0656cAaB417Dee1d7939c7 )
                  • TetherToken.transferFrom( _from=0x4E64C2d06d19D13061e62E291b2C4e9fe5679b93, _to=0xC6C84554dD6006D3b6319094e635E9335F6A4683, _value=1079302 )
                    File 1 of 8: ERC20ConversionProxy
                    // SPDX-License-Identifier: MIT
                    pragma solidity ^0.5.0;
                    
                    
                    /**
                     * @dev Wrappers over Solidity's arithmetic operations with added overflow
                     * checks.
                     *
                     * Arithmetic operations in Solidity wrap on overflow. This can easily result
                     * in bugs, because programmers usually assume that an overflow raises an
                     * error, which is the standard behavior in high level programming languages.
                     * `SafeMath` restores this intuition by reverting the transaction when an
                     * operation overflows.
                     *
                     * Using this library instead of the unchecked operations eliminates an entire
                     * class of bugs, so it's recommended to use it always.
                     */
                    library SafeMath {
                        /**
                         * @dev Returns the addition of two unsigned integers, reverting on
                         * overflow.
                         *
                         * Counterpart to Solidity's `+` operator.
                         *
                         * Requirements:
                         *
                         * - Addition cannot overflow.
                         */
                        function add(uint256 a, uint256 b) internal pure returns (uint256) {
                            uint256 c = a + b;
                            require(c >= a, "SafeMath: addition overflow");
                    
                            return c;
                        }
                    
                        /**
                         * @dev Returns the subtraction of two unsigned integers, reverting on
                         * overflow (when the result is negative).
                         *
                         * Counterpart to Solidity's `-` operator.
                         *
                         * Requirements:
                         *
                         * - Subtraction cannot overflow.
                         */
                        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                            return sub(a, b, "SafeMath: subtraction overflow");
                        }
                    
                        /**
                         * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
                         * overflow (when the result is negative).
                         *
                         * Counterpart to Solidity's `-` operator.
                         *
                         * Requirements:
                         *
                         * - Subtraction cannot overflow.
                         */
                        function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                            require(b <= a, errorMessage);
                            uint256 c = a - b;
                    
                            return c;
                        }
                    
                        /**
                         * @dev Returns the multiplication of two unsigned integers, reverting on
                         * overflow.
                         *
                         * Counterpart to Solidity's `*` operator.
                         *
                         * Requirements:
                         *
                         * - Multiplication cannot 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-contracts/pull/522
                            if (a == 0) {
                                return 0;
                            }
                    
                            uint256 c = a * b;
                            require(c / a == b, "SafeMath: multiplication overflow");
                    
                            return c;
                        }
                    
                        /**
                         * @dev Returns the integer division of two unsigned integers. Reverts on
                         * division by zero. The result is rounded towards zero.
                         *
                         * Counterpart to Solidity's `/` operator. Note: this function uses a
                         * `revert` opcode (which leaves remaining gas untouched) while Solidity
                         * uses an invalid opcode to revert (consuming all remaining gas).
                         *
                         * Requirements:
                         *
                         * - The divisor cannot be zero.
                         */
                        function div(uint256 a, uint256 b) internal pure returns (uint256) {
                            return div(a, b, "SafeMath: division by zero");
                        }
                    
                        /**
                         * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
                         * division by zero. The result is rounded towards zero.
                         *
                         * Counterpart to Solidity's `/` operator. Note: this function uses a
                         * `revert` opcode (which leaves remaining gas untouched) while Solidity
                         * uses an invalid opcode to revert (consuming all remaining gas).
                         *
                         * Requirements:
                         *
                         * - The divisor cannot be zero.
                         */
                        function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                            require(b > 0, errorMessage);
                            uint256 c = a / b;
                            // assert(a == b * c + a % b); // There is no case in which this doesn't hold
                    
                            return c;
                        }
                    
                        /**
                         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                         * Reverts when dividing by zero.
                         *
                         * Counterpart to Solidity's `%` operator. This function uses a `revert`
                         * opcode (which leaves remaining gas untouched) while Solidity uses an
                         * invalid opcode to revert (consuming all remaining gas).
                         *
                         * Requirements:
                         *
                         * - The divisor cannot be zero.
                         */
                        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                            return mod(a, b, "SafeMath: modulo by zero");
                        }
                    
                        /**
                         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                         * Reverts with custom message when dividing by zero.
                         *
                         * Counterpart to Solidity's `%` operator. This function uses a `revert`
                         * opcode (which leaves remaining gas untouched) while Solidity uses an
                         * invalid opcode to revert (consuming all remaining gas).
                         *
                         * Requirements:
                         *
                         * - The divisor cannot be zero.
                         */
                        function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                            require(b != 0, errorMessage);
                            return a % b;
                        }
                    }
                    
                    /**
                     * @title Roles
                     * @dev Library for managing addresses assigned to a Role.
                     */
                    library Roles {
                        struct Role {
                            mapping (address => bool) bearer;
                        }
                    
                        /**
                         * @dev give an account access to this role
                         */
                        function add(Role storage role, address account) internal {
                            require(account != address(0));
                            require(!has(role, account));
                    
                            role.bearer[account] = true;
                        }
                    
                        /**
                         * @dev remove an account's access to this role
                         */
                        function remove(Role storage role, address account) internal {
                            require(account != address(0));
                            require(has(role, account));
                    
                            role.bearer[account] = false;
                        }
                    
                        /**
                         * @dev check if an account has this role
                         * @return bool
                         */
                        function has(Role storage role, address account) internal view returns (bool) {
                            require(account != address(0));
                            return role.bearer[account];
                        }
                    }
                    
                    /**
                     * @title ChainlinkConversionPath
                     *
                     * @notice ChainlinkConversionPath is a contract allowing to compute conversion rate from a Chainlink aggretators
                     */
                    interface ChainlinkConversionPath {
                    
                    
                      /**
                      * @notice Computes the rate from a list of conversion
                      * @param _path List of addresses representing the currencies for the conversions
                      * @return rate the rate
                      * @return oldestRateTimestamp he oldest timestamp of the path
                      * @return decimals of the conversion rate
                      */
                      function getRate(
                        address[] calldata _path
                      )
                        external
                        view
                        returns (uint256 rate, uint256 oldestRateTimestamp, uint256 decimals);
                    }
                    
                    interface IERC20FeeProxy {
                      event TransferWithReferenceAndFee(
                        address tokenAddress,
                        address to,
                        uint256 amount,
                        bytes indexed paymentReference,
                        uint256 feeAmount,
                        address feeAddress
                      );
                    
                      function transferFromWithReferenceAndFee(
                        address _tokenAddress,
                        address _to,
                        uint256 _amount,
                        bytes calldata _paymentReference,
                        uint256 _feeAmount,
                        address _feeAddress
                        ) external;
                    }
                    
                    
                    /**
                     * @title ERC20ConversionProxy
                     */
                    contract ERC20ConversionProxy {
                      using SafeMath for uint256;
                    
                      address public paymentProxy;
                      ChainlinkConversionPath public chainlinkConversionPath;
                    
                      constructor(address _paymentProxyAddress, address _chainlinkConversionPathAddress) public {
                        paymentProxy = _paymentProxyAddress;
                        chainlinkConversionPath = ChainlinkConversionPath(_chainlinkConversionPathAddress);
                      }
                    
                      // Event to declare a transfer with a reference
                      event TransferWithConversionAndReference(
                        uint256 amount,
                        address currency,
                        bytes indexed paymentReference,
                        uint256 feeAmount,
                        uint256 maxRateTimespan
                      );
                    
                      /**
                       * @notice Performs an ERC20 token transfer with a reference computing the amount based on a fiat amount
                       * @param _to Transfer recipient
                       * @param _requestAmount request amount
                       * @param _path conversion path
                       * @param _paymentReference Reference of the payment related
                       * @param _feeAmount The amount of the payment fee
                       * @param _feeAddress The fee recipient
                       * @param _maxToSpend amount max that we can spend on the behalf of the user
                       * @param _maxRateTimespan max time span with the oldestrate, ignored if zero
                       */
                      function transferFromWithReferenceAndFee(
                        address _to,
                        uint256 _requestAmount,
                        address[] calldata _path,
                        bytes calldata _paymentReference,
                        uint256 _feeAmount,
                        address _feeAddress,
                        uint256 _maxToSpend,
                        uint256 _maxRateTimespan
                      ) external
                      {
                        (uint256 amountToPay, uint256 amountToPayInFees) = getConversions(_path, _requestAmount, _feeAmount, _maxRateTimespan);
                    
                        require(amountToPay.add(amountToPayInFees) <= _maxToSpend, "Amount to pay is over the user limit");
                    
                        // Pay the request and fees
                        (bool status, ) = paymentProxy.delegatecall(
                          abi.encodeWithSignature(
                            "transferFromWithReferenceAndFee(address,address,uint256,bytes,uint256,address)",
                            // payment currency
                            _path[_path.length - 1],
                            _to,
                            amountToPay,
                            _paymentReference,
                            amountToPayInFees,
                            _feeAddress
                          )
                        );
                        require(status, "transferFromWithReferenceAndFee failed");
                    
                        // Event to declare a transfer with a reference
                        emit TransferWithConversionAndReference(
                          _requestAmount,
                          // request currency
                          _path[0],
                          _paymentReference,
                          _feeAmount,
                          _maxRateTimespan
                        );
                      }
                    
                      function getConversions(
                        address[] memory _path,
                        uint256 _requestAmount,
                        uint256 _feeAmount,
                        uint256 _maxRateTimespan
                      ) internal
                        view
                        returns (uint256 amountToPay, uint256 amountToPayInFees)
                      {
                        (uint256 rate, uint256 oldestTimestampRate, uint256 decimals) = chainlinkConversionPath.getRate(_path);
                    
                        // Check rate timespan
                        require(_maxRateTimespan == 0 || block.timestamp.sub(oldestTimestampRate) <= _maxRateTimespan, "aggregator rate is outdated");
                        
                        // Get the amount to pay in the crypto currency chosen
                        amountToPay = _requestAmount.mul(rate).div(decimals);
                        amountToPayInFees = _feeAmount.mul(rate).div(decimals);
                      }
                    }

                    File 2 of 8: TetherToken
                    pragma solidity ^0.4.17;
                    
                    /**
                     * @title SafeMath
                     * @dev Math operations with safety checks that throw on error
                     */
                    library SafeMath {
                        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                            if (a == 0) {
                                return 0;
                            }
                            uint256 c = a * b;
                            assert(c / a == b);
                            return c;
                        }
                    
                        function div(uint256 a, uint256 b) internal pure returns (uint256) {
                            // assert(b > 0); // Solidity automatically throws when dividing by 0
                            uint256 c = a / b;
                            // assert(a == b * c + a % b); // There is no case in which this doesn't hold
                            return c;
                        }
                    
                        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                            assert(b <= a);
                            return a - b;
                        }
                    
                        function add(uint256 a, uint256 b) internal pure returns (uint256) {
                            uint256 c = a + b;
                            assert(c >= a);
                            return c;
                        }
                    }
                    
                    /**
                     * @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 public owner;
                    
                        /**
                          * @dev The Ownable constructor sets the original `owner` of the contract to the sender
                          * account.
                          */
                        function Ownable() public {
                            owner = msg.sender;
                        }
                    
                        /**
                          * @dev Throws if called by any account other than the owner.
                          */
                        modifier onlyOwner() {
                            require(msg.sender == owner);
                            _;
                        }
                    
                        /**
                        * @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 {
                            if (newOwner != address(0)) {
                                owner = newOwner;
                            }
                        }
                    
                    }
                    
                    /**
                     * @title ERC20Basic
                     * @dev Simpler version of ERC20 interface
                     * @dev see https://github.com/ethereum/EIPs/issues/20
                     */
                    contract ERC20Basic {
                        uint public _totalSupply;
                        function totalSupply() public constant returns (uint);
                        function balanceOf(address who) public constant returns (uint);
                        function transfer(address to, uint value) public;
                        event Transfer(address indexed from, address indexed to, uint value);
                    }
                    
                    /**
                     * @title ERC20 interface
                     * @dev see https://github.com/ethereum/EIPs/issues/20
                     */
                    contract ERC20 is ERC20Basic {
                        function allowance(address owner, address spender) public constant returns (uint);
                        function transferFrom(address from, address to, uint value) public;
                        function approve(address spender, uint value) public;
                        event Approval(address indexed owner, address indexed spender, uint value);
                    }
                    
                    /**
                     * @title Basic token
                     * @dev Basic version of StandardToken, with no allowances.
                     */
                    contract BasicToken is Ownable, ERC20Basic {
                        using SafeMath for uint;
                    
                        mapping(address => uint) public balances;
                    
                        // additional variables for use if transaction fees ever became necessary
                        uint public basisPointsRate = 0;
                        uint public maximumFee = 0;
                    
                        /**
                        * @dev Fix for the ERC20 short address attack.
                        */
                        modifier onlyPayloadSize(uint size) {
                            require(!(msg.data.length < size + 4));
                            _;
                        }
                    
                        /**
                        * @dev transfer token for a specified address
                        * @param _to The address to transfer to.
                        * @param _value The amount to be transferred.
                        */
                        function transfer(address _to, uint _value) public onlyPayloadSize(2 * 32) {
                            uint fee = (_value.mul(basisPointsRate)).div(10000);
                            if (fee > maximumFee) {
                                fee = maximumFee;
                            }
                            uint sendAmount = _value.sub(fee);
                            balances[msg.sender] = balances[msg.sender].sub(_value);
                            balances[_to] = balances[_to].add(sendAmount);
                            if (fee > 0) {
                                balances[owner] = balances[owner].add(fee);
                                Transfer(msg.sender, owner, fee);
                            }
                            Transfer(msg.sender, _to, sendAmount);
                        }
                    
                        /**
                        * @dev Gets the balance of the specified address.
                        * @param _owner The address to query the the balance of.
                        * @return An uint representing the amount owned by the passed address.
                        */
                        function balanceOf(address _owner) public constant returns (uint balance) {
                            return balances[_owner];
                        }
                    
                    }
                    
                    /**
                     * @title Standard ERC20 token
                     *
                     * @dev Implementation of the basic standard token.
                     * @dev https://github.com/ethereum/EIPs/issues/20
                     * @dev Based oncode by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
                     */
                    contract StandardToken is BasicToken, ERC20 {
                    
                        mapping (address => mapping (address => uint)) public allowed;
                    
                        uint public constant MAX_UINT = 2**256 - 1;
                    
                        /**
                        * @dev Transfer tokens from one address to another
                        * @param _from address The address which you want to send tokens from
                        * @param _to address The address which you want to transfer to
                        * @param _value uint the amount of tokens to be transferred
                        */
                        function transferFrom(address _from, address _to, uint _value) public onlyPayloadSize(3 * 32) {
                            var _allowance = allowed[_from][msg.sender];
                    
                            // Check is not needed because sub(_allowance, _value) will already throw if this condition is not met
                            // if (_value > _allowance) throw;
                    
                            uint fee = (_value.mul(basisPointsRate)).div(10000);
                            if (fee > maximumFee) {
                                fee = maximumFee;
                            }
                            if (_allowance < MAX_UINT) {
                                allowed[_from][msg.sender] = _allowance.sub(_value);
                            }
                            uint sendAmount = _value.sub(fee);
                            balances[_from] = balances[_from].sub(_value);
                            balances[_to] = balances[_to].add(sendAmount);
                            if (fee > 0) {
                                balances[owner] = balances[owner].add(fee);
                                Transfer(_from, owner, fee);
                            }
                            Transfer(_from, _to, sendAmount);
                        }
                    
                        /**
                        * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
                        * @param _spender The address which will spend the funds.
                        * @param _value The amount of tokens to be spent.
                        */
                        function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
                    
                            // To change the approve amount you first have to reduce the addresses`
                            //  allowance to zero by calling `approve(_spender, 0)` if it is not
                            //  already 0 to mitigate the race condition described here:
                            //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                            require(!((_value != 0) && (allowed[msg.sender][_spender] != 0)));
                    
                            allowed[msg.sender][_spender] = _value;
                            Approval(msg.sender, _spender, _value);
                        }
                    
                        /**
                        * @dev Function to check the amount of tokens than an owner allowed to a spender.
                        * @param _owner address The address which owns the funds.
                        * @param _spender address The address which will spend the funds.
                        * @return A uint specifying the amount of tokens still available for the spender.
                        */
                        function allowance(address _owner, address _spender) public constant returns (uint remaining) {
                            return allowed[_owner][_spender];
                        }
                    
                    }
                    
                    
                    /**
                     * @title Pausable
                     * @dev Base contract which allows children to implement an emergency stop mechanism.
                     */
                    contract Pausable is Ownable {
                      event Pause();
                      event Unpause();
                    
                      bool public paused = false;
                    
                    
                      /**
                       * @dev Modifier to make a function callable only when the contract is not paused.
                       */
                      modifier whenNotPaused() {
                        require(!paused);
                        _;
                      }
                    
                      /**
                       * @dev Modifier to make a function callable only when the contract is paused.
                       */
                      modifier whenPaused() {
                        require(paused);
                        _;
                      }
                    
                      /**
                       * @dev called by the owner to pause, triggers stopped state
                       */
                      function pause() onlyOwner whenNotPaused public {
                        paused = true;
                        Pause();
                      }
                    
                      /**
                       * @dev called by the owner to unpause, returns to normal state
                       */
                      function unpause() onlyOwner whenPaused public {
                        paused = false;
                        Unpause();
                      }
                    }
                    
                    contract BlackList is Ownable, BasicToken {
                    
                        /////// Getters to allow the same blacklist to be used also by other contracts (including upgraded Tether) ///////
                        function getBlackListStatus(address _maker) external constant returns (bool) {
                            return isBlackListed[_maker];
                        }
                    
                        function getOwner() external constant returns (address) {
                            return owner;
                        }
                    
                        mapping (address => bool) public isBlackListed;
                        
                        function addBlackList (address _evilUser) public onlyOwner {
                            isBlackListed[_evilUser] = true;
                            AddedBlackList(_evilUser);
                        }
                    
                        function removeBlackList (address _clearedUser) public onlyOwner {
                            isBlackListed[_clearedUser] = false;
                            RemovedBlackList(_clearedUser);
                        }
                    
                        function destroyBlackFunds (address _blackListedUser) public onlyOwner {
                            require(isBlackListed[_blackListedUser]);
                            uint dirtyFunds = balanceOf(_blackListedUser);
                            balances[_blackListedUser] = 0;
                            _totalSupply -= dirtyFunds;
                            DestroyedBlackFunds(_blackListedUser, dirtyFunds);
                        }
                    
                        event DestroyedBlackFunds(address _blackListedUser, uint _balance);
                    
                        event AddedBlackList(address _user);
                    
                        event RemovedBlackList(address _user);
                    
                    }
                    
                    contract UpgradedStandardToken is StandardToken{
                        // those methods are called by the legacy contract
                        // and they must ensure msg.sender to be the contract address
                        function transferByLegacy(address from, address to, uint value) public;
                        function transferFromByLegacy(address sender, address from, address spender, uint value) public;
                        function approveByLegacy(address from, address spender, uint value) public;
                    }
                    
                    contract TetherToken is Pausable, StandardToken, BlackList {
                    
                        string public name;
                        string public symbol;
                        uint public decimals;
                        address public upgradedAddress;
                        bool public deprecated;
                    
                        //  The contract can be initialized with a number of tokens
                        //  All the tokens are deposited to the owner address
                        //
                        // @param _balance Initial supply of the contract
                        // @param _name Token Name
                        // @param _symbol Token symbol
                        // @param _decimals Token decimals
                        function TetherToken(uint _initialSupply, string _name, string _symbol, uint _decimals) public {
                            _totalSupply = _initialSupply;
                            name = _name;
                            symbol = _symbol;
                            decimals = _decimals;
                            balances[owner] = _initialSupply;
                            deprecated = false;
                        }
                    
                        // Forward ERC20 methods to upgraded contract if this one is deprecated
                        function transfer(address _to, uint _value) public whenNotPaused {
                            require(!isBlackListed[msg.sender]);
                            if (deprecated) {
                                return UpgradedStandardToken(upgradedAddress).transferByLegacy(msg.sender, _to, _value);
                            } else {
                                return super.transfer(_to, _value);
                            }
                        }
                    
                        // Forward ERC20 methods to upgraded contract if this one is deprecated
                        function transferFrom(address _from, address _to, uint _value) public whenNotPaused {
                            require(!isBlackListed[_from]);
                            if (deprecated) {
                                return UpgradedStandardToken(upgradedAddress).transferFromByLegacy(msg.sender, _from, _to, _value);
                            } else {
                                return super.transferFrom(_from, _to, _value);
                            }
                        }
                    
                        // Forward ERC20 methods to upgraded contract if this one is deprecated
                        function balanceOf(address who) public constant returns (uint) {
                            if (deprecated) {
                                return UpgradedStandardToken(upgradedAddress).balanceOf(who);
                            } else {
                                return super.balanceOf(who);
                            }
                        }
                    
                        // Forward ERC20 methods to upgraded contract if this one is deprecated
                        function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
                            if (deprecated) {
                                return UpgradedStandardToken(upgradedAddress).approveByLegacy(msg.sender, _spender, _value);
                            } else {
                                return super.approve(_spender, _value);
                            }
                        }
                    
                        // Forward ERC20 methods to upgraded contract if this one is deprecated
                        function allowance(address _owner, address _spender) public constant returns (uint remaining) {
                            if (deprecated) {
                                return StandardToken(upgradedAddress).allowance(_owner, _spender);
                            } else {
                                return super.allowance(_owner, _spender);
                            }
                        }
                    
                        // deprecate current contract in favour of a new one
                        function deprecate(address _upgradedAddress) public onlyOwner {
                            deprecated = true;
                            upgradedAddress = _upgradedAddress;
                            Deprecate(_upgradedAddress);
                        }
                    
                        // deprecate current contract if favour of a new one
                        function totalSupply() public constant returns (uint) {
                            if (deprecated) {
                                return StandardToken(upgradedAddress).totalSupply();
                            } else {
                                return _totalSupply;
                            }
                        }
                    
                        // Issue a new amount of tokens
                        // these tokens are deposited into the owner address
                        //
                        // @param _amount Number of tokens to be issued
                        function issue(uint amount) public onlyOwner {
                            require(_totalSupply + amount > _totalSupply);
                            require(balances[owner] + amount > balances[owner]);
                    
                            balances[owner] += amount;
                            _totalSupply += amount;
                            Issue(amount);
                        }
                    
                        // Redeem tokens.
                        // These tokens are withdrawn from the owner address
                        // if the balance must be enough to cover the redeem
                        // or the call will fail.
                        // @param _amount Number of tokens to be issued
                        function redeem(uint amount) public onlyOwner {
                            require(_totalSupply >= amount);
                            require(balances[owner] >= amount);
                    
                            _totalSupply -= amount;
                            balances[owner] -= amount;
                            Redeem(amount);
                        }
                    
                        function setParams(uint newBasisPoints, uint newMaxFee) public onlyOwner {
                            // Ensure transparency by hardcoding limit beyond which fees can never be added
                            require(newBasisPoints < 20);
                            require(newMaxFee < 50);
                    
                            basisPointsRate = newBasisPoints;
                            maximumFee = newMaxFee.mul(10**decimals);
                    
                            Params(basisPointsRate, maximumFee);
                        }
                    
                        // Called when new token are issued
                        event Issue(uint amount);
                    
                        // Called when tokens are redeemed
                        event Redeem(uint amount);
                    
                        // Called when contract is deprecated
                        event Deprecate(address newAddress);
                    
                        // Called if contract ever adds fees
                        event Params(uint feeBasisPoints, uint maxFee);
                    }

                    File 3 of 8: ChainlinkConversionPath
                    // SPDX-License-Identifier: MIT
                    pragma solidity >=0.4.25 <0.7.0;
                    
                    /**
                     * @dev Wrappers over Solidity's arithmetic operations with added overflow
                     * checks.
                     *
                     * Arithmetic operations in Solidity wrap on overflow. This can easily result
                     * in bugs, because programmers usually assume that an overflow raises an
                     * error, which is the standard behavior in high level programming languages.
                     * `SafeMath` restores this intuition by reverting the transaction when an
                     * operation overflows.
                     *
                     * Using this library instead of the unchecked operations eliminates an entire
                     * class of bugs, so it's recommended to use it always.
                     */
                    library SafeMath {
                        /**
                         * @dev Returns the addition of two unsigned integers, reverting on
                         * overflow.
                         *
                         * Counterpart to Solidity's `+` operator.
                         *
                         * Requirements:
                         *
                         * - Addition cannot overflow.
                         */
                        function add(uint256 a, uint256 b) internal pure returns (uint256) {
                            uint256 c = a + b;
                            require(c >= a, "SafeMath: addition overflow");
                    
                            return c;
                        }
                    
                        /**
                         * @dev Returns the subtraction of two unsigned integers, reverting on
                         * overflow (when the result is negative).
                         *
                         * Counterpart to Solidity's `-` operator.
                         *
                         * Requirements:
                         *
                         * - Subtraction cannot overflow.
                         */
                        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                            return sub(a, b, "SafeMath: subtraction overflow");
                        }
                    
                        /**
                         * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
                         * overflow (when the result is negative).
                         *
                         * Counterpart to Solidity's `-` operator.
                         *
                         * Requirements:
                         *
                         * - Subtraction cannot overflow.
                         */
                        function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                            require(b <= a, errorMessage);
                            uint256 c = a - b;
                    
                            return c;
                        }
                    
                        /**
                         * @dev Returns the multiplication of two unsigned integers, reverting on
                         * overflow.
                         *
                         * Counterpart to Solidity's `*` operator.
                         *
                         * Requirements:
                         *
                         * - Multiplication cannot 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-contracts/pull/522
                            if (a == 0) {
                                return 0;
                            }
                    
                            uint256 c = a * b;
                            require(c / a == b, "SafeMath: multiplication overflow");
                    
                            return c;
                        }
                    
                        /**
                         * @dev Returns the integer division of two unsigned integers. Reverts on
                         * division by zero. The result is rounded towards zero.
                         *
                         * Counterpart to Solidity's `/` operator. Note: this function uses a
                         * `revert` opcode (which leaves remaining gas untouched) while Solidity
                         * uses an invalid opcode to revert (consuming all remaining gas).
                         *
                         * Requirements:
                         *
                         * - The divisor cannot be zero.
                         */
                        function div(uint256 a, uint256 b) internal pure returns (uint256) {
                            return div(a, b, "SafeMath: division by zero");
                        }
                    
                        /**
                         * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
                         * division by zero. The result is rounded towards zero.
                         *
                         * Counterpart to Solidity's `/` operator. Note: this function uses a
                         * `revert` opcode (which leaves remaining gas untouched) while Solidity
                         * uses an invalid opcode to revert (consuming all remaining gas).
                         *
                         * Requirements:
                         *
                         * - The divisor cannot be zero.
                         */
                        function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                            require(b > 0, errorMessage);
                            uint256 c = a / b;
                            // assert(a == b * c + a % b); // There is no case in which this doesn't hold
                    
                            return c;
                        }
                    
                        /**
                         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                         * Reverts when dividing by zero.
                         *
                         * Counterpart to Solidity's `%` operator. This function uses a `revert`
                         * opcode (which leaves remaining gas untouched) while Solidity uses an
                         * invalid opcode to revert (consuming all remaining gas).
                         *
                         * Requirements:
                         *
                         * - The divisor cannot be zero.
                         */
                        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                            return mod(a, b, "SafeMath: modulo by zero");
                        }
                    
                        /**
                         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                         * Reverts with custom message when dividing by zero.
                         *
                         * Counterpart to Solidity's `%` operator. This function uses a `revert`
                         * opcode (which leaves remaining gas untouched) while Solidity uses an
                         * invalid opcode to revert (consuming all remaining gas).
                         *
                         * Requirements:
                         *
                         * - The divisor cannot be zero.
                         */
                        function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                            require(b != 0, errorMessage);
                            return a % b;
                        }
                    }
                    
                    /**
                     * @title Roles
                     * @dev Library for managing addresses assigned to a Role.
                     */
                    library Roles {
                        struct Role {
                            mapping (address => bool) bearer;
                        }
                    
                        /**
                         * @dev give an account access to this role
                         */
                        function add(Role storage role, address account) internal {
                            require(account != address(0));
                            require(!has(role, account));
                    
                            role.bearer[account] = true;
                        }
                    
                        /**
                         * @dev remove an account's access to this role
                         */
                        function remove(Role storage role, address account) internal {
                            require(account != address(0));
                            require(has(role, account));
                    
                            role.bearer[account] = false;
                        }
                    
                        /**
                         * @dev check if an account has this role
                         * @return bool
                         */
                        function has(Role storage role, address account) internal view returns (bool) {
                            require(account != address(0));
                            return role.bearer[account];
                        }
                    }
                    
                    
                    /**
                     * @title WhitelistAdminRole
                     * @dev WhitelistAdmins are responsible for assigning and removing Whitelisted accounts.
                     */
                    contract WhitelistAdminRole {
                        using Roles for Roles.Role;
                    
                        event WhitelistAdminAdded(address indexed account);
                        event WhitelistAdminRemoved(address indexed account);
                    
                        Roles.Role private _whitelistAdmins;
                    
                        constructor () internal {
                            _addWhitelistAdmin(msg.sender);
                        }
                    
                        modifier onlyWhitelistAdmin() {
                            require(isWhitelistAdmin(msg.sender));
                            _;
                        }
                    
                        function isWhitelistAdmin(address account) public view returns (bool) {
                            return _whitelistAdmins.has(account);
                        }
                    
                        function addWhitelistAdmin(address account) public onlyWhitelistAdmin {
                            _addWhitelistAdmin(account);
                        }
                    
                        function renounceWhitelistAdmin() public {
                            _removeWhitelistAdmin(msg.sender);
                        }
                    
                        function _addWhitelistAdmin(address account) internal {
                            _whitelistAdmins.add(account);
                            emit WhitelistAdminAdded(account);
                        }
                    
                        function _removeWhitelistAdmin(address account) internal {
                            _whitelistAdmins.remove(account);
                            emit WhitelistAdminRemoved(account);
                        }
                    }
                    
                    interface ERC20fraction {
                      function decimals() external view returns (uint8);
                    }
                    
                    interface AggregatorFraction {
                      function decimals() external view returns (uint8);
                      function latestAnswer() external view returns (int256);
                      function latestTimestamp() external view returns (uint256);
                    }
                    
                    
                    /**
                     * @title ChainlinkConversionPath
                     *
                     * @notice ChainlinkConversionPath is a contract computing currency conversion rates based on Chainlink aggretators
                     */
                    contract ChainlinkConversionPath is WhitelistAdminRole {
                      using SafeMath for uint256;
                    
                      uint constant DECIMALS = 1e18;
                    
                      // Mapping of Chainlink aggregators (input currency => output currency => contract address)
                      // input & output currencies are the addresses of the ERC20 contracts OR the sha3("currency code")
                      mapping(address => mapping(address => address)) public allAggregators;
                    
                      // declare a new aggregator
                      event AggregatorUpdated(address _input, address _output, address _aggregator);
                    
                      /**
                        * @notice Update an aggregator
                        * @param _input address representing the input currency
                        * @param _output address representing the output currency
                        * @param _aggregator address of the aggregator contract
                      */
                      function updateAggregator(address _input, address _output, address _aggregator)
                        external
                        onlyWhitelistAdmin
                      {
                        allAggregators[_input][_output] = _aggregator;
                        emit AggregatorUpdated(_input, _output, _aggregator);
                      }
                    
                      /**
                        * @notice Update a list of aggregators
                        * @param _inputs list of addresses representing the input currencies
                        * @param _outputs list of addresses representing the output currencies
                        * @param _aggregators list of addresses of the aggregator contracts
                      */
                      function updateAggregatorsList(address[] calldata _inputs, address[] calldata _outputs, address[] calldata _aggregators)
                        external
                        onlyWhitelistAdmin
                      {
                        require(_inputs.length == _outputs.length, "arrays must have the same length");
                        require(_inputs.length == _aggregators.length, "arrays must have the same length");
                    
                        // For every conversions of the path
                        for (uint i; i < _inputs.length; i++) {
                          allAggregators[_inputs[i]][_outputs[i]] = _aggregators[i];
                          emit AggregatorUpdated(_inputs[i], _outputs[i], _aggregators[i]);
                        }
                      }
                    
                      /**
                      * @notice Computes the conversion of an amount through a list of intermediate conversions
                      * @param _amountIn Amount to convert
                      * @param _path List of addresses representing the currencies for the intermediate conversions
                      * @return result The result after all the conversions
                      * @return oldestRateTimestamp The oldest timestamp of the path
                      */
                      function getConversion(
                        uint256 _amountIn,
                        address[] calldata _path
                      )
                        external
                        view
                        returns (uint256 result, uint256 oldestRateTimestamp)
                      {
                        (uint256 rate, uint256 timestamp, uint256 decimals) = getRate(_path);
                    
                        // initialize the result
                        result = _amountIn.mul(rate).div(decimals);
                    
                        oldestRateTimestamp = timestamp;
                      }
                    
                      /**
                      * @notice Computes the conversion rate from a list of currencies
                      * @param _path List of addresses representing the currencies for the conversions
                      * @return rate The rate
                      * @return oldestRateTimestamp The oldest timestamp of the path
                      * @return decimals of the conversion rate
                      */
                      function getRate(
                        address[] memory _path
                      )
                        public
                        view
                        returns (uint256 rate, uint256 oldestRateTimestamp, uint256 decimals)
                      {
                        // initialize the result with 18 decimals (for more precision)
                        rate = DECIMALS;
                        decimals = DECIMALS;
                        oldestRateTimestamp = block.timestamp;
                    
                        // For every conversion of the path
                        for (uint i; i < _path.length - 1; i++) {
                          (AggregatorFraction aggregator, bool reverseAggregator, uint256 decimalsInput, uint256 decimalsOutput) = getAggregatorAndDecimals(_path[i], _path[i + 1]);
                    
                          // store the latest timestamp of the path
                          uint256 currentTimestamp = aggregator.latestTimestamp();
                          if (currentTimestamp < oldestRateTimestamp) {
                            oldestRateTimestamp = currentTimestamp;
                          }
                    
                          // get the rate of the current step
                          uint256 currentRate = uint256(aggregator.latestAnswer());
                          // get the number of decimals of the current rate
                          uint256 decimalsAggregator = uint256(aggregator.decimals());
                    
                          // mul with the difference of decimals before the current rate computation (for more precision)
                          if (decimalsAggregator > decimalsInput) {
                            rate = rate.mul(10**(decimalsAggregator-decimalsInput));
                          }
                          if (decimalsAggregator < decimalsOutput) {
                            rate = rate.mul(10**(decimalsOutput-decimalsAggregator));
                          }
                    
                          // Apply the current rate (if path uses an aggregator in the reverse way, div instead of mul)
                          if (reverseAggregator) {
                            rate = rate.mul(10**decimalsAggregator).div(currentRate);
                          } else {
                            rate = rate.mul(currentRate).div(10**decimalsAggregator);
                          }
                    
                          // div with the difference of decimals AFTER the current rate computation (for more precision)
                          if (decimalsAggregator < decimalsInput) {
                            rate = rate.div(10**(decimalsInput-decimalsAggregator));
                          }
                          if (decimalsAggregator > decimalsOutput) {
                            rate = rate.div(10**(decimalsAggregator-decimalsOutput));
                          }
                        }
                      }
                    
                      /**
                      * @notice Gets aggregators and decimals of two currencies
                      * @param _input input Address
                      * @param _output output Address
                      * @return aggregator to get the rate between the two currencies
                      * @return reverseAggregator true if the aggregator returned give the rate from _output to _input
                      * @return decimalsInput decimals of _input
                      * @return decimalsOutput decimals of _output
                      */
                      function getAggregatorAndDecimals(address _input, address _output)
                        private
                        view
                        returns (AggregatorFraction aggregator, bool reverseAggregator, uint256 decimalsInput, uint256 decimalsOutput)
                      {
                        // Try to get the right aggregator for the conversion
                        aggregator = AggregatorFraction(allAggregators[_input][_output]);
                        reverseAggregator = false;
                    
                        // if no aggregator found we try to find an aggregator in the reverse way
                        if (address(aggregator) == address(0x00)) {
                          aggregator = AggregatorFraction(allAggregators[_output][_input]);
                          reverseAggregator = true;
                        }
                    
                        require(address(aggregator) != address(0x00), "No aggregator found");
                    
                        // get the decimals for the two currencies
                        decimalsInput = getDecimals(_input);
                        decimalsOutput = getDecimals(_output);
                      }
                    
                      /**
                      * @notice Gets decimals from an address currency
                      * @param _addr address to check
                      * @return decimals number of decimals
                      */
                      function getDecimals(address _addr)
                        private
                        view
                        returns (uint256 decimals)
                      {
                        // by default we assume it is FIAT so 8 decimals
                        decimals = 8;
                        // if address is the hash of the ETH currency
                        if (_addr == address(0xF5AF88e117747e87fC5929F2ff87221B1447652E)) {
                          decimals = 18;
                        } else if (isContract(_addr)) {
                          // otherwise, we get the decimals from the erc20 directly
                          decimals = ERC20fraction(_addr).decimals();
                        }
                      }
                    
                      /**
                      * @notice Checks if an address is a contract
                      * @param _addr Address to check
                      * @return true if the address hosts a contract, false otherwise
                      */
                      function isContract(address _addr)
                        private
                        view
                        returns (bool)
                      {
                        uint32 size;
                        // solium-disable security/no-inline-assembly
                        assembly {
                          size := extcodesize(_addr)
                        }
                        return (size > 0);
                      }
                    }

                    File 4 of 8: EACAggregatorProxy
                    pragma solidity 0.6.6;
                    
                    
                    /**
                     * @title The Owned contract
                     * @notice A contract with helpers for basic contract ownership.
                     */
                    contract Owned {
                    
                      address payable public owner;
                      address private pendingOwner;
                    
                      event OwnershipTransferRequested(
                        address indexed from,
                        address indexed to
                      );
                      event OwnershipTransferred(
                        address indexed from,
                        address indexed to
                      );
                    
                      constructor() public {
                        owner = msg.sender;
                      }
                    
                      /**
                       * @dev Allows an owner to begin transferring ownership to a new address,
                       * pending.
                       */
                      function transferOwnership(address _to)
                        external
                        onlyOwner()
                      {
                        pendingOwner = _to;
                    
                        emit OwnershipTransferRequested(owner, _to);
                      }
                    
                      /**
                       * @dev Allows an ownership transfer to be completed by the recipient.
                       */
                      function acceptOwnership()
                        external
                      {
                        require(msg.sender == pendingOwner, "Must be proposed owner");
                    
                        address oldOwner = owner;
                        owner = msg.sender;
                        pendingOwner = address(0);
                    
                        emit OwnershipTransferred(oldOwner, msg.sender);
                      }
                    
                      /**
                       * @dev Reverts if called by anyone other than the contract owner.
                       */
                      modifier onlyOwner() {
                        require(msg.sender == owner, "Only callable by owner");
                        _;
                      }
                    
                    }
                    
                    interface AggregatorInterface {
                      function latestAnswer() external view returns (int256);
                      function latestTimestamp() external view returns (uint256);
                      function latestRound() external view returns (uint256);
                      function getAnswer(uint256 roundId) external view returns (int256);
                      function getTimestamp(uint256 roundId) external view returns (uint256);
                    
                      event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);
                      event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
                    }
                    
                    interface AggregatorV3Interface {
                    
                      function decimals() external view returns (uint8);
                      function description() external view returns (string memory);
                      function version() external view returns (uint256);
                    
                      // getRoundData and latestRoundData should both raise "No data present"
                      // if they do not have data to report, instead of returning unset values
                      // which could be misinterpreted as actual reported values.
                      function getRoundData(uint80 _roundId)
                        external
                        view
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        );
                      function latestRoundData()
                        external
                        view
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        );
                    
                    }
                    
                    interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface
                    {
                    }
                    
                    /**
                     * @title A trusted proxy for updating where current answers are read from
                     * @notice This contract provides a consistent address for the
                     * CurrentAnwerInterface but delegates where it reads from to the owner, who is
                     * trusted to update it.
                     */
                    contract AggregatorProxy is AggregatorV2V3Interface, Owned {
                    
                      struct Phase {
                        uint16 id;
                        AggregatorV2V3Interface aggregator;
                      }
                      Phase private currentPhase;
                      AggregatorV2V3Interface public proposedAggregator;
                      mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators;
                    
                      uint256 constant private PHASE_OFFSET = 64;
                      uint256 constant private PHASE_SIZE = 16;
                      uint256 constant private MAX_ID = 2**(PHASE_OFFSET+PHASE_SIZE) - 1;
                    
                      constructor(address _aggregator) public Owned() {
                        setAggregator(_aggregator);
                      }
                    
                      /**
                       * @notice Reads the current answer from aggregator delegated to.
                       *
                       * @dev #[deprecated] Use latestRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended latestRoundData
                       * instead which includes better verification information.
                       */
                      function latestAnswer()
                        public
                        view
                        virtual
                        override
                        returns (int256 answer)
                      {
                        return currentPhase.aggregator.latestAnswer();
                      }
                    
                      /**
                       * @notice Reads the last updated height from aggregator delegated to.
                       *
                       * @dev #[deprecated] Use latestRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended latestRoundData
                       * instead which includes better verification information.
                       */
                      function latestTimestamp()
                        public
                        view
                        virtual
                        override
                        returns (uint256 updatedAt)
                      {
                        return currentPhase.aggregator.latestTimestamp();
                      }
                    
                      /**
                       * @notice get past rounds answers
                       * @param _roundId the answer number to retrieve the answer for
                       *
                       * @dev #[deprecated] Use getRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended getRoundData
                       * instead which includes better verification information.
                       */
                      function getAnswer(uint256 _roundId)
                        public
                        view
                        virtual
                        override
                        returns (int256 answer)
                      {
                        if (_roundId > MAX_ID) return 0;
                    
                        (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
                        AggregatorV2V3Interface aggregator = phaseAggregators[phaseId];
                        if (address(aggregator) == address(0)) return 0;
                    
                        return aggregator.getAnswer(aggregatorRoundId);
                      }
                    
                      /**
                       * @notice get block timestamp when an answer was last updated
                       * @param _roundId the answer number to retrieve the updated timestamp for
                       *
                       * @dev #[deprecated] Use getRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended getRoundData
                       * instead which includes better verification information.
                       */
                      function getTimestamp(uint256 _roundId)
                        public
                        view
                        virtual
                        override
                        returns (uint256 updatedAt)
                      {
                        if (_roundId > MAX_ID) return 0;
                    
                        (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
                        AggregatorV2V3Interface aggregator = phaseAggregators[phaseId];
                        if (address(aggregator) == address(0)) return 0;
                    
                        return aggregator.getTimestamp(aggregatorRoundId);
                      }
                    
                      /**
                       * @notice get the latest completed round where the answer was updated. This
                       * ID includes the proxy's phase, to make sure round IDs increase even when
                       * switching to a newly deployed aggregator.
                       *
                       * @dev #[deprecated] Use latestRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended latestRoundData
                       * instead which includes better verification information.
                       */
                      function latestRound()
                        public
                        view
                        virtual
                        override
                        returns (uint256 roundId)
                      {
                        Phase memory phase = currentPhase; // cache storage reads
                        return addPhase(phase.id, uint64(phase.aggregator.latestRound()));
                      }
                    
                      /**
                       * @notice get data about a round. Consumers are encouraged to check
                       * that they're receiving fresh data by inspecting the updatedAt and
                       * answeredInRound return values.
                       * Note that different underlying implementations of AggregatorV3Interface
                       * have slightly different semantics for some of the return values. Consumers
                       * should determine what implementations they expect to receive
                       * data from and validate that they can properly handle return data from all
                       * of them.
                       * @param _roundId the requested round ID as presented through the proxy, this
                       * is made up of the aggregator's round ID with the phase ID encoded in the
                       * two highest order bytes
                       * @return roundId is the round ID from the aggregator for which the data was
                       * retrieved combined with an phase to ensure that round IDs get larger as
                       * time moves forward.
                       * @return answer is the answer for the given round
                       * @return startedAt is the timestamp when the round was started.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @return updatedAt is the timestamp when the round last was updated (i.e.
                       * answer was last computed)
                       * @return answeredInRound is the round ID of the round in which the answer
                       * was computed.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @dev Note that answer and updatedAt may change between queries.
                       */
                      function getRoundData(uint80 _roundId)
                        public
                        view
                        virtual
                        override
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        )
                      {
                        (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
                    
                        (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 ansIn
                        ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId);
                    
                        return addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId);
                      }
                    
                      /**
                       * @notice get data about the latest round. Consumers are encouraged to check
                       * that they're receiving fresh data by inspecting the updatedAt and
                       * answeredInRound return values.
                       * Note that different underlying implementations of AggregatorV3Interface
                       * have slightly different semantics for some of the return values. Consumers
                       * should determine what implementations they expect to receive
                       * data from and validate that they can properly handle return data from all
                       * of them.
                       * @return roundId is the round ID from the aggregator for which the data was
                       * retrieved combined with an phase to ensure that round IDs get larger as
                       * time moves forward.
                       * @return answer is the answer for the given round
                       * @return startedAt is the timestamp when the round was started.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @return updatedAt is the timestamp when the round last was updated (i.e.
                       * answer was last computed)
                       * @return answeredInRound is the round ID of the round in which the answer
                       * was computed.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @dev Note that answer and updatedAt may change between queries.
                       */
                      function latestRoundData()
                        public
                        view
                        virtual
                        override
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        )
                      {
                        Phase memory current = currentPhase; // cache storage reads
                    
                        (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 ansIn
                        ) = current.aggregator.latestRoundData();
                    
                        return addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, current.id);
                      }
                    
                      /**
                       * @notice Used if an aggregator contract has been proposed.
                       * @param _roundId the round ID to retrieve the round data for
                       * @return roundId is the round ID for which data was retrieved
                       * @return answer is the answer for the given round
                       * @return startedAt is the timestamp when the round was started.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @return updatedAt is the timestamp when the round last was updated (i.e.
                       * answer was last computed)
                       * @return answeredInRound is the round ID of the round in which the answer
                       * was computed.
                      */
                      function proposedGetRoundData(uint80 _roundId)
                        public
                        view
                        virtual
                        hasProposal()
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        )
                      {
                        return proposedAggregator.getRoundData(_roundId);
                      }
                    
                      /**
                       * @notice Used if an aggregator contract has been proposed.
                       * @return roundId is the round ID for which data was retrieved
                       * @return answer is the answer for the given round
                       * @return startedAt is the timestamp when the round was started.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @return updatedAt is the timestamp when the round last was updated (i.e.
                       * answer was last computed)
                       * @return answeredInRound is the round ID of the round in which the answer
                       * was computed.
                      */
                      function proposedLatestRoundData()
                        public
                        view
                        virtual
                        hasProposal()
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        )
                      {
                        return proposedAggregator.latestRoundData();
                      }
                    
                      /**
                       * @notice returns the current phase's aggregator address.
                       */
                      function aggregator()
                        external
                        view
                        returns (address)
                      {
                        return address(currentPhase.aggregator);
                      }
                    
                      /**
                       * @notice returns the current phase's ID.
                       */
                      function phaseId()
                        external
                        view
                        returns (uint16)
                      {
                        return currentPhase.id;
                      }
                    
                      /**
                       * @notice represents the number of decimals the aggregator responses represent.
                       */
                      function decimals()
                        external
                        view
                        override
                        returns (uint8)
                      {
                        return currentPhase.aggregator.decimals();
                      }
                    
                      /**
                       * @notice the version number representing the type of aggregator the proxy
                       * points to.
                       */
                      function version()
                        external
                        view
                        override
                        returns (uint256)
                      {
                        return currentPhase.aggregator.version();
                      }
                    
                      /**
                       * @notice returns the description of the aggregator the proxy points to.
                       */
                      function description()
                        external
                        view
                        override
                        returns (string memory)
                      {
                        return currentPhase.aggregator.description();
                      }
                    
                      /**
                       * @notice Allows the owner to propose a new address for the aggregator
                       * @param _aggregator The new address for the aggregator contract
                       */
                      function proposeAggregator(address _aggregator)
                        external
                        onlyOwner()
                      {
                        proposedAggregator = AggregatorV2V3Interface(_aggregator);
                      }
                    
                      /**
                       * @notice Allows the owner to confirm and change the address
                       * to the proposed aggregator
                       * @dev Reverts if the given address doesn't match what was previously
                       * proposed
                       * @param _aggregator The new address for the aggregator contract
                       */
                      function confirmAggregator(address _aggregator)
                        external
                        onlyOwner()
                      {
                        require(_aggregator == address(proposedAggregator), "Invalid proposed aggregator");
                        delete proposedAggregator;
                        setAggregator(_aggregator);
                      }
                    
                    
                      /*
                       * Internal
                       */
                    
                      function setAggregator(address _aggregator)
                        internal
                      {
                        uint16 id = currentPhase.id + 1;
                        currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator));
                        phaseAggregators[id] = AggregatorV2V3Interface(_aggregator);
                      }
                    
                      function addPhase(
                        uint16 _phase,
                        uint64 _originalId
                      )
                        internal
                        view
                        returns (uint80)
                      {
                        return uint80(uint256(_phase) << PHASE_OFFSET | _originalId);
                      }
                    
                      function parseIds(
                        uint256 _roundId
                      )
                        internal
                        view
                        returns (uint16, uint64)
                      {
                        uint16 phaseId = uint16(_roundId >> PHASE_OFFSET);
                        uint64 aggregatorRoundId = uint64(_roundId);
                    
                        return (phaseId, aggregatorRoundId);
                      }
                    
                      function addPhaseIds(
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound,
                          uint16 phaseId
                      )
                        internal
                        view
                        returns (uint80, int256, uint256, uint256, uint80)
                      {
                        return (
                          addPhase(phaseId, uint64(roundId)),
                          answer,
                          startedAt,
                          updatedAt,
                          addPhase(phaseId, uint64(answeredInRound))
                        );
                      }
                    
                      /*
                       * Modifiers
                       */
                    
                      modifier hasProposal() {
                        require(address(proposedAggregator) != address(0), "No proposed aggregator present");
                        _;
                      }
                    
                    }
                    
                    interface AccessControllerInterface {
                      function hasAccess(address user, bytes calldata data) external view returns (bool);
                    }
                    
                    /**
                     * @title External Access Controlled Aggregator Proxy
                     * @notice A trusted proxy for updating where current answers are read from
                     * @notice This contract provides a consistent address for the
                     * Aggregator and AggregatorV3Interface but delegates where it reads from to the owner, who is
                     * trusted to update it.
                     * @notice Only access enabled addresses are allowed to access getters for
                     * aggregated answers and round information.
                     */
                    contract EACAggregatorProxy is AggregatorProxy {
                    
                      AccessControllerInterface public accessController;
                    
                      constructor(
                        address _aggregator,
                        address _accessController
                      )
                        public
                        AggregatorProxy(_aggregator)
                      {
                        setController(_accessController);
                      }
                    
                      /**
                       * @notice Allows the owner to update the accessController contract address.
                       * @param _accessController The new address for the accessController contract
                       */
                      function setController(address _accessController)
                        public
                        onlyOwner()
                      {
                        accessController = AccessControllerInterface(_accessController);
                      }
                    
                      /**
                       * @notice Reads the current answer from aggregator delegated to.
                       * @dev overridden function to add the checkAccess() modifier
                       *
                       * @dev #[deprecated] Use latestRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended latestRoundData
                       * instead which includes better verification information.
                       */
                      function latestAnswer()
                        public
                        view
                        override
                        checkAccess()
                        returns (int256)
                      {
                        return super.latestAnswer();
                      }
                    
                      /**
                       * @notice get the latest completed round where the answer was updated. This
                       * ID includes the proxy's phase, to make sure round IDs increase even when
                       * switching to a newly deployed aggregator.
                       *
                       * @dev #[deprecated] Use latestRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended latestRoundData
                       * instead which includes better verification information.
                       */
                      function latestTimestamp()
                        public
                        view
                        override
                        checkAccess()
                        returns (uint256)
                      {
                        return super.latestTimestamp();
                      }
                    
                      /**
                       * @notice get past rounds answers
                       * @param _roundId the answer number to retrieve the answer for
                       * @dev overridden function to add the checkAccess() modifier
                       *
                       * @dev #[deprecated] Use getRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended getRoundData
                       * instead which includes better verification information.
                       */
                      function getAnswer(uint256 _roundId)
                        public
                        view
                        override
                        checkAccess()
                        returns (int256)
                      {
                        return super.getAnswer(_roundId);
                      }
                    
                      /**
                       * @notice get block timestamp when an answer was last updated
                       * @param _roundId the answer number to retrieve the updated timestamp for
                       * @dev overridden function to add the checkAccess() modifier
                       *
                       * @dev #[deprecated] Use getRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended getRoundData
                       * instead which includes better verification information.
                       */
                      function getTimestamp(uint256 _roundId)
                        public
                        view
                        override
                        checkAccess()
                        returns (uint256)
                      {
                        return super.getTimestamp(_roundId);
                      }
                    
                      /**
                       * @notice get the latest completed round where the answer was updated
                       * @dev overridden function to add the checkAccess() modifier
                       *
                       * @dev #[deprecated] Use latestRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended latestRoundData
                       * instead which includes better verification information.
                       */
                      function latestRound()
                        public
                        view
                        override
                        checkAccess()
                        returns (uint256)
                      {
                        return super.latestRound();
                      }
                    
                      /**
                       * @notice get data about a round. Consumers are encouraged to check
                       * that they're receiving fresh data by inspecting the updatedAt and
                       * answeredInRound return values.
                       * Note that different underlying implementations of AggregatorV3Interface
                       * have slightly different semantics for some of the return values. Consumers
                       * should determine what implementations they expect to receive
                       * data from and validate that they can properly handle return data from all
                       * of them.
                       * @param _roundId the round ID to retrieve the round data for
                       * @return roundId is the round ID from the aggregator for which the data was
                       * retrieved combined with a phase to ensure that round IDs get larger as
                       * time moves forward.
                       * @return answer is the answer for the given round
                       * @return startedAt is the timestamp when the round was started.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @return updatedAt is the timestamp when the round last was updated (i.e.
                       * answer was last computed)
                       * @return answeredInRound is the round ID of the round in which the answer
                       * was computed.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @dev Note that answer and updatedAt may change between queries.
                       */
                      function getRoundData(uint80 _roundId)
                        public
                        view
                        checkAccess()
                        override
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        )
                      {
                        return super.getRoundData(_roundId);
                      }
                    
                      /**
                       * @notice get data about the latest round. Consumers are encouraged to check
                       * that they're receiving fresh data by inspecting the updatedAt and
                       * answeredInRound return values.
                       * Note that different underlying implementations of AggregatorV3Interface
                       * have slightly different semantics for some of the return values. Consumers
                       * should determine what implementations they expect to receive
                       * data from and validate that they can properly handle return data from all
                       * of them.
                       * @return roundId is the round ID from the aggregator for which the data was
                       * retrieved combined with a phase to ensure that round IDs get larger as
                       * time moves forward.
                       * @return answer is the answer for the given round
                       * @return startedAt is the timestamp when the round was started.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @return updatedAt is the timestamp when the round last was updated (i.e.
                       * answer was last computed)
                       * @return answeredInRound is the round ID of the round in which the answer
                       * was computed.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @dev Note that answer and updatedAt may change between queries.
                       */
                      function latestRoundData()
                        public
                        view
                        checkAccess()
                        override
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        )
                      {
                        return super.latestRoundData();
                      }
                    
                      /**
                       * @notice Used if an aggregator contract has been proposed.
                       * @param _roundId the round ID to retrieve the round data for
                       * @return roundId is the round ID for which data was retrieved
                       * @return answer is the answer for the given round
                       * @return startedAt is the timestamp when the round was started.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @return updatedAt is the timestamp when the round last was updated (i.e.
                       * answer was last computed)
                       * @return answeredInRound is the round ID of the round in which the answer
                       * was computed.
                      */
                      function proposedGetRoundData(uint80 _roundId)
                        public
                        view
                        checkAccess()
                        hasProposal()
                        override
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        )
                      {
                        return super.proposedGetRoundData(_roundId);
                      }
                    
                      /**
                       * @notice Used if an aggregator contract has been proposed.
                       * @return roundId is the round ID for which data was retrieved
                       * @return answer is the answer for the given round
                       * @return startedAt is the timestamp when the round was started.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @return updatedAt is the timestamp when the round last was updated (i.e.
                       * answer was last computed)
                       * @return answeredInRound is the round ID of the round in which the answer
                       * was computed.
                      */
                      function proposedLatestRoundData()
                        public
                        view
                        checkAccess()
                        hasProposal()
                        override
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        )
                      {
                        return super.proposedLatestRoundData();
                      }
                    
                      /**
                       * @dev reverts if the caller does not have access by the accessController
                       * contract or is the contract itself.
                       */
                      modifier checkAccess() {
                        AccessControllerInterface ac = accessController;
                        require(address(ac) == address(0) || ac.hasAccess(msg.sender, msg.data), "No access");
                        _;
                      }
                    }

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

                    File 6 of 8: EACAggregatorProxy
                    pragma solidity 0.6.6;
                    
                    
                    /**
                     * @title The Owned contract
                     * @notice A contract with helpers for basic contract ownership.
                     */
                    contract Owned {
                    
                      address public owner;
                      address private pendingOwner;
                    
                      event OwnershipTransferRequested(
                        address indexed from,
                        address indexed to
                      );
                      event OwnershipTransferred(
                        address indexed from,
                        address indexed to
                      );
                    
                      constructor() public {
                        owner = msg.sender;
                      }
                    
                      /**
                       * @dev Allows an owner to begin transferring ownership to a new address,
                       * pending.
                       */
                      function transferOwnership(address _to)
                        external
                        onlyOwner()
                      {
                        pendingOwner = _to;
                    
                        emit OwnershipTransferRequested(owner, _to);
                      }
                    
                      /**
                       * @dev Allows an ownership transfer to be completed by the recipient.
                       */
                      function acceptOwnership()
                        external
                      {
                        require(msg.sender == pendingOwner, "Must be proposed owner");
                    
                        address oldOwner = owner;
                        owner = msg.sender;
                        pendingOwner = address(0);
                    
                        emit OwnershipTransferred(oldOwner, msg.sender);
                      }
                    
                      /**
                       * @dev Reverts if called by anyone other than the contract owner.
                       */
                      modifier onlyOwner() {
                        require(msg.sender == owner, "Only callable by owner");
                        _;
                      }
                    
                    }
                    
                    interface AggregatorInterface {
                      function latestAnswer() external view returns (int256);
                      function latestTimestamp() external view returns (uint256);
                      function latestRound() external view returns (uint256);
                      function getAnswer(uint256 roundId) external view returns (int256);
                      function getTimestamp(uint256 roundId) external view returns (uint256);
                    
                      event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);
                      event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
                    }
                    
                    interface AggregatorV3Interface {
                    
                      function decimals() external view returns (uint8);
                      function description() external view returns (string memory);
                      function version() external view returns (uint256);
                    
                      // getRoundData and latestRoundData should both raise "No data present"
                      // if they do not have data to report, instead of returning unset values
                      // which could be misinterpreted as actual reported values.
                      function getRoundData(uint80 _roundId)
                        external
                        view
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        );
                      function latestRoundData()
                        external
                        view
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        );
                    
                    }
                    
                    interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface
                    {
                    }
                    
                    /**
                     * @title A trusted proxy for updating where current answers are read from
                     * @notice This contract provides a consistent address for the
                     * CurrentAnwerInterface but delegates where it reads from to the owner, who is
                     * trusted to update it.
                     */
                    contract AggregatorProxy is AggregatorV2V3Interface, Owned {
                    
                      struct Phase {
                        uint16 id;
                        AggregatorV2V3Interface aggregator;
                      }
                      Phase private currentPhase;
                      AggregatorV2V3Interface public proposedAggregator;
                      mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators;
                    
                      uint256 constant private PHASE_OFFSET = 64;
                      uint256 constant private PHASE_SIZE = 16;
                      uint256 constant private MAX_ID = 2**(PHASE_OFFSET+PHASE_SIZE) - 1;
                    
                      constructor(address _aggregator) public Owned() {
                        setAggregator(_aggregator);
                      }
                    
                      /**
                       * @notice Reads the current answer from aggregator delegated to.
                       *
                       * @dev #[deprecated] Use latestRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended latestRoundData
                       * instead which includes better verification information.
                       */
                      function latestAnswer()
                        public
                        view
                        virtual
                        override
                        returns (int256 answer)
                      {
                        return currentPhase.aggregator.latestAnswer();
                      }
                    
                      /**
                       * @notice Reads the last updated height from aggregator delegated to.
                       *
                       * @dev #[deprecated] Use latestRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended latestRoundData
                       * instead which includes better verification information.
                       */
                      function latestTimestamp()
                        public
                        view
                        virtual
                        override
                        returns (uint256 updatedAt)
                      {
                        return currentPhase.aggregator.latestTimestamp();
                      }
                    
                      /**
                       * @notice get past rounds answers
                       * @param _roundId the answer number to retrieve the answer for
                       *
                       * @dev #[deprecated] Use getRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended getRoundData
                       * instead which includes better verification information.
                       */
                      function getAnswer(uint256 _roundId)
                        public
                        view
                        virtual
                        override
                        returns (int256 answer)
                      {
                        if (_roundId > MAX_ID) return 0;
                    
                        (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
                        AggregatorV2V3Interface aggregator = phaseAggregators[phaseId];
                        if (address(aggregator) == address(0)) return 0;
                    
                        return aggregator.getAnswer(aggregatorRoundId);
                      }
                    
                      /**
                       * @notice get block timestamp when an answer was last updated
                       * @param _roundId the answer number to retrieve the updated timestamp for
                       *
                       * @dev #[deprecated] Use getRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended getRoundData
                       * instead which includes better verification information.
                       */
                      function getTimestamp(uint256 _roundId)
                        public
                        view
                        virtual
                        override
                        returns (uint256 updatedAt)
                      {
                        if (_roundId > MAX_ID) return 0;
                    
                        (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
                        AggregatorV2V3Interface aggregator = phaseAggregators[phaseId];
                        if (address(aggregator) == address(0)) return 0;
                    
                        return aggregator.getTimestamp(aggregatorRoundId);
                      }
                    
                      /**
                       * @notice get the latest completed round where the answer was updated. This
                       * ID includes the proxy's phase, to make sure round IDs increase even when
                       * switching to a newly deployed aggregator.
                       *
                       * @dev #[deprecated] Use latestRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended latestRoundData
                       * instead which includes better verification information.
                       */
                      function latestRound()
                        public
                        view
                        virtual
                        override
                        returns (uint256 roundId)
                      {
                        Phase memory phase = currentPhase; // cache storage reads
                        return addPhase(phase.id, uint64(phase.aggregator.latestRound()));
                      }
                    
                      /**
                       * @notice get data about a round. Consumers are encouraged to check
                       * that they're receiving fresh data by inspecting the updatedAt and
                       * answeredInRound return values.
                       * Note that different underlying implementations of AggregatorV3Interface
                       * have slightly different semantics for some of the return values. Consumers
                       * should determine what implementations they expect to receive
                       * data from and validate that they can properly handle return data from all
                       * of them.
                       * @param _roundId the requested round ID as presented through the proxy, this
                       * is made up of the aggregator's round ID with the phase ID encoded in the
                       * two highest order bytes
                       * @return roundId is the round ID from the aggregator for which the data was
                       * retrieved combined with an phase to ensure that round IDs get larger as
                       * time moves forward.
                       * @return answer is the answer for the given round
                       * @return startedAt is the timestamp when the round was started.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @return updatedAt is the timestamp when the round last was updated (i.e.
                       * answer was last computed)
                       * @return answeredInRound is the round ID of the round in which the answer
                       * was computed.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @dev Note that answer and updatedAt may change between queries.
                       */
                      function getRoundData(uint80 _roundId)
                        public
                        view
                        virtual
                        override
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        )
                      {
                        (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
                    
                        (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 ansIn
                        ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId);
                    
                        return addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId);
                      }
                    
                      /**
                       * @notice get data about the latest round. Consumers are encouraged to check
                       * that they're receiving fresh data by inspecting the updatedAt and
                       * answeredInRound return values.
                       * Note that different underlying implementations of AggregatorV3Interface
                       * have slightly different semantics for some of the return values. Consumers
                       * should determine what implementations they expect to receive
                       * data from and validate that they can properly handle return data from all
                       * of them.
                       * @return roundId is the round ID from the aggregator for which the data was
                       * retrieved combined with an phase to ensure that round IDs get larger as
                       * time moves forward.
                       * @return answer is the answer for the given round
                       * @return startedAt is the timestamp when the round was started.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @return updatedAt is the timestamp when the round last was updated (i.e.
                       * answer was last computed)
                       * @return answeredInRound is the round ID of the round in which the answer
                       * was computed.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @dev Note that answer and updatedAt may change between queries.
                       */
                      function latestRoundData()
                        public
                        view
                        virtual
                        override
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        )
                      {
                        Phase memory current = currentPhase; // cache storage reads
                    
                        (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 ansIn
                        ) = current.aggregator.latestRoundData();
                    
                        return addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, current.id);
                      }
                    
                      /**
                       * @notice Used if an aggregator contract has been proposed.
                       * @param _roundId the round ID to retrieve the round data for
                       * @return roundId is the round ID for which data was retrieved
                       * @return answer is the answer for the given round
                       * @return startedAt is the timestamp when the round was started.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @return updatedAt is the timestamp when the round last was updated (i.e.
                       * answer was last computed)
                       * @return answeredInRound is the round ID of the round in which the answer
                       * was computed.
                      */
                      function proposedGetRoundData(uint80 _roundId)
                        public
                        view
                        virtual
                        hasProposal()
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        )
                      {
                        return proposedAggregator.getRoundData(_roundId);
                      }
                    
                      /**
                       * @notice Used if an aggregator contract has been proposed.
                       * @return roundId is the round ID for which data was retrieved
                       * @return answer is the answer for the given round
                       * @return startedAt is the timestamp when the round was started.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @return updatedAt is the timestamp when the round last was updated (i.e.
                       * answer was last computed)
                       * @return answeredInRound is the round ID of the round in which the answer
                       * was computed.
                      */
                      function proposedLatestRoundData()
                        public
                        view
                        virtual
                        hasProposal()
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        )
                      {
                        return proposedAggregator.latestRoundData();
                      }
                    
                      /**
                       * @notice returns the current phase's aggregator address.
                       */
                      function aggregator()
                        external
                        view
                        returns (address)
                      {
                        return address(currentPhase.aggregator);
                      }
                    
                      /**
                       * @notice returns the current phase's ID.
                       */
                      function phaseId()
                        external
                        view
                        returns (uint16)
                      {
                        return currentPhase.id;
                      }
                    
                      /**
                       * @notice represents the number of decimals the aggregator responses represent.
                       */
                      function decimals()
                        external
                        view
                        override
                        returns (uint8)
                      {
                        return currentPhase.aggregator.decimals();
                      }
                    
                      /**
                       * @notice the version number representing the type of aggregator the proxy
                       * points to.
                       */
                      function version()
                        external
                        view
                        override
                        returns (uint256)
                      {
                        return currentPhase.aggregator.version();
                      }
                    
                      /**
                       * @notice returns the description of the aggregator the proxy points to.
                       */
                      function description()
                        external
                        view
                        override
                        returns (string memory)
                      {
                        return currentPhase.aggregator.description();
                      }
                    
                      /**
                       * @notice Allows the owner to propose a new address for the aggregator
                       * @param _aggregator The new address for the aggregator contract
                       */
                      function proposeAggregator(address _aggregator)
                        external
                        onlyOwner()
                      {
                        proposedAggregator = AggregatorV2V3Interface(_aggregator);
                      }
                    
                      /**
                       * @notice Allows the owner to confirm and change the address
                       * to the proposed aggregator
                       * @dev Reverts if the given address doesn't match what was previously
                       * proposed
                       * @param _aggregator The new address for the aggregator contract
                       */
                      function confirmAggregator(address _aggregator)
                        external
                        onlyOwner()
                      {
                        require(_aggregator == address(proposedAggregator), "Invalid proposed aggregator");
                        delete proposedAggregator;
                        setAggregator(_aggregator);
                      }
                    
                    
                      /*
                       * Internal
                       */
                    
                      function setAggregator(address _aggregator)
                        internal
                      {
                        uint16 id = currentPhase.id + 1;
                        currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator));
                        phaseAggregators[id] = AggregatorV2V3Interface(_aggregator);
                      }
                    
                      function addPhase(
                        uint16 _phase,
                        uint64 _originalId
                      )
                        internal
                        view
                        returns (uint80)
                      {
                        return uint80(uint256(_phase) << PHASE_OFFSET | _originalId);
                      }
                    
                      function parseIds(
                        uint256 _roundId
                      )
                        internal
                        view
                        returns (uint16, uint64)
                      {
                        uint16 phaseId = uint16(_roundId >> PHASE_OFFSET);
                        uint64 aggregatorRoundId = uint64(_roundId);
                    
                        return (phaseId, aggregatorRoundId);
                      }
                    
                      function addPhaseIds(
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound,
                          uint16 phaseId
                      )
                        internal
                        view
                        returns (uint80, int256, uint256, uint256, uint80)
                      {
                        return (
                          addPhase(phaseId, uint64(roundId)),
                          answer,
                          startedAt,
                          updatedAt,
                          addPhase(phaseId, uint64(answeredInRound))
                        );
                      }
                    
                      /*
                       * Modifiers
                       */
                    
                      modifier hasProposal() {
                        require(address(proposedAggregator) != address(0), "No proposed aggregator present");
                        _;
                      }
                    
                    }
                    
                    interface AccessControllerInterface {
                      function hasAccess(address user, bytes calldata data) external view returns (bool);
                    }
                    
                    /**
                     * @title External Access Controlled Aggregator Proxy
                     * @notice A trusted proxy for updating where current answers are read from
                     * @notice This contract provides a consistent address for the
                     * Aggregator and AggregatorV3Interface but delegates where it reads from to the owner, who is
                     * trusted to update it.
                     * @notice Only access enabled addresses are allowed to access getters for
                     * aggregated answers and round information.
                     */
                    contract EACAggregatorProxy is AggregatorProxy {
                    
                      AccessControllerInterface public accessController;
                    
                      constructor(
                        address _aggregator,
                        address _accessController
                      )
                        public
                        AggregatorProxy(_aggregator)
                      {
                        setController(_accessController);
                      }
                    
                      /**
                       * @notice Allows the owner to update the accessController contract address.
                       * @param _accessController The new address for the accessController contract
                       */
                      function setController(address _accessController)
                        public
                        onlyOwner()
                      {
                        accessController = AccessControllerInterface(_accessController);
                      }
                    
                      /**
                       * @notice Reads the current answer from aggregator delegated to.
                       * @dev overridden function to add the checkAccess() modifier
                       *
                       * @dev #[deprecated] Use latestRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended latestRoundData
                       * instead which includes better verification information.
                       */
                      function latestAnswer()
                        public
                        view
                        override
                        checkAccess()
                        returns (int256)
                      {
                        return super.latestAnswer();
                      }
                    
                      /**
                       * @notice get the latest completed round where the answer was updated. This
                       * ID includes the proxy's phase, to make sure round IDs increase even when
                       * switching to a newly deployed aggregator.
                       *
                       * @dev #[deprecated] Use latestRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended latestRoundData
                       * instead which includes better verification information.
                       */
                      function latestTimestamp()
                        public
                        view
                        override
                        checkAccess()
                        returns (uint256)
                      {
                        return super.latestTimestamp();
                      }
                    
                      /**
                       * @notice get past rounds answers
                       * @param _roundId the answer number to retrieve the answer for
                       * @dev overridden function to add the checkAccess() modifier
                       *
                       * @dev #[deprecated] Use getRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended getRoundData
                       * instead which includes better verification information.
                       */
                      function getAnswer(uint256 _roundId)
                        public
                        view
                        override
                        checkAccess()
                        returns (int256)
                      {
                        return super.getAnswer(_roundId);
                      }
                    
                      /**
                       * @notice get block timestamp when an answer was last updated
                       * @param _roundId the answer number to retrieve the updated timestamp for
                       * @dev overridden function to add the checkAccess() modifier
                       *
                       * @dev #[deprecated] Use getRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended getRoundData
                       * instead which includes better verification information.
                       */
                      function getTimestamp(uint256 _roundId)
                        public
                        view
                        override
                        checkAccess()
                        returns (uint256)
                      {
                        return super.getTimestamp(_roundId);
                      }
                    
                      /**
                       * @notice get the latest completed round where the answer was updated
                       * @dev overridden function to add the checkAccess() modifier
                       *
                       * @dev #[deprecated] Use latestRoundData instead. This does not error if no
                       * answer has been reached, it will simply return 0. Either wait to point to
                       * an already answered Aggregator or use the recommended latestRoundData
                       * instead which includes better verification information.
                       */
                      function latestRound()
                        public
                        view
                        override
                        checkAccess()
                        returns (uint256)
                      {
                        return super.latestRound();
                      }
                    
                      /**
                       * @notice get data about a round. Consumers are encouraged to check
                       * that they're receiving fresh data by inspecting the updatedAt and
                       * answeredInRound return values.
                       * Note that different underlying implementations of AggregatorV3Interface
                       * have slightly different semantics for some of the return values. Consumers
                       * should determine what implementations they expect to receive
                       * data from and validate that they can properly handle return data from all
                       * of them.
                       * @param _roundId the round ID to retrieve the round data for
                       * @return roundId is the round ID from the aggregator for which the data was
                       * retrieved combined with a phase to ensure that round IDs get larger as
                       * time moves forward.
                       * @return answer is the answer for the given round
                       * @return startedAt is the timestamp when the round was started.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @return updatedAt is the timestamp when the round last was updated (i.e.
                       * answer was last computed)
                       * @return answeredInRound is the round ID of the round in which the answer
                       * was computed.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @dev Note that answer and updatedAt may change between queries.
                       */
                      function getRoundData(uint80 _roundId)
                        public
                        view
                        checkAccess()
                        override
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        )
                      {
                        return super.getRoundData(_roundId);
                      }
                    
                      /**
                       * @notice get data about the latest round. Consumers are encouraged to check
                       * that they're receiving fresh data by inspecting the updatedAt and
                       * answeredInRound return values.
                       * Note that different underlying implementations of AggregatorV3Interface
                       * have slightly different semantics for some of the return values. Consumers
                       * should determine what implementations they expect to receive
                       * data from and validate that they can properly handle return data from all
                       * of them.
                       * @return roundId is the round ID from the aggregator for which the data was
                       * retrieved combined with a phase to ensure that round IDs get larger as
                       * time moves forward.
                       * @return answer is the answer for the given round
                       * @return startedAt is the timestamp when the round was started.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @return updatedAt is the timestamp when the round last was updated (i.e.
                       * answer was last computed)
                       * @return answeredInRound is the round ID of the round in which the answer
                       * was computed.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @dev Note that answer and updatedAt may change between queries.
                       */
                      function latestRoundData()
                        public
                        view
                        checkAccess()
                        override
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        )
                      {
                        return super.latestRoundData();
                      }
                    
                      /**
                       * @notice Used if an aggregator contract has been proposed.
                       * @param _roundId the round ID to retrieve the round data for
                       * @return roundId is the round ID for which data was retrieved
                       * @return answer is the answer for the given round
                       * @return startedAt is the timestamp when the round was started.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @return updatedAt is the timestamp when the round last was updated (i.e.
                       * answer was last computed)
                       * @return answeredInRound is the round ID of the round in which the answer
                       * was computed.
                      */
                      function proposedGetRoundData(uint80 _roundId)
                        public
                        view
                        checkAccess()
                        hasProposal()
                        override
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        )
                      {
                        return super.proposedGetRoundData(_roundId);
                      }
                    
                      /**
                       * @notice Used if an aggregator contract has been proposed.
                       * @return roundId is the round ID for which data was retrieved
                       * @return answer is the answer for the given round
                       * @return startedAt is the timestamp when the round was started.
                       * (Only some AggregatorV3Interface implementations return meaningful values)
                       * @return updatedAt is the timestamp when the round last was updated (i.e.
                       * answer was last computed)
                       * @return answeredInRound is the round ID of the round in which the answer
                       * was computed.
                      */
                      function proposedLatestRoundData()
                        public
                        view
                        checkAccess()
                        hasProposal()
                        override
                        returns (
                          uint80 roundId,
                          int256 answer,
                          uint256 startedAt,
                          uint256 updatedAt,
                          uint80 answeredInRound
                        )
                      {
                        return super.proposedLatestRoundData();
                      }
                    
                      /**
                       * @dev reverts if the caller does not have access by the accessController
                       * contract or is the contract itself.
                       */
                      modifier checkAccess() {
                        AccessControllerInterface ac = accessController;
                        require(address(ac) == address(0) || ac.hasAccess(msg.sender, msg.data), "No access");
                        _;
                      }
                    }

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

                    File 8 of 8: ERC20FeeProxy
                    pragma solidity ^0.5.0;
                    
                    
                    /**
                     * @title ERC20FeeProxy
                     * @notice This contract performs an ERC20 token transfer, with a Fee sent to a third address and stores a reference
                     */
                    contract ERC20FeeProxy {
                      // Event to declare a transfer with a reference
                      event TransferWithReferenceAndFee(
                        address tokenAddress,
                        address to,
                        uint256 amount,
                        bytes indexed paymentReference,
                        uint256 feeAmount,
                        address feeAddress
                      );
                    
                      // Fallback function returns funds to the sender
                      function() external payable {
                        revert("not payable fallback");
                      }
                    
                      /**
                        * @notice Performs a ERC20 token transfer with a reference and a transfer to a second address for the payment of a fee
                        * @param _tokenAddress Address of the ERC20 token smart contract
                        * @param _to Transfer recipient
                        * @param _amount Amount to transfer
                        * @param _paymentReference Reference of the payment related
                        * @param _feeAmount The amount of the payment fee
                        * @param _feeAddress The fee recipient
                        */
                      function transferFromWithReferenceAndFee(
                        address _tokenAddress,
                        address _to,
                        uint256 _amount,
                        bytes calldata _paymentReference,
                        uint256 _feeAmount,
                        address _feeAddress
                        ) external
                        {
                        require(safeTransferFrom(_tokenAddress, _to, _amount), "payment transferFrom() failed");
                        if (_feeAmount > 0 && _feeAddress != address(0)) {
                          require(safeTransferFrom(_tokenAddress, _feeAddress, _feeAmount), "fee transferFrom() failed");
                        }
                        emit TransferWithReferenceAndFee(
                          _tokenAddress,
                          _to,
                          _amount,
                          _paymentReference,
                          _feeAmount,
                          _feeAddress
                        );
                      }
                    
                      /**
                       * @notice Call transferFrom ERC20 function and validates the return data of a ERC20 contract call.
                       * @dev This is necessary because of non-standard ERC20 tokens that don't have a return value.
                       * @return The return value of the ERC20 call, returning true for non-standard tokens
                       */
                      function safeTransferFrom(address _tokenAddress, address _to, uint256 _amount) internal returns (bool result) {
                        /* solium-disable security/no-inline-assembly */
                        // check if the address is a contract
                        assembly {
                          if iszero(extcodesize(_tokenAddress)) { revert(0, 0) }
                        }
                        
                        // solium-disable-next-line security/no-low-level-calls
                        (bool success, ) = _tokenAddress.call(abi.encodeWithSignature(
                          "transferFrom(address,address,uint256)",
                          msg.sender,
                          _to,
                          _amount
                        ));
                    
                        assembly {
                            switch returndatasize()
                            case 0 { // not a standard erc20
                                result := 1
                            }
                            case 32 { // standard erc20
                                returndatacopy(0, 0, 32)
                                result := mload(0)
                            }
                            default { // anything else, should revert for safety
                                revert(0, 0)
                            }
                        }
                    
                        require(success, "transferFrom() has been reverted");
                    
                        /* solium-enable security/no-inline-assembly */
                        return result;
                      }
                    }