ETH Price: $2,155.39 (+0.36%)

Transaction Decoder

Block:
10159287 at May-29-2020 07:16:21 AM +UTC
Transaction Fee:
0.001271550000042385 ETH $2.74
Gas Used:
42,385 Gas / 30.000000001 Gwei

Emitted Events:

136 0x5f4ce2e0d0b9ae3ca0652fbba1401cb9c8495718.0x7cc135e0cebb02c3480ae5d74d377283180a2601f8f644edf7987b009316c63a( 0x7cc135e0cebb02c3480ae5d74d377283180a2601f8f644edf7987b009316c63a, 0x9f4eae2cb65070555f7bf06a37501591f9d49d79ccca8a5840f37ce7fb3fcf48 )
137 0x5f4ce2e0d0b9ae3ca0652fbba1401cb9c8495718.0xb51168059c83c860caf5b830c5d2e64c2172c6fb2fe9f25447d9838e18d93b60( 0xb51168059c83c860caf5b830c5d2e64c2172c6fb2fe9f25447d9838e18d93b60, 0x0000000000000000000000000000000000000000000000000000008f82df5e00, 0x000000000000000000000000000000000000000000000000000000000000017d, 0x0000000000000000000000008cfb1d4269f0daa003cdea567ac8f76c0647764a )

Account State Difference:

  Address   Before After State Difference Code
(Nanopool)
3,303.662125171047854573 Eth3,303.663396721047896958 Eth0.001271550000042385
0x5F4Ce2e0...9C8495718
0x8cfb1D42...c0647764a
0xAaEed1E7...E4ba78433
6.62550320335275152 Eth
Nonce: 98006
6.624231653352709135 Eth
Nonce: 98007
0.001271550000042385

Execution Trace

Oracle.fulfillOracleRequest( _requestId=9F4EAE2CB65070555F7BF06A37501591F9D49D79CCCA8A5840F37CE7FB3FCF48, _payment=160000000000000000, _callbackAddress=0x5F4Ce2e0d0b9AE3CA0652FbBa1401cb9C8495718, _callbackFunctionId=System.Byte[], _expiration=1590736863, _data=0000000000000000000000000000000000000000000000000000008F82DF5E00 ) => ( True )
  • 0x5f4ce2e0d0b9ae3ca0652fbba1401cb9c8495718.6a9705b4( )
    // File: openzeppelin-solidity/contracts/ownership/Ownable.sol
    
    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");
        _;
      }
    
    }