Glenn Barry
Glenn Barry

Reputation: 13

Is there a simpler way to get decentralized data from Chainlink than doing separate multiple API calls through nodes?

I want to get price feed data of ETH in USD in my solidity project I'm testing in Remix. I'm using the Chainlink request data as a guide so that my data can be decentralized.

Right now, I make 3 chainlink requests to different nodes with different URLs and then calculate the median of the three responses to get a decentralized price. It seems like this is a fairly tedious way to do this, is there a simpler way to get this?

 function requestEthereumPrice(address _address, bytes32 job_id, string url) 
    public
    onlyOwner
  {
    Chainlink.Request memory req = buildChainlinkRequest(stringToBytes32(JOB_ID), address(this), this.fulfill.selector);
    req.add("get", url);
    req.add("path", "USD");
    req.addInt("times", 100);
    sendChainlinkRequestTo(_address, req, ORACLE_PAYMENT);
  }

  function multipleData() public{
      requestEthereumPrice(ORACLE_ADDRESS, JOB_ID);
      requestEthereumPrice(ORACLE2_ADDRESS, JOB2_ID);
      requestEthereumPrice(ORACLE3_ADDRESS, JOB3_ID);
  }

 function fulfill(bytes32 _requestId, uint256 _price)
    public
    // Use recordChainlinkFulfillment to ensure only the requesting oracle can fulfill
    recordChainlinkFulfillment(_requestId)
  {
    currentPriceList[index] = _price;
    index = (index + 1) & 3
    currentPrice = median();
  }

Upvotes: 1

Views: 432

Answers (1)

Patrick Collins
Patrick Collins

Reputation: 6131

Welcome to Stack Overflow!

Your approach is the most "brute force" way to do this, which works. However there are currently two ways you can improve this.

1. Use the reference data contracts

A reference data contract is a contract that has multiple trusted decentralized Chainlink nodes sending price updates from different data providers to a point of reference on the blockchain for anyone to query. Your specific currency pair of ETH/USD is one of those pairs currently supported. The code to get that data looks like this:

pragma solidity ^0.6.0;

import "github.com/smartcontractkit/chainlink/evm-contracts/src/v0.6/dev/AggregatorInterface.sol";

contract ReferenceConsumer {
  AggregatorInterface internal ref;

// Use 0xF79D6aFBb6dA890132F9D7c355e3015f15F3406F as the address of the ETH/USD pair
  constructor(address _aggregator) public {
    ref = AggregatorInterface(_aggregator);
  }

  function getLatestAnswer() public view returns (int256) {
    return ref.latestAnswer();
  }

  function getLatestTimestamp() public view returns (uint256) {
    return ref.latestTimestamp();
  }

You can find a list of currently supported feeds in there feeds documentation or the slightly nicer looking page of their feeds explorer.

2. Use a precoordinator contract

Number 1 is great if you want a boxed solution, however, maybe you disagree with the node selection of Chainlink, and would like your own implementation (which increases decentralization!). Your solution is one way to choose your own node network.

A precoordinator contract allows you to make a normal buildChainlinkRequest as you do above, but fans it out to multiple nodes for you. To create this, first deploy a contract:

pragma solidity ^0.5.0;

import "github.com/smartcontractkit/chainlink/evm-contracts/src/v0.5/PreCoordinator.sol";

You can then call the createServiceAgreement from the contract, which takes the parameters uint256 _minResponses, address[] _oracles, address[]_jobIds, uint256[] _payments. You can use remix to deploy them. precoordinator

Once you deploy a service agreement from your precoordinator contract, it will give you a service agreement ID. You can find this ID by checking the logs or looking at something like etherscan and going to topic 1 to see the ID. Here is an example.

Once you have the address of the precoordinator and the service agreement, you can use the address of the precoordinator contract as the oracle address, and the service agreement at the jobId. Meaning you can call a host of nodes with just:

function requestEthereumPrice(address precoordinator_address, bytes32 service_agreement, string url) 
    public
    onlyOwner
  {
    Chainlink.Request memory req = buildChainlinkRequest(service_agreement, address(this), this.fulfill.selector);
    req.add("get", url);
    req.add("path", "USD");
    req.addInt("times", 100);
    sendChainlinkRequestTo(precoordinator_address, req, ORACLE_PAYMENT);
  }

Upvotes: 2

Related Questions