3

Currently, when I call

oraclize_getPrice("random", 400000);

I get back

8000000000000000

on rinkeby. That'd be over 2$ USD if on the mainnet and also looks oddly round. Why is this so high?

2

Your oraclize_getPrice("random", 400000) returns 8000000000000000 because it calculates gasLimit * gasPrice with the given gasLimit of 400000 and the default gasPrice of 20 Gwei. The total cost is calculated by: $0.05 +( call of your __callback() + execution gas of the __callback()) * gasPrice However, in practice it's calculated by $0.05 + CUSTOM_GAS_LIMIT * CUSTOM_GAS_PRICE whereby CUSTOM_GAS_LIMIT should be enough to execute your __callback() and CUSTOM_GAS_PRICE high enough to have the transaction be mined in time.

See below how to influence these values:

There are three factors affecting the "real" price of using oraclize:

  1. The gas cost of your __callback() function. This function is called by Oraclize and must be paid by your contract.
  2. (Closely related to (1)) The gas limit used by Oraclize to send the answer to your contract. By default, oraclize uses a gas limit of 200k when calling your __callback(). These 200k are paid by your contract. However, unused gas will be returned to Oraclize - not to your contract! Try and error to find a close value and use it in oraclize_newRandomDSQuery(delay, N, CUSTOM_GASLIMIT) and oraclize_getPrice("random", CUSTOM_GASLIMIT). This value MUST BE >= than the value determined in (1).
  3. The set gas price. By default, oraclize uses a relatively high price of 20Gwei. Currently, according to Ethgasstation.info, 3-4 Gwei would be enough (this alone lowers your cost by 80%!). You can set it in your constructor or any other function by calling oraclize_setCustomGasPrice(customGasPrice). I suggest not to hardcode that value because the requirements may vary in times of high network load. If your gasPrice is too low, the oraclize callback to your contract may take very long or may even never be mined.

Here's an example how I handle these values:

pragma solidity ^0.4.24;
import "oraclize-api/contracts/usingOraclize.sol";

contract MyContract is usingOraclize {

  // USD Cent value of 1 ether. Init with non-zero value.
  uint256 public ethusd = 1;

  // Sold out / sale active?
  bool public soldOut = false;  

  // Oracle active?
  bool public oracleActive = false;

  // Delay between autonomous oraclize requests
  uint256 public oracleInterval;

  // Gas price for oraclize callback transaction. 5 Gwei
  uint256 public oracleGasPrice = 5000000000;

  // Gas limit for oraclize callback transaction
  // Unused gas is returned to oraclize.
  uint256 public oracleGasLimit = 100000;


  constructor(uint _oracleInterval, uint _oracleGasPrice) public {
    require(_oracleInterval > 0);
    require(_oracleGasPrice > 0);

    oracleInterval = _oracleInterval;    
    oracleGasPrice = _oracleGasPrice;

    oraclize_setCustomGasPrice(_oracleGasPrice);
  }

  // Activate ethusd oracle and load contract with ETH
  function activateOracle() external payable {
    oracleActive = true;
    requestEthUsd(0);
  }

 /**
   * @dev Request ETHUSD rate from oraclize
   * @param _delay in seconds when the request should be scheduled from now on
   */
  function requestEthUsd(uint _delay) internal {
    if (oracleActive && !soldOut) {
      if (oraclize_getPrice("URL") > address(this).balance) {
        oracleActive = false;
      } else {
        if (_delay == 0) {
          oraclize_query("URL", "json(https://api.gdax.com/products/ETH-USD/ticker).price", oracleGasLimit);
        } else {
          oraclize_query(_delay, "URL", "json(https://api.gdax.com/products/ETH-USD/ticker).price", oracleGasLimit);
        }
      }
    }
  }

  /**
   * @dev Called by oraclize.
   */
  function __callback(bytes32 myid, string result) public {
    if (msg.sender != oraclize_cbAddress()) revert();
    ethusd = parseInt(result, 2);
    requestEthUsd(oracleInterval);
  }

  /**
   * @dev Public function to set the oracle gas price.
   */
  function setOracleGasPrice(uint256 _gasPrice) external {
    require(_gasPrice > 0, "Gas price must be a positive number.");
    oraclize_setCustomGasPrice(_gasPrice);
    oracleGasPrice = _gasPrice;
  }


  /**
   * @dev Public function to set the oracle gas limit.
   */
  function setOracleGasLimit(uint256 _gasLimit) external {
    require(_gasLimit > 0, "Gas limit must be a positive number.");
    oracleGasLimit = _gasLimit;
  }


  /**
   * @dev Public function to set the oracle query interval.
   */
  function setOracleInterval(uint256 _interval) external {
    require(_interval > 0, "Interval must be > 0");
    oracleInterval = _interval;
  }
}

This way you're able to apply new values even after contract deployment. The cost of my "URL" query has been lowered from $1.20 to $0.13.

NB: you should make your contract ownable and limit access to some of the above functions to the contract owner.

  • Not sure I understand the difference between 1. & 2. - isn't the callback function gas cost exactly what I'm paying by specifying the oracleGasLimit? – user1282931 Aug 24 '18 at 7:24
  • Indeed, they're related. Point 1 is the "real" cost on the EVM. Point 2 is what you're willing to pay. P2 should always be > P1. In contrast to the gasLimit set in MetaMask transactions, you don't get unused gas back. This is important to understand. – haggis Aug 24 '18 at 7:30
  • I still don't get how such a high return value is possible. I pass in 400000 as gas limit to the query.Gas station reports for 400000 a price of 0.254 usd$ currently (that's on main net of course) and the pricing website of oraclize states a 0.05$ fee for the random service. So how is the returned value over 2 usd$? – user1282931 Aug 24 '18 at 7:36
  • The total cost is calculated by: $0.254 +( call of your __callback() + execution gas of the __callback()) * gasPrice. But since oraclize does not know how much gas is needed in total, you have to deliver a close value by your own. – haggis Aug 24 '18 at 7:39
  • I updated my answer for clarification. – haggis Aug 24 '18 at 7:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.