ETH Price: $1,879.79 (-0.40%)

Transaction Decoder

Block:
12020461 at Mar-12-2021 12:23:47 AM +UTC
Transaction Fee:
0.039325436232943057 ETH $73.92
Gas Used:
83,179 Gas / 472.780824883 Gwei

Emitted Events:

9 Aggregator.ChainlinkFulfilled( id=C3CAB98CC2136D06D2C8AD2F85313AE51A90006CD3B484195000EB109BB7FE06 )
10 Aggregator.ResponseReceived( response=28721000000, answerId=1359, sender=[Receiver] Oracle )
11 Aggregator.AnswerUpdated( current=28698095000, roundId=1359, timestamp=1615508627 )

Account State Difference:

  Address   Before After State Difference Code
0x0821f21F...525495D06
(Chainlink: BNB - USD Aggregator)
0x3A8B67C0...Ee51BDe3F
(F2Pool Old)
4,869.481087603900856264 Eth4,869.520413040133799321 Eth0.039325436232943057
0xa932fb7c...C5744F4FC
20.288543511171884492 Eth
Nonce: 128500
20.249218074938941435 Eth
Nonce: 128501
0.039325436232943057

Execution Trace

Oracle.fulfillOracleRequest( _requestId=C3CAB98CC2136D06D2C8AD2F85313AE51A90006CD3B484195000EB109BB7FE06, _payment=750000000000000000, _callbackAddress=0x0821f21F21C325AE39557CA83B6B4df525495D06, _callbackFunctionId=System.Byte[], _expiration=1615508496, _data=00000000000000000000000000000000000000000000000000000006AFE7AE40 ) => ( True )
  • Aggregator.chainlinkCallback( _clRequestId=C3CAB98CC2136D06D2C8AD2F85313AE51A90006CD3B484195000EB109BB7FE06, _response=28721000000 )
    File 1 of 2: Oracle
    /*                                                                                           
    *      ___ ___       ___         ___                                                             
    *      `MM `MMb     dMM'         `MM                                                             
    *       MM  MMM.   ,PMM           MM                                                             
    *   ____MM  M`Mb   d'MM    ___    MM   __   ____  ___  __   ____         _____  ___  __   __     
    *  6MMMMMM  M YM. ,P MM  6MMMMb   MM   d'  6MMMMb `MM 6MM  6MMMMb\      6MMMMMb `MM 6MM  6MMbMMM 
    * 6M'  `MM  M `Mb d' MM 8M'  `Mb  MM  d'  6M'  `Mb MM69 " MM'    `     6M'   `Mb MM69 " 6M'`Mb   
    * MM    MM  M  YM.P  MM     ,oMM  MM d'   MM    MM MM'    YM.          MM     MM MM'    MM  MM   
    * MM    MM  M  `Mb'  MM ,6MM9'MM  MMdM.   MMMMMMMM MM      YMMMMb      MM     MM MM     YM.,M9   
    * MM    MM  M   YP   MM MM'   MM  MMPYM.  MM       MM          `Mb     MM     MM MM      YMM9    
    * YM.  ,MM  M   `'   MM MM.  ,MM  MM  YM. YM    d9 MM     L    ,MM 68b YM.   ,M9 MM     (M       
    *  YMMMMMM__M_      _MM_`YMMM9'Yb_MM_  YM._YMMMM9 _MM_    MYMMMM9  Y89  YMMMMM9 _MM_     YMMMMb. 
    *                                                                                       6M    Yb 
    *                                                                                       YM.   d9 
    *                                                                                        YMMMM9  
    */
    
    pragma solidity 0.4.24;
    
    /**
     * @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;
    
    
      event OwnershipRenounced(address indexed previousOwner);
      event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
      );
    
    
      /**
       * @dev The Ownable constructor sets the original `owner` of the contract to the sender
       * account.
       */
      constructor() 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 relinquish control of the contract.
       * @notice Renouncing to ownership will leave the contract without an owner.
       * It will not be possible to call the functions with the `onlyOwner`
       * modifier anymore.
       */
      function renounceOwnership() public onlyOwner {
        emit OwnershipRenounced(owner);
        owner = address(0);
      }
    
      /**
       * @dev Allows the current owner to transfer control of the contract to a newOwner.
       * @param _newOwner The address to transfer ownership to.
       */
      function transferOwnership(address _newOwner) public onlyOwner {
        _transferOwnership(_newOwner);
      }
    
      /**
       * @dev Transfers control of the contract to a newOwner.
       * @param _newOwner The address to transfer ownership to.
       */
      function _transferOwnership(address _newOwner) internal {
        require(_newOwner != address(0));
        emit OwnershipTransferred(owner, _newOwner);
        owner = _newOwner;
      }
    }
    
    // File: openzeppelin-solidity/contracts/math/SafeMath.sol
    
    pragma solidity ^0.4.24;
    
    
    /**
     * @title SafeMath
     * @dev Math operations with safety checks that throw on error
     */
    library SafeMath {
    
      /**
      * @dev Multiplies two numbers, throws on overflow.
      */
      function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
        // Gas optimization: this is cheaper than asserting 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
        if (_a == 0) {
          return 0;
        }
    
        c = _a * _b;
        assert(c / _a == _b);
        return c;
      }
    
      /**
      * @dev Integer division of two numbers, truncating the quotient.
      */
      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 _a / _b;
      }
    
      /**
      * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
      */
      function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
        assert(_b <= _a);
        return _a - _b;
      }
    
      /**
      * @dev Adds two numbers, throws on overflow.
      */
      function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
        c = _a + _b;
        assert(c >= _a);
        return c;
      }
    }
    
    // File: contracts/interfaces/ChainlinkRequestInterface.sol
    
    pragma solidity 0.4.24;
    
    interface ChainlinkRequestInterface {
      function oracleRequest(
        address sender,
        uint256 payment,
        bytes32 id,
        address callbackAddress,
        bytes4 callbackFunctionId,
        uint256 nonce,
        uint256 version,
        bytes data
      ) external;
    
      function cancelOracleRequest(
        bytes32 requestId,
        uint256 payment,
        bytes4 callbackFunctionId,
        uint256 expiration
      ) external;
    }
    
    // File: contracts/interfaces/OracleInterface.sol
    
    pragma solidity 0.4.24;
    
    interface OracleInterface {
      function fulfillOracleRequest(
        bytes32 requestId,
        uint256 payment,
        address callbackAddress,
        bytes4 callbackFunctionId,
        uint256 expiration,
        bytes32 data
      ) external returns (bool);
      function getAuthorizationStatus(address node) external view returns (bool);
      function setFulfillmentPermission(address node, bool allowed) external;
      function withdraw(address recipient, uint256 amount) external;
      function withdrawable() external view returns (uint256);
    }
    
    // File: contracts/interfaces/LinkTokenInterface.sol
    
    pragma solidity 0.4.24;
    
    interface LinkTokenInterface {
      function allowance(address owner, address spender) external returns (bool success);
      function approve(address spender, uint256 value) external returns (bool success);
      function balanceOf(address owner) external returns (uint256 balance);
      function decimals() external returns (uint8 decimalPlaces);
      function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);
      function increaseApproval(address spender, uint256 subtractedValue) external;
      function name() external returns (string tokenName);
      function symbol() external returns (string tokenSymbol);
      function totalSupply() external returns (uint256 totalTokensIssued);
      function transfer(address to, uint256 value) external returns (bool success);
      function transferAndCall(address to, uint256 value, bytes data) external returns (bool success);
      function transferFrom(address from, address to, uint256 value) external returns (bool success);
    }
    
    // File: contracts/Oracle.sol
    
    pragma solidity 0.4.24;
    
    
    
    
    
    
    /**
     * @title The Chainlink Oracle contract
     * @notice Node operators can deploy this contract to fulfill requests sent to them
     */
    contract Oracle is ChainlinkRequestInterface, OracleInterface, Ownable {
      using SafeMath for uint256;
    
      uint256 constant public EXPIRY_TIME = 5 minutes;
      uint256 constant private MINIMUM_CONSUMER_GAS_LIMIT = 400000;
      // We initialize fields to 1 instead of 0 so that the first invocation
      // does not cost more gas.
      uint256 constant private ONE_FOR_CONSISTENT_GAS_COST = 1;
      uint256 constant private SELECTOR_LENGTH = 4;
      uint256 constant private EXPECTED_REQUEST_WORDS = 2;
      // solium-disable-next-line zeppelin/no-arithmetic-operations
      uint256 constant private MINIMUM_REQUEST_LENGTH = SELECTOR_LENGTH + (32 * EXPECTED_REQUEST_WORDS);
    
      LinkTokenInterface internal LinkToken;
      mapping(bytes32 => bytes32) private commitments;
      mapping(address => bool) private authorizedNodes;
      uint256 private withdrawableTokens = ONE_FOR_CONSISTENT_GAS_COST;
    
      event OracleRequest(
        bytes32 indexed specId,
        address requester,
        bytes32 requestId,
        uint256 payment,
        address callbackAddr,
        bytes4 callbackFunctionId,
        uint256 cancelExpiration,
        uint256 dataVersion,
        bytes data
      );
    
      event CancelOracleRequest(
        bytes32 indexed requestId
      );
    
      /**
       * @notice Deploy with the address of the LINK token
       * @dev Sets the LinkToken address for the imported LinkTokenInterface
       * @param _link The address of the LINK token
       */
      constructor(address _link) Ownable() public {
        LinkToken = LinkTokenInterface(_link);
      }
    
      /**
       * @notice Called when LINK is sent to the contract via `transferAndCall`
       * @dev The data payload's first 2 words will be overwritten by the `_sender` and `_amount`
       * values to ensure correctness. Calls oracleRequest.
       * @param _sender Address of the sender
       * @param _amount Amount of LINK sent (specified in wei)
       * @param _data Payload of the transaction
       */
      function onTokenTransfer(
        address _sender,
        uint256 _amount,
        bytes _data
      )
        public
        onlyLINK
        validRequestLength(_data)
        permittedFunctionsForLINK(_data)
      {
        assembly {
          // solium-disable-next-line security/no-low-level-calls
          mstore(add(_data, 36), _sender) // ensure correct sender is passed
          // solium-disable-next-line security/no-low-level-calls
          mstore(add(_data, 68), _amount)    // ensure correct amount is passed
        }
        // solium-disable-next-line security/no-low-level-calls
        require(address(this).delegatecall(_data), "Unable to create request"); // calls oracleRequest
      }
    
      /**
       * @notice Creates the Chainlink request
       * @dev Stores the hash of the params as the on-chain commitment for the request.
       * Emits OracleRequest event for the Chainlink node to detect.
       * @param _sender The sender of the request
       * @param _payment The amount of payment given (specified in wei)
       * @param _specId The Job Specification ID
       * @param _callbackAddress The callback address for the response
       * @param _callbackFunctionId The callback function ID for the response
       * @param _nonce The nonce sent by the requester
       * @param _dataVersion The specified data version
       * @param _data The CBOR payload of the request
       */
      function oracleRequest(
        address _sender,
        uint256 _payment,
        bytes32 _specId,
        address _callbackAddress,
        bytes4 _callbackFunctionId,
        uint256 _nonce,
        uint256 _dataVersion,
        bytes _data
      )
        external
        onlyLINK
        checkCallbackAddress(_callbackAddress)
      {
        bytes32 requestId = keccak256(abi.encodePacked(_sender, _nonce));
        require(commitments[requestId] == 0, "Must use a unique ID");
        uint256 expiration = now.add(EXPIRY_TIME);
    
        commitments[requestId] = keccak256(
          abi.encodePacked(
            _payment,
            _callbackAddress,
            _callbackFunctionId,
            expiration
          )
        );
    
        emit OracleRequest(
          _specId,
          _sender,
          requestId,
          _payment,
          _callbackAddress,
          _callbackFunctionId,
          expiration,
          _dataVersion,
          _data);
      }
    
      /**
       * @notice Called by the Chainlink node to fulfill requests
       * @dev Given params must hash back to the commitment stored from `oracleRequest`.
       * Will call the callback address' callback function without bubbling up error
       * checking in a `require` so that the node can get paid.
       * @param _requestId The fulfillment request ID that must match the requester's
       * @param _payment The payment amount that will be released for the oracle (specified in wei)
       * @param _callbackAddress The callback address to call for fulfillment
       * @param _callbackFunctionId The callback function ID to use for fulfillment
       * @param _expiration The expiration that the node should respond by before the requester can cancel
       * @param _data The data to return to the consuming contract
       * @return Status if the external call was successful
       */
      function fulfillOracleRequest(
        bytes32 _requestId,
        uint256 _payment,
        address _callbackAddress,
        bytes4 _callbackFunctionId,
        uint256 _expiration,
        bytes32 _data
      )
        external
        onlyAuthorizedNode
        isValidRequest(_requestId)
        returns (bool)
      {
        bytes32 paramsHash = keccak256(
          abi.encodePacked(
            _payment,
            _callbackAddress,
            _callbackFunctionId,
            _expiration
          )
        );
        require(commitments[_requestId] == paramsHash, "Params do not match request ID");
        withdrawableTokens = withdrawableTokens.add(_payment);
        delete commitments[_requestId];
        require(gasleft() >= MINIMUM_CONSUMER_GAS_LIMIT, "Must provide consumer enough gas");
        // All updates to the oracle's fulfillment should come before calling the
        // callback(addr+functionId) as it is untrusted.
        // See: https://solidity.readthedocs.io/en/develop/security-considerations.html#use-the-checks-effects-interactions-pattern
        return _callbackAddress.call(_callbackFunctionId, _requestId, _data); // solium-disable-line security/no-low-level-calls
      }
    
      /**
       * @notice Use this to check if a node is authorized for fulfilling requests
       * @param _node The address of the Chainlink node
       * @return The authorization status of the node
       */
      function getAuthorizationStatus(address _node) external view returns (bool) {
        return authorizedNodes[_node];
      }
    
      /**
       * @notice Sets the fulfillment permission for a given node. Use `true` to allow, `false` to disallow.
       * @param _node The address of the Chainlink node
       * @param _allowed Bool value to determine if the node can fulfill requests
       */
      function setFulfillmentPermission(address _node, bool _allowed) external onlyOwner {
        authorizedNodes[_node] = _allowed;
      }
    
      /**
       * @notice Allows the node operator to withdraw earned LINK to a given address
       * @dev The owner of the contract can be another wallet and does not have to be a Chainlink node
       * @param _recipient The address to send the LINK token to
       * @param _amount The amount to send (specified in wei)
       */
      function withdraw(address _recipient, uint256 _amount)
        external
        onlyOwner
        hasAvailableFunds(_amount)
      {
        withdrawableTokens = withdrawableTokens.sub(_amount);
        assert(LinkToken.transfer(_recipient, _amount));
      }
    
      /**
       * @notice Displays the amount of LINK that is available for the node operator to withdraw
       * @dev We use `ONE_FOR_CONSISTENT_GAS_COST` in place of 0 in storage
       * @return The amount of withdrawable LINK on the contract
       */
      function withdrawable() external view onlyOwner returns (uint256) {
        return withdrawableTokens.sub(ONE_FOR_CONSISTENT_GAS_COST);
      }
    
      /**
       * @notice Allows requesters to cancel requests sent to this oracle contract. Will transfer the LINK
       * sent for the request back to the requester's address.
       * @dev Given params must hash to a commitment stored on the contract in order for the request to be valid
       * Emits CancelOracleRequest event.
       * @param _requestId The request ID
       * @param _payment The amount of payment given (specified in wei)
       * @param _callbackFunc The requester's specified callback address
       * @param _expiration The time of the expiration for the request
       */
      function cancelOracleRequest(
        bytes32 _requestId,
        uint256 _payment,
        bytes4 _callbackFunc,
        uint256 _expiration
      ) external {
        bytes32 paramsHash = keccak256(
          abi.encodePacked(
            _payment,
            msg.sender,
            _callbackFunc,
            _expiration)
        );
        require(paramsHash == commitments[_requestId], "Params do not match request ID");
        require(_expiration <= now, "Request is not expired");
    
        delete commitments[_requestId];
        emit CancelOracleRequest(_requestId);
    
        assert(LinkToken.transfer(msg.sender, _payment));
      }
    
      // MODIFIERS
    
      /**
       * @dev Reverts if amount requested is greater than withdrawable balance
       * @param _amount The given amount to compare to `withdrawableTokens`
       */
      modifier hasAvailableFunds(uint256 _amount) {
        require(withdrawableTokens >= _amount.add(ONE_FOR_CONSISTENT_GAS_COST), "Amount requested is greater than withdrawable balance");
        _;
      }
    
      /**
       * @dev Reverts if request ID does not exist
       * @param _requestId The given request ID to check in stored `commitments`
       */
      modifier isValidRequest(bytes32 _requestId) {
        require(commitments[_requestId] != 0, "Must have a valid requestId");
        _;
      }
    
      /**
       * @dev Reverts if `msg.sender` is not authorized to fulfill requests
       */
      modifier onlyAuthorizedNode() {
        require(authorizedNodes[msg.sender] || msg.sender == owner, "Not an authorized node to fulfill requests");
        _;
      }
    
      /**
       * @dev Reverts if not sent from the LINK token
       */
      modifier onlyLINK() {
        require(msg.sender == address(LinkToken), "Must use LINK token");
        _;
      }
    
      /**
       * @dev Reverts if the given data does not begin with the `oracleRequest` function selector
       * @param _data The data payload of the request
       */
      modifier permittedFunctionsForLINK(bytes _data) {
        bytes4 funcSelector;
        assembly {
          // solium-disable-next-line security/no-low-level-calls
          funcSelector := mload(add(_data, 32))
        }
        require(funcSelector == this.oracleRequest.selector, "Must use whitelisted functions");
        _;
      }
    
      /**
       * @dev Reverts if the callback address is the LINK token
       * @param _to The callback address
       */
      modifier checkCallbackAddress(address _to) {
        require(_to != address(LinkToken), "Cannot callback to LINK");
        _;
      }
    
      /**
       * @dev Reverts if the given payload is less than needed to create a request
       * @param _data The request payload
       */
      modifier validRequestLength(bytes _data) {
        require(_data.length >= MINIMUM_REQUEST_LENGTH, "Invalid request length");
        _;
      }
    
    }

    File 2 of 2: Aggregator
    pragma solidity 0.4.24;
    
    /**
    * @dev A library for working with mutable byte buffers in Solidity.
    *
    * Byte buffers are mutable and expandable, and provide a variety of primitives
    * for writing to them. At any time you can fetch a bytes object containing the
    * current contents of the buffer. The bytes object should not be stored between
    * operations, as it may change due to resizing of the buffer.
    */
    library Buffer {
      /**
      * @dev Represents a mutable buffer. Buffers have a current value (buf) and
      *      a capacity. The capacity may be longer than the current value, in
      *      which case it can be extended without the need to allocate more memory.
      */
      struct buffer {
        bytes buf;
        uint capacity;
      }
    
      /**
      * @dev Initializes a buffer with an initial capacity.
      * @param buf The buffer to initialize.
      * @param capacity The number of bytes of space to allocate the buffer.
      * @return The buffer, for chaining.
      */
      function init(buffer memory buf, uint capacity) internal pure returns(buffer memory) {
        if (capacity % 32 != 0) {
          capacity += 32 - (capacity % 32);
        }
        // Allocate space for the buffer data
        buf.capacity = capacity;
        assembly {
          let ptr := mload(0x40)
          mstore(buf, ptr)
          mstore(ptr, 0)
          mstore(0x40, add(32, add(ptr, capacity)))
        }
        return buf;
      }
    
      /**
      * @dev Initializes a new buffer from an existing bytes object.
      *      Changes to the buffer may mutate the original value.
      * @param b The bytes object to initialize the buffer with.
      * @return A new buffer.
      */
      function fromBytes(bytes memory b) internal pure returns(buffer memory) {
        buffer memory buf;
        buf.buf = b;
        buf.capacity = b.length;
        return buf;
      }
    
      function resize(buffer memory buf, uint capacity) private pure {
        bytes memory oldbuf = buf.buf;
        init(buf, capacity);
        append(buf, oldbuf);
      }
    
      function max(uint a, uint b) private pure returns(uint) {
        if (a > b) {
          return a;
        }
        return b;
      }
    
      /**
      * @dev Sets buffer length to 0.
      * @param buf The buffer to truncate.
      * @return The original buffer, for chaining..
      */
      function truncate(buffer memory buf) internal pure returns (buffer memory) {
        assembly {
          let bufptr := mload(buf)
          mstore(bufptr, 0)
        }
        return buf;
      }
    
      /**
      * @dev Writes a byte string to a buffer. Resizes if doing so would exceed
      *      the capacity of the buffer.
      * @param buf The buffer to append to.
      * @param off The start offset to write to.
      * @param data The data to append.
      * @param len The number of bytes to copy.
      * @return The original buffer, for chaining.
      */
      function write(buffer memory buf, uint off, bytes memory data, uint len) internal pure returns(buffer memory) {
        require(len <= data.length);
    
        if (off + len > buf.capacity) {
          resize(buf, max(buf.capacity, len + off) * 2);
        }
    
        uint dest;
        uint src;
        assembly {
          // Memory address of the buffer data
          let bufptr := mload(buf)
          // Length of existing buffer data
          let buflen := mload(bufptr)
          // Start address = buffer address + offset + sizeof(buffer length)
          dest := add(add(bufptr, 32), off)
          // Update buffer length if we're extending it
          if gt(add(len, off), buflen) {
            mstore(bufptr, add(len, off))
          }
          src := add(data, 32)
        }
    
        // Copy word-length chunks while possible
        for (; len >= 32; len -= 32) {
          assembly {
            mstore(dest, mload(src))
          }
          dest += 32;
          src += 32;
        }
    
        // Copy remaining bytes
        uint mask = 256 ** (32 - len) - 1;
        assembly {
          let srcpart := and(mload(src), not(mask))
          let destpart := and(mload(dest), mask)
          mstore(dest, or(destpart, srcpart))
        }
    
        return buf;
      }
    
      /**
      * @dev Appends a byte string to a buffer. Resizes if doing so would exceed
      *      the capacity of the buffer.
      * @param buf The buffer to append to.
      * @param data The data to append.
      * @param len The number of bytes to copy.
      * @return The original buffer, for chaining.
      */
      function append(buffer memory buf, bytes memory data, uint len) internal pure returns (buffer memory) {
        return write(buf, buf.buf.length, data, len);
      }
    
      /**
      * @dev Appends a byte string to a buffer. Resizes if doing so would exceed
      *      the capacity of the buffer.
      * @param buf The buffer to append to.
      * @param data The data to append.
      * @return The original buffer, for chaining.
      */
      function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) {
        return write(buf, buf.buf.length, data, data.length);
      }
    
      /**
      * @dev Writes a byte to the buffer. Resizes if doing so would exceed the
      *      capacity of the buffer.
      * @param buf The buffer to append to.
      * @param off The offset to write the byte at.
      * @param data The data to append.
      * @return The original buffer, for chaining.
      */
      function writeUint8(buffer memory buf, uint off, uint8 data) internal pure returns(buffer memory) {
        if (off >= buf.capacity) {
          resize(buf, buf.capacity * 2);
        }
    
        assembly {
          // Memory address of the buffer data
          let bufptr := mload(buf)
          // Length of existing buffer data
          let buflen := mload(bufptr)
          // Address = buffer address + sizeof(buffer length) + off
          let dest := add(add(bufptr, off), 32)
          mstore8(dest, data)
          // Update buffer length if we extended it
          if eq(off, buflen) {
            mstore(bufptr, add(buflen, 1))
          }
        }
        return buf;
      }
    
      /**
      * @dev Appends a byte to the buffer. Resizes if doing so would exceed the
      *      capacity of the buffer.
      * @param buf The buffer to append to.
      * @param data The data to append.
      * @return The original buffer, for chaining.
      */
      function appendUint8(buffer memory buf, uint8 data) internal pure returns(buffer memory) {
        return writeUint8(buf, buf.buf.length, data);
      }
    
      /**
      * @dev Writes up to 32 bytes to the buffer. Resizes if doing so would
      *      exceed the capacity of the buffer.
      * @param buf The buffer to append to.
      * @param off The offset to write at.
      * @param data The data to append.
      * @param len The number of bytes to write (left-aligned).
      * @return The original buffer, for chaining.
      */
      function write(buffer memory buf, uint off, bytes32 data, uint len) private pure returns(buffer memory) {
        if (len + off > buf.capacity) {
          resize(buf, (len + off) * 2);
        }
    
        uint mask = 256 ** len - 1;
        // Right-align data
        data = data >> (8 * (32 - len));
        assembly {
          // Memory address of the buffer data
          let bufptr := mload(buf)
          // Address = buffer address + sizeof(buffer length) + off + len
          let dest := add(add(bufptr, off), len)
          mstore(dest, or(and(mload(dest), not(mask)), data))
          // Update buffer length if we extended it
          if gt(add(off, len), mload(bufptr)) {
            mstore(bufptr, add(off, len))
          }
        }
        return buf;
      }
    
      /**
      * @dev Writes a bytes20 to the buffer. Resizes if doing so would exceed the
      *      capacity of the buffer.
      * @param buf The buffer to append to.
      * @param off The offset to write at.
      * @param data The data to append.
      * @return The original buffer, for chaining.
      */
      function writeBytes20(buffer memory buf, uint off, bytes20 data) internal pure returns (buffer memory) {
        return write(buf, off, bytes32(data), 20);
      }
    
      /**
      * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed
      *      the capacity of the buffer.
      * @param buf The buffer to append to.
      * @param data The data to append.
      * @return The original buffer, for chhaining.
      */
      function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) {
        return write(buf, buf.buf.length, bytes32(data), 20);
      }
    
      /**
      * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed
      *      the capacity of the buffer.
      * @param buf The buffer to append to.
      * @param data The data to append.
      * @return The original buffer, for chaining.
      */
      function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) {
        return write(buf, buf.buf.length, data, 32);
      }
    
      /**
      * @dev Writes an integer to the buffer. Resizes if doing so would exceed
      *      the capacity of the buffer.
      * @param buf The buffer to append to.
      * @param off The offset to write at.
      * @param data The data to append.
      * @param len The number of bytes to write (right-aligned).
      * @return The original buffer, for chaining.
      */
      function writeInt(buffer memory buf, uint off, uint data, uint len) private pure returns(buffer memory) {
        if (len + off > buf.capacity) {
          resize(buf, (len + off) * 2);
        }
    
        uint mask = 256 ** len - 1;
        assembly {
          // Memory address of the buffer data
          let bufptr := mload(buf)
          // Address = buffer address + off + sizeof(buffer length) + len
          let dest := add(add(bufptr, off), len)
          mstore(dest, or(and(mload(dest), not(mask)), data))
          // Update buffer length if we extended it
          if gt(add(off, len), mload(bufptr)) {
            mstore(bufptr, add(off, len))
          }
        }
        return buf;
      }
    
      /**
       * @dev Appends a byte to the end of the buffer. Resizes if doing so would
       * exceed the capacity of the buffer.
       * @param buf The buffer to append to.
       * @param data The data to append.
       * @return The original buffer.
       */
      function appendInt(buffer memory buf, uint data, uint len) internal pure returns(buffer memory) {
        return writeInt(buf, buf.buf.length, data, len);
      }
    }
    
    library CBOR {
      using Buffer for Buffer.buffer;
    
      uint8 private constant MAJOR_TYPE_INT = 0;
      uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1;
      uint8 private constant MAJOR_TYPE_BYTES = 2;
      uint8 private constant MAJOR_TYPE_STRING = 3;
      uint8 private constant MAJOR_TYPE_ARRAY = 4;
      uint8 private constant MAJOR_TYPE_MAP = 5;
      uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7;
    
      function encodeType(Buffer.buffer memory buf, uint8 major, uint value) private pure {
        if(value <= 23) {
          buf.appendUint8(uint8((major << 5) | value));
        } else if(value <= 0xFF) {
          buf.appendUint8(uint8((major << 5) | 24));
          buf.appendInt(value, 1);
        } else if(value <= 0xFFFF) {
          buf.appendUint8(uint8((major << 5) | 25));
          buf.appendInt(value, 2);
        } else if(value <= 0xFFFFFFFF) {
          buf.appendUint8(uint8((major << 5) | 26));
          buf.appendInt(value, 4);
        } else if(value <= 0xFFFFFFFFFFFFFFFF) {
          buf.appendUint8(uint8((major << 5) | 27));
          buf.appendInt(value, 8);
        }
      }
    
      function encodeIndefiniteLengthType(Buffer.buffer memory buf, uint8 major) private pure {
        buf.appendUint8(uint8((major << 5) | 31));
      }
    
      function encodeUInt(Buffer.buffer memory buf, uint value) internal pure {
        encodeType(buf, MAJOR_TYPE_INT, value);
      }
    
      function encodeInt(Buffer.buffer memory buf, int value) internal pure {
        if(value >= 0) {
          encodeType(buf, MAJOR_TYPE_INT, uint(value));
        } else {
          encodeType(buf, MAJOR_TYPE_NEGATIVE_INT, uint(-1 - value));
        }
      }
    
      function encodeBytes(Buffer.buffer memory buf, bytes value) internal pure {
        encodeType(buf, MAJOR_TYPE_BYTES, value.length);
        buf.append(value);
      }
    
      function encodeString(Buffer.buffer memory buf, string value) internal pure {
        encodeType(buf, MAJOR_TYPE_STRING, bytes(value).length);
        buf.append(bytes(value));
      }
    
      function startArray(Buffer.buffer memory buf) internal pure {
        encodeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY);
      }
    
      function startMap(Buffer.buffer memory buf) internal pure {
        encodeIndefiniteLengthType(buf, MAJOR_TYPE_MAP);
      }
    
      function endSequence(Buffer.buffer memory buf) internal pure {
        encodeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE);
      }
    }
    
    /**
     * @title Library for common Chainlink functions
     * @dev Uses imported CBOR library for encoding to buffer
     */
    library Chainlink {
      uint256 internal constant defaultBufferSize = 256; // solhint-disable-line const-name-snakecase
    
      using CBOR for Buffer.buffer;
    
      struct Request {
        bytes32 id;
        address callbackAddress;
        bytes4 callbackFunctionId;
        uint256 nonce;
        Buffer.buffer buf;
      }
    
      /**
       * @notice Initializes a Chainlink request
       * @dev Sets the ID, callback address, and callback function signature on the request
       * @param self The uninitialized request
       * @param _id The Job Specification ID
       * @param _callbackAddress The callback address
       * @param _callbackFunction The callback function signature
       * @return The initialized request
       */
      function initialize(
        Request memory self,
        bytes32 _id,
        address _callbackAddress,
        bytes4 _callbackFunction
      ) internal pure returns (Chainlink.Request memory) {
        Buffer.init(self.buf, defaultBufferSize);
        self.id = _id;
        self.callbackAddress = _callbackAddress;
        self.callbackFunctionId = _callbackFunction;
        return self;
      }
    
      /**
       * @notice Sets the data for the buffer without encoding CBOR on-chain
       * @dev CBOR can be closed with curly-brackets {} or they can be left off
       * @param self The initialized request
       * @param _data The CBOR data
       */
      function setBuffer(Request memory self, bytes _data)
        internal pure
      {
        Buffer.init(self.buf, _data.length);
        Buffer.append(self.buf, _data);
      }
    
      /**
       * @notice Adds a string value to the request with a given key name
       * @param self The initialized request
       * @param _key The name of the key
       * @param _value The string value to add
       */
      function add(Request memory self, string _key, string _value)
        internal pure
      {
        self.buf.encodeString(_key);
        self.buf.encodeString(_value);
      }
    
      /**
       * @notice Adds a bytes value to the request with a given key name
       * @param self The initialized request
       * @param _key The name of the key
       * @param _value The bytes value to add
       */
      function addBytes(Request memory self, string _key, bytes _value)
        internal pure
      {
        self.buf.encodeString(_key);
        self.buf.encodeBytes(_value);
      }
    
      /**
       * @notice Adds a int256 value to the request with a given key name
       * @param self The initialized request
       * @param _key The name of the key
       * @param _value The int256 value to add
       */
      function addInt(Request memory self, string _key, int256 _value)
        internal pure
      {
        self.buf.encodeString(_key);
        self.buf.encodeInt(_value);
      }
    
      /**
       * @notice Adds a uint256 value to the request with a given key name
       * @param self The initialized request
       * @param _key The name of the key
       * @param _value The uint256 value to add
       */
      function addUint(Request memory self, string _key, uint256 _value)
        internal pure
      {
        self.buf.encodeString(_key);
        self.buf.encodeUInt(_value);
      }
    
      /**
       * @notice Adds an array of strings to the request with a given key name
       * @param self The initialized request
       * @param _key The name of the key
       * @param _values The array of string values to add
       */
      function addStringArray(Request memory self, string _key, string[] memory _values)
        internal pure
      {
        self.buf.encodeString(_key);
        self.buf.startArray();
        for (uint256 i = 0; i < _values.length; i++) {
          self.buf.encodeString(_values[i]);
        }
        self.buf.endSequence();
      }
    }
    
    interface ENSInterface {
    
      // Logged when the owner of a node assigns a new owner to a subnode.
      event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
    
      // Logged when the owner of a node transfers ownership to a new account.
      event Transfer(bytes32 indexed node, address owner);
    
      // Logged when the resolver for a node changes.
      event NewResolver(bytes32 indexed node, address resolver);
    
      // Logged when the TTL of a node changes
      event NewTTL(bytes32 indexed node, uint64 ttl);
    
    
      function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external;
      function setResolver(bytes32 node, address resolver) external;
      function setOwner(bytes32 node, address owner) external;
      function setTTL(bytes32 node, uint64 ttl) external;
      function owner(bytes32 node) external view returns (address);
      function resolver(bytes32 node) external view returns (address);
      function ttl(bytes32 node) external view returns (uint64);
    
    }
    
    interface LinkTokenInterface {
      function allowance(address owner, address spender) external returns (uint256 remaining);
      function approve(address spender, uint256 value) external returns (bool success);
      function balanceOf(address owner) external returns (uint256 balance);
      function decimals() external returns (uint8 decimalPlaces);
      function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);
      function increaseApproval(address spender, uint256 subtractedValue) external;
      function name() external returns (string tokenName);
      function symbol() external returns (string tokenSymbol);
      function totalSupply() external returns (uint256 totalTokensIssued);
      function transfer(address to, uint256 value) external returns (bool success);
      function transferAndCall(address to, uint256 value, bytes data) external returns (bool success);
      function transferFrom(address from, address to, uint256 value) external returns (bool success);
    }
    
    interface ChainlinkRequestInterface {
      function oracleRequest(
        address sender,
        uint256 payment,
        bytes32 id,
        address callbackAddress,
        bytes4 callbackFunctionId,
        uint256 nonce,
        uint256 version,
        bytes data
      ) external;
    
      function cancelOracleRequest(
        bytes32 requestId,
        uint256 payment,
        bytes4 callbackFunctionId,
        uint256 expiration
      ) external;
    }
    
    interface PointerInterface {
      function getAddress() external view returns (address);
    }
    
    
    contract ENSResolver {
      function addr(bytes32 node) public view returns (address);
    }
    
    
    /**
     * @title SafeMath
     * @dev Math operations with safety checks that throw on error
     */
    library SafeMath {
    
      /**
      * @dev Multiplies two numbers, throws on overflow.
      */
      function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
        // Gas optimization: this is cheaper than asserting 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
        if (_a == 0) {
          return 0;
        }
    
        c = _a * _b;
        assert(c / _a == _b);
        return c;
      }
    
      /**
      * @dev Integer division of two numbers, truncating the quotient.
      */
      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 _a / _b;
      }
    
      /**
      * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
      */
      function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
        assert(_b <= _a);
        return _a - _b;
      }
    
      /**
      * @dev Adds two numbers, throws on overflow.
      */
      function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
        c = _a + _b;
        assert(c >= _a);
        return c;
      }
    }
    
    /**
     * @title The ChainlinkClient contract
     * @notice Contract writers can inherit this contract in order to create requests for the
     * Chainlink network
     */
    contract ChainlinkClient {
      using Chainlink for Chainlink.Request;
      using SafeMath for uint256;
    
      uint256 constant internal LINK = 10**18;
      uint256 constant private AMOUNT_OVERRIDE = 0;
      address constant private SENDER_OVERRIDE = 0x0;
      uint256 constant private ARGS_VERSION = 1;
      bytes32 constant private ENS_TOKEN_SUBNAME = keccak256("link");
      bytes32 constant private ENS_ORACLE_SUBNAME = keccak256("oracle");
      address constant private LINK_TOKEN_POINTER = 0xC89bD4E1632D3A43CB03AAAd5262cbe4038Bc571;
    
      ENSInterface private ens;
      bytes32 private ensNode;
      LinkTokenInterface private link;
      ChainlinkRequestInterface private oracle;
      uint256 private requests = 1;
      mapping(bytes32 => address) private pendingRequests;
    
      event ChainlinkRequested(bytes32 indexed id);
      event ChainlinkFulfilled(bytes32 indexed id);
      event ChainlinkCancelled(bytes32 indexed id);
    
      /**
       * @notice Creates a request that can hold additional parameters
       * @param _specId The Job Specification ID that the request will be created for
       * @param _callbackAddress The callback address that the response will be sent to
       * @param _callbackFunctionSignature The callback function signature to use for the callback address
       * @return A Chainlink Request struct in memory
       */
      function buildChainlinkRequest(
        bytes32 _specId,
        address _callbackAddress,
        bytes4 _callbackFunctionSignature
      ) internal pure returns (Chainlink.Request memory) {
        Chainlink.Request memory req;
        return req.initialize(_specId, _callbackAddress, _callbackFunctionSignature);
      }
    
      /**
       * @notice Creates a Chainlink request to the stored oracle address
       * @dev Calls `chainlinkRequestTo` with the stored oracle address
       * @param _req The initialized Chainlink Request
       * @param _payment The amount of LINK to send for the request
       * @return The request ID
       */
      function sendChainlinkRequest(Chainlink.Request memory _req, uint256 _payment)
        internal
        returns (bytes32)
      {
        return sendChainlinkRequestTo(oracle, _req, _payment);
      }
    
      /**
       * @notice Creates a Chainlink request to the specified oracle address
       * @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to
       * send LINK which creates a request on the target oracle contract.
       * Emits ChainlinkRequested event.
       * @param _oracle The address of the oracle for the request
       * @param _req The initialized Chainlink Request
       * @param _payment The amount of LINK to send for the request
       * @return The request ID
       */
      function sendChainlinkRequestTo(address _oracle, Chainlink.Request memory _req, uint256 _payment)
        internal
        returns (bytes32 requestId)
      {
        requestId = keccak256(abi.encodePacked(this, requests));
        _req.nonce = requests;
        pendingRequests[requestId] = _oracle;
        emit ChainlinkRequested(requestId);
        require(link.transferAndCall(_oracle, _payment, encodeRequest(_req)), "unable to transferAndCall to oracle");
        requests += 1;
    
        return requestId;
      }
    
      /**
       * @notice Allows a request to be cancelled if it has not been fulfilled
       * @dev Requires keeping track of the expiration value emitted from the oracle contract.
       * Deletes the request from the `pendingRequests` mapping.
       * Emits ChainlinkCancelled event.
       * @param _requestId The request ID
       * @param _payment The amount of LINK sent for the request
       * @param _callbackFunc The callback function specified for the request
       * @param _expiration The time of the expiration for the request
       */
      function cancelChainlinkRequest(
        bytes32 _requestId,
        uint256 _payment,
        bytes4 _callbackFunc,
        uint256 _expiration
      )
        internal
      {
        ChainlinkRequestInterface requested = ChainlinkRequestInterface(pendingRequests[_requestId]);
        delete pendingRequests[_requestId];
        emit ChainlinkCancelled(_requestId);
        requested.cancelOracleRequest(_requestId, _payment, _callbackFunc, _expiration);
      }
    
      /**
       * @notice Sets the stored oracle address
       * @param _oracle The address of the oracle contract
       */
      function setChainlinkOracle(address _oracle) internal {
        oracle = ChainlinkRequestInterface(_oracle);
      }
    
      /**
       * @notice Sets the LINK token address
       * @param _link The address of the LINK token contract
       */
      function setChainlinkToken(address _link) internal {
        link = LinkTokenInterface(_link);
      }
    
      /**
       * @notice Sets the Chainlink token address for the public
       * network as given by the Pointer contract
       */
      function setPublicChainlinkToken() internal {
        setChainlinkToken(PointerInterface(LINK_TOKEN_POINTER).getAddress());
      }
    
      /**
       * @notice Retrieves the stored address of the LINK token
       * @return The address of the LINK token
       */
      function chainlinkTokenAddress()
        internal
        view
        returns (address)
      {
        return address(link);
      }
    
      /**
       * @notice Retrieves the stored address of the oracle contract
       * @return The address of the oracle contract
       */
      function chainlinkOracleAddress()
        internal
        view
        returns (address)
      {
        return address(oracle);
      }
    
      /**
       * @notice Allows for a request which was created on another contract to be fulfilled
       * on this contract
       * @param _oracle The address of the oracle contract that will fulfill the request
       * @param _requestId The request ID used for the response
       */
      function addChainlinkExternalRequest(address _oracle, bytes32 _requestId)
        internal
        notPendingRequest(_requestId)
      {
        pendingRequests[_requestId] = _oracle;
      }
    
      /**
       * @notice Sets the stored oracle and LINK token contracts with the addresses resolved by ENS
       * @dev Accounts for subnodes having different resolvers
       * @param _ens The address of the ENS contract
       * @param _node The ENS node hash
       */
      function useChainlinkWithENS(address _ens, bytes32 _node)
        internal
      {
        ens = ENSInterface(_ens);
        ensNode = _node;
        bytes32 linkSubnode = keccak256(abi.encodePacked(ensNode, ENS_TOKEN_SUBNAME));
        ENSResolver resolver = ENSResolver(ens.resolver(linkSubnode));
        setChainlinkToken(resolver.addr(linkSubnode));
        updateChainlinkOracleWithENS();
      }
    
      /**
       * @notice Sets the stored oracle contract with the address resolved by ENS
       * @dev This may be called on its own as long as `useChainlinkWithENS` has been called previously
       */
      function updateChainlinkOracleWithENS()
        internal
      {
        bytes32 oracleSubnode = keccak256(abi.encodePacked(ensNode, ENS_ORACLE_SUBNAME));
        ENSResolver resolver = ENSResolver(ens.resolver(oracleSubnode));
        setChainlinkOracle(resolver.addr(oracleSubnode));
      }
    
      /**
       * @notice Encodes the request to be sent to the oracle contract
       * @dev The Chainlink node expects values to be in order for the request to be picked up. Order of types
       * will be validated in the oracle contract.
       * @param _req The initialized Chainlink Request
       * @return The bytes payload for the `transferAndCall` method
       */
      function encodeRequest(Chainlink.Request memory _req)
        private
        view
        returns (bytes memory)
      {
        return abi.encodeWithSelector(
          oracle.oracleRequest.selector,
          SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address
          AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of LINK sent
          _req.id,
          _req.callbackAddress,
          _req.callbackFunctionId,
          _req.nonce,
          ARGS_VERSION,
          _req.buf.buf);
      }
    
      /**
       * @notice Ensures that the fulfillment is valid for this contract
       * @dev Use if the contract developer prefers methods instead of modifiers for validation
       * @param _requestId The request ID for fulfillment
       */
      function validateChainlinkCallback(bytes32 _requestId)
        internal
        recordChainlinkFulfillment(_requestId)
        // solhint-disable-next-line no-empty-blocks
      {}
    
      /**
       * @dev Reverts if the sender is not the oracle of the request.
       * Emits ChainlinkFulfilled event.
       * @param _requestId The request ID for fulfillment
       */
      modifier recordChainlinkFulfillment(bytes32 _requestId) {
        require(msg.sender == pendingRequests[_requestId], "Source must be the oracle of the request");
        delete pendingRequests[_requestId];
        emit ChainlinkFulfilled(_requestId);
        _;
      }
    
      /**
       * @dev Reverts if the request is already pending
       * @param _requestId The request ID for fulfillment
       */
      modifier notPendingRequest(bytes32 _requestId) {
        require(pendingRequests[_requestId] == address(0), "Request is already pending");
        _;
      }
    }
    
    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 timestamp);
      event NewRound(uint256 indexed roundId, address indexed startedBy);
    }
    
    library SignedSafeMath {
    
      /**
       * @dev Adds two int256s and makes sure the result doesn't overflow. Signed
       * integers aren't supported by the SafeMath library, thus this method
       * @param _a The first number to be added
       * @param _a The second number to be added
       */
      function add(int256 _a, int256 _b)
        internal
        pure
        returns (int256)
      {
        int256 c = _a + _b;
        require((_b >= 0 && c >= _a) || (_b < 0 && c < _a), "SignedSafeMath: addition overflow");
    
        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;
    
    
      event OwnershipRenounced(address indexed previousOwner);
      event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
      );
    
    
      /**
       * @dev The Ownable constructor sets the original `owner` of the contract to the sender
       * account.
       */
      constructor() 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 relinquish control of the contract.
       * @notice Renouncing to ownership will leave the contract without an owner.
       * It will not be possible to call the functions with the `onlyOwner`
       * modifier anymore.
       */
      function renounceOwnership() public onlyOwner {
        emit OwnershipRenounced(owner);
        owner = address(0);
      }
    
      /**
       * @dev Allows the current owner to transfer control of the contract to a newOwner.
       * @param _newOwner The address to transfer ownership to.
       */
      function transferOwnership(address _newOwner) public onlyOwner {
        _transferOwnership(_newOwner);
      }
    
      /**
       * @dev Transfers control of the contract to a newOwner.
       * @param _newOwner The address to transfer ownership to.
       */
      function _transferOwnership(address _newOwner) internal {
        require(_newOwner != address(0));
        emit OwnershipTransferred(owner, _newOwner);
        owner = _newOwner;
      }
    }
    
    /**
     * @title An example Chainlink contract with aggregation
     * @notice Requesters can use this contract as a framework for creating
     * requests to multiple Chainlink nodes and running aggregation
     * as the contract receives answers.
     */
    contract Aggregator is AggregatorInterface, ChainlinkClient, Ownable {
      using SignedSafeMath for int256;
    
      struct Answer {
        uint128 minimumResponses;
        uint128 maxResponses;
        int256[] responses;
      }
    
      event ResponseReceived(int256 indexed response, uint256 indexed answerId, address indexed sender);
    
      int256 private currentAnswerValue;
      uint256 private updatedTimestampValue;
      uint256 private latestCompletedAnswer;
      uint128 public paymentAmount;
      uint128 public minimumResponses;
      bytes32[] public jobIds;
      address[] public oracles;
    
      uint256 private answerCounter = 1;
      mapping(address => bool) public authorizedRequesters;
      mapping(bytes32 => uint256) private requestAnswers;
      mapping(uint256 => Answer) private answers;
      mapping(uint256 => int256) private currentAnswers;
      mapping(uint256 => uint256) private updatedTimestamps;
    
      uint256 constant private MAX_ORACLE_COUNT = 45;
    
      /**
       * @notice Deploy with the address of the LINK token and arrays of matching
       * length containing the addresses of the oracles and their corresponding
       * Job IDs.
       * @dev Sets the LinkToken address for the network, addresses of the oracles,
       * and jobIds in storage.
       * @param _link The address of the LINK token
       * @param _paymentAmount the amount of LINK to be sent to each oracle for each request
       * @param _minimumResponses the minimum number of responses
       * before an answer will be calculated
       * @param _oracles An array of oracle addresses
       * @param _jobIds An array of Job IDs
       */
      constructor(
        address _link,
        uint128 _paymentAmount,
        uint128 _minimumResponses,
        address[] _oracles,
        bytes32[] _jobIds
      ) public Ownable() {
        setChainlinkToken(_link);
        updateRequestDetails(_paymentAmount, _minimumResponses, _oracles, _jobIds);
      }
    
      /**
       * @notice Creates a Chainlink request for each oracle in the oracles array.
       * @dev This example does not include request parameters. Reference any documentation
       * associated with the Job IDs used to determine the required parameters per-request.
       */
      function requestRateUpdate()
        external
        ensureAuthorizedRequester()
      {
        Chainlink.Request memory request;
        bytes32 requestId;
        uint256 oraclePayment = paymentAmount;
    
        for (uint i = 0; i < oracles.length; i++) {
          request = buildChainlinkRequest(jobIds[i], this, this.chainlinkCallback.selector);
          requestId = sendChainlinkRequestTo(oracles[i], request, oraclePayment);
          requestAnswers[requestId] = answerCounter;
        }
        answers[answerCounter].minimumResponses = minimumResponses;
        answers[answerCounter].maxResponses = uint128(oracles.length);
        answerCounter = answerCounter.add(1);
    
        emit NewRound(answerCounter, msg.sender);
      }
    
      /**
       * @notice Receives the answer from the Chainlink node.
       * @dev This function can only be called by the oracle that received the request.
       * @param _clRequestId The Chainlink request ID associated with the answer
       * @param _response The answer provided by the Chainlink node
       */
      function chainlinkCallback(bytes32 _clRequestId, int256 _response)
        external
      {
        validateChainlinkCallback(_clRequestId);
    
        uint256 answerId = requestAnswers[_clRequestId];
        delete requestAnswers[_clRequestId];
    
        answers[answerId].responses.push(_response);
        emit ResponseReceived(_response, answerId, msg.sender);
        updateLatestAnswer(answerId);
        deleteAnswer(answerId);
      }
    
      /**
       * @notice Updates the arrays of oracles and jobIds with new values,
       * overwriting the old values.
       * @dev Arrays are validated to be equal length.
       * @param _paymentAmount the amount of LINK to be sent to each oracle for each request
       * @param _minimumResponses the minimum number of responses
       * before an answer will be calculated
       * @param _oracles An array of oracle addresses
       * @param _jobIds An array of Job IDs
       */
      function updateRequestDetails(
        uint128 _paymentAmount,
        uint128 _minimumResponses,
        address[] _oracles,
        bytes32[] _jobIds
      )
        public
        onlyOwner()
        validateAnswerRequirements(_minimumResponses, _oracles, _jobIds)
      {
        paymentAmount = _paymentAmount;
        minimumResponses = _minimumResponses;
        jobIds = _jobIds;
        oracles = _oracles;
      }
    
      /**
       * @notice Allows the owner of the contract to withdraw any LINK balance
       * available on the contract.
       * @dev The contract will need to have a LINK balance in order to create requests.
       * @param _recipient The address to receive the LINK tokens
       * @param _amount The amount of LINK to send from the contract
       */
      function transferLINK(address _recipient, uint256 _amount)
        public
        onlyOwner()
      {
        LinkTokenInterface linkToken = LinkTokenInterface(chainlinkTokenAddress());
        require(linkToken.transfer(_recipient, _amount), "LINK transfer failed");
      }
    
      /**
       * @notice Called by the owner to permission other addresses to generate new
       * requests to oracles.
       * @param _requester the address whose permissions are being set
       * @param _allowed boolean that determines whether the requester is
       * permissioned or not
       */
      function setAuthorization(address _requester, bool _allowed)
        external
        onlyOwner()
      {
        authorizedRequesters[_requester] = _allowed;
      }
    
      /**
       * @notice Cancels an outstanding Chainlink request.
       * The oracle contract requires the request ID and additional metadata to
       * validate the cancellation. Only old answers can be cancelled.
       * @param _requestId is the identifier for the chainlink request being cancelled
       * @param _payment is the amount of LINK paid to the oracle for the request
       * @param _expiration is the time when the request expires
       */
      function cancelRequest(
        bytes32 _requestId,
        uint256 _payment,
        uint256 _expiration
      )
        external
        ensureAuthorizedRequester()
      {
        uint256 answerId = requestAnswers[_requestId];
        require(answerId < latestCompletedAnswer, "Cannot modify an in-progress answer");
    
        delete requestAnswers[_requestId];
        answers[answerId].responses.push(0);
        deleteAnswer(answerId);
    
        cancelChainlinkRequest(
          _requestId,
          _payment,
          this.chainlinkCallback.selector,
          _expiration
        );
      }
    
      /**
       * @notice Called by the owner to kill the contract. This transfers all LINK
       * balance and ETH balance (if there is any) to the owner.
       */
      function destroy()
        external
        onlyOwner()
      {
        LinkTokenInterface linkToken = LinkTokenInterface(chainlinkTokenAddress());
        transferLINK(owner, linkToken.balanceOf(address(this)));
        selfdestruct(owner);
      }
    
      /**
       * @dev Performs aggregation of the answers received from the Chainlink nodes.
       * Assumes that at least half the oracles are honest and so can't contol the
       * middle of the ordered responses.
       * @param _answerId The answer ID associated with the group of requests
       */
      function updateLatestAnswer(uint256 _answerId)
        private
        ensureMinResponsesReceived(_answerId)
        ensureOnlyLatestAnswer(_answerId)
      {
        uint256 responseLength = answers[_answerId].responses.length;
        uint256 middleIndex = responseLength.div(2);
        int256 currentAnswerTemp;
        if (responseLength % 2 == 0) {
          int256 median1 = quickselect(answers[_answerId].responses, middleIndex);
          int256 median2 = quickselect(answers[_answerId].responses, middleIndex.add(1)); // quickselect is 1 indexed
          currentAnswerTemp = median1.add(median2) / 2; // signed integers are not supported by SafeMath
        } else {
          currentAnswerTemp = quickselect(answers[_answerId].responses, middleIndex.add(1)); // quickselect is 1 indexed
        }
        currentAnswerValue = currentAnswerTemp;
        latestCompletedAnswer = _answerId;
        updatedTimestampValue = now;
        updatedTimestamps[_answerId] = now;
        currentAnswers[_answerId] = currentAnswerTemp;
        emit AnswerUpdated(currentAnswerTemp, _answerId, now);
      }
    
      /**
       * @notice get the most recently reported answer
       */
      function latestAnswer()
        external
        view
        returns (int256)
      {
        return currentAnswers[latestCompletedAnswer];
      }
    
      /**
       * @notice get the last updated at block timestamp
       */
      function latestTimestamp()
        external
        view
        returns (uint256)
      {
        return updatedTimestamps[latestCompletedAnswer];
      }
    
      /**
       * @notice get past rounds answers
       * @param _roundId the answer number to retrieve the answer for
       */
      function getAnswer(uint256 _roundId)
        external
        view
        returns (int256)
      {
        return currentAnswers[_roundId];
      }
    
      /**
       * @notice get block timestamp when an answer was last updated
       * @param _roundId the answer number to retrieve the updated timestamp for
       */
      function getTimestamp(uint256 _roundId)
        external
        view
        returns (uint256)
      {
        return updatedTimestamps[_roundId];
      }
    
      /**
       * @notice get the latest completed round where the answer was updated
       */
      function latestRound() external view returns (uint256) {
        return latestCompletedAnswer;
      }
    
      /**
       * @dev Returns the kth value of the ordered array
       * See: http://www.cs.yale.edu/homes/aspnes/pinewiki/QuickSelect.html
       * @param _a The list of elements to pull from
       * @param _k The index, 1 based, of the elements you want to pull from when ordered
       */
      function quickselect(int256[] memory _a, uint256 _k)
        private
        pure
        returns (int256)
      {
        int256[] memory a = _a;
        uint256 k = _k;
        uint256 aLen = a.length;
        int256[] memory a1 = new int256[](aLen);
        int256[] memory a2 = new int256[](aLen);
        uint256 a1Len;
        uint256 a2Len;
        int256 pivot;
        uint256 i;
    
        while (true) {
          pivot = a[aLen.div(2)];
          a1Len = 0;
          a2Len = 0;
          for (i = 0; i < aLen; i++) {
            if (a[i] < pivot) {
              a1[a1Len] = a[i];
              a1Len++;
            } else if (a[i] > pivot) {
              a2[a2Len] = a[i];
              a2Len++;
            }
          }
          if (k <= a1Len) {
            aLen = a1Len;
            (a, a1) = swap(a, a1);
          } else if (k > (aLen.sub(a2Len))) {
            k = k.sub(aLen.sub(a2Len));
            aLen = a2Len;
            (a, a2) = swap(a, a2);
          } else {
            return pivot;
          }
        }
      }
    
      /**
       * @dev Swaps the pointers to two uint256 arrays in memory
       * @param _a The pointer to the first in memory array
       * @param _b The pointer to the second in memory array
       */
      function swap(int256[] memory _a, int256[] memory _b)
        private
        pure
        returns(int256[] memory, int256[] memory)
      {
        return (_b, _a);
      }
    
      /**
       * @dev Cleans up the answer record if all responses have been received.
       * @param _answerId The identifier of the answer to be deleted
       */
      function deleteAnswer(uint256 _answerId)
        private
        ensureAllResponsesReceived(_answerId)
      {
        delete answers[_answerId];
      }
    
      /**
       * @dev Prevents taking an action if the minimum number of responses has not
       * been received for an answer.
       * @param _answerId The the identifier of the answer that keeps track of the responses.
       */
      modifier ensureMinResponsesReceived(uint256 _answerId) {
        if (answers[_answerId].responses.length >= answers[_answerId].minimumResponses) {
          _;
        }
      }
    
      /**
       * @dev Prevents taking an action if not all responses are received for an answer.
       * @param _answerId The the identifier of the answer that keeps track of the responses.
       */
      modifier ensureAllResponsesReceived(uint256 _answerId) {
        if (answers[_answerId].responses.length == answers[_answerId].maxResponses) {
          _;
        }
      }
    
      /**
       * @dev Prevents taking an action if a newer answer has been recorded.
       * @param _answerId The current answer's identifier.
       * Answer IDs are in ascending order.
       */
      modifier ensureOnlyLatestAnswer(uint256 _answerId) {
        if (latestCompletedAnswer <= _answerId) {
          _;
        }
      }
    
      /**
       * @dev Ensures corresponding number of oracles and jobs.
       * @param _oracles The list of oracles.
       * @param _jobIds The list of jobs.
       */
      modifier validateAnswerRequirements(
        uint256 _minimumResponses,
        address[] _oracles,
        bytes32[] _jobIds
      ) {
        require(_oracles.length <= MAX_ORACLE_COUNT, "cannot have more than 45 oracles");
        require(_oracles.length >= _minimumResponses, "must have at least as many oracles as responses");
        require(_oracles.length == _jobIds.length, "must have exactly as many oracles as job IDs");
        _;
      }
    
      /**
       * @dev Reverts if `msg.sender` is not authorized to make requests.
       */
      modifier ensureAuthorizedRequester() {
        require(authorizedRequesters[msg.sender] || msg.sender == owner, "Not an authorized address for creating requests");
        _;
      }
    
    }