1

I am using Chainlink to get a value from an API for my smart-contract.

I just want to do a simple Get request as described in Chainlink's documentation. Here is the scripte taken from the documentation:

pragma solidity ^0.6.0;

import "@chainlink/contracts/src/v0.6/ChainlinkClient.sol";

contract APIConsumer is ChainlinkClient {
  
    uint256 public volume;
    
    address private oracle;
    bytes32 private jobId;
    uint256 private fee;
    
    /**
     * Network: Kovan
     * Oracle: 0x2f90A6D021db21e1B2A077c5a37B3C7E75D15b7e
     * Job ID: 29fa9aa13bf1468788b7cc4a500a45b8
     * Fee: 0.1 LINK
     */
    constructor() public {
        setPublicChainlinkToken();
        oracle = 0x2f90A6D021db21e1B2A077c5a37B3C7E75D15b7e;
        jobId = "29fa9aa13bf1468788b7cc4a500a45b8";
        fee = 0.1 * 10 ** 18; // 0.1 LINK
    }
    
    /**
     * Create a Chainlink request to retrieve API response, find the target
     * data, then multiply by 1000000000000000000 (to remove decimal places from data).
     */
    function requestVolumeData() public returns (bytes32 requestId) 
    {
        Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);
        
        // Set the URL to perform the GET request on
        request.add("get", "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD");
        
        // Set the path to find the desired data in the API response, where the response format is:
        // {"RAW":
        //   {"ETH":
        //    {"USD":
        //     {
        //      "VOLUME24HOUR": xxx.xxx,
        //     }
        //    }
        //   }
        //  }
        request.add("path", "RAW.ETH.USD.VOLUME24HOUR");
        
        // Multiply the result by 1000000000000000000 to remove decimals
        int timesAmount = 10**18;
        request.addInt("times", timesAmount);
        
        // Sends the request
        return sendChainlinkRequestTo(oracle, request, fee);
    }
    
    /**
     * Receive the response in the form of uint256
     */ 
    function fulfill(bytes32 _requestId, uint256 _volume) public recordChainlinkFulfillment(_requestId)
    {
        volume = _volume;
    }
}

The only difference with the example above is that the value ("Myvalue" in this example) I am trying to access is in an array. Here is what the structure of the JSON answer looks like when I call the API using python:

{
            "data": [
                {
                    "Myvalue": "0.764",
                    "OtherValue": "4.658"
                    
                }
            ],
            "metadata": {
                "id": "5646843"
            }
}

This is my smart-contract code:

function requestVolumeData() public returns (bytes32 requestId) 
    {
        Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);
        
        // Set the URL to perform the GET request on
        request.add("get", "myURL");
        
        // ----- This is where I suspect the syntax is wrong -----
        request.add("path", "data[0].Myvalue");
        
        // Multiply the result by 1000000000000000000 to remove decimals
        int timesAmount = 10**18;
        request.addInt("times", timesAmount);
        
        // Sends the request
        return sendChainlinkRequestTo(oracle, request, fee);
    }

    function fulfill(bytes32 _requestId, uint256 _volume) public recordChainlinkFulfillment(_requestId)
    {
        volume = _volume;
    }
    

When I call requestVolumeData(), the volume value stays at 0. I do not think that the error comes from outside of this function as when I tried to access the "id" in "metadata", it worked.

I suspect the error comes from my JSON spec "data[0].Myvalue". My question thus is what is the correct syntax to get the value inside an array?

Thank you

5
  • Could you please edit this question so all information can be found on this page? It doesn't help us if we have to flip back and forth between links. Dec 28 '20 at 23:54
  • Could you also include your fulfill function? There is a good chance you just have the wrong return type. It looks like the object in your JSON is a string, so you'd have to return a bytes object and convert it to a string. Dec 28 '20 at 23:57
  • I edited my question with the changes you asked for, hope this is easier to read now. About the return type, I would be curious to know why Myvalue would be a string but id be an integer? Thank you for your help
    – Thomas
    Dec 29 '20 at 10:24
  • “Myvalue” is in quotes in your JSON object, so that gets interpreted as a string Dec 29 '20 at 11:04
  • Found the issue, it was in the JSON path syntax, it should not include "[ ]". Will write a proper answer.
    – Thomas
    Dec 29 '20 at 13:39
1

The issue, as suspected, came from the JSON path syntax. It seems that the adapter does not like "[ ]". The correct syntax in this example is:

request.add("path", "data.0.Myvalue");

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.