Making HTTP Requests in Solidity
By: Patrick Collins
Tags: Solidity, Ethereum, Programming, Chainlink, Blockchain

What Does This Look Like in Solidity?

To show what this looks like in code, let’s look at getting the numerical price of ETH. You can use this Remix link to follow along, but here is a subset of that contract code.



// Ideally, you'd want to pass the oracle payment, address, and jobID as

function requestEthereumPrice()

public

onlyOwner

{

// newRequest takes a JobID, a callback address, and callback function as input

Chainlink.Request memory req = buildChainlinkRequest(JOBID, address(this), this.fulfill.selector);

req.add("get", "

req.add("path", "USD");

req.addInt("times", 100);

sendChainlinkRequestTo(ORACLE_ADDRESS, req, ORACLE_PAYMENT);

} // Creates a Chainlink request with the uint256 multiplier job// Ideally, you'd want to pass the oracle payment, address, and jobID asfunction requestEthereumPrice()publiconlyOwner// newRequest takes a JobID, a callback address, and callback function as inputChainlink.Request memory req = buildChainlinkRequest(JOBID, address(this), this.fulfill.selector);req.add("get", " https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD ");req.add("path", "USD");req.addInt("times", 100);sendChainlinkRequestTo(ORACLE_ADDRESS, req, ORACLE_PAYMENT); // fulfill receives a uint256 data type

function fulfill(bytes32 _requestId, uint256 _price)

public

// Use recordChainlinkFulfillment to ensure only the requesting oracle can fulfill

recordChainlinkFulfillment(_requestId)

{

currentPrice = _price;

}

To start making a request to a chainlink node, we call the buildChainlinkRequest function that is imported from the ChainlinkClient.sol , this function returns a Chainlink.Request struct. In this function, we pass the jobID, return address, and fulfillment function when we start to build it.

We can find a jobID of an independent Chainlink node by heading over to a node listing service, like market.link, and searching for what we want. Node listing services are where independent nodes post their information about how to connect to their Chainlink node. You can use them to build your network of decentralized oracles. Make sure you’re on the correct network (ropsten, mainnet, kovan, etc).

For this, we want a job that can make an httpget call and return a uint256 , so let’s try searching for that job on the ropsten network.

Searching for a job on market.link

Let’s pick a job, and just make sure that the jobspec is what we are looking for. We can head on over to the jobspec tab to see what the initiators and adapters are.

Image from market.link

To make sure this job has the right adapters, we can check out their tasks/adapters list. The image above shows that this job has exactly the initiators and adapters/tasks that we want.

Once we verify that the job has the adapters we want, we can then copy the job ID to use in our code. You can see other nodes that have a similar job, and you’ll need this list when you make your contract decentralized, but again for testing and developing we can just pull from a single node. Make sure you also grab the oracle address, as you’ll need this later.

Chainlink.Request memory req = buildChainlinkRequest(JOBID, address(this), this.fulfill.selector);

We then put the JOBID in the first parameter of our buildChainlinkReqeust . The second parameter is the address of the contract to return the data to also known as the callbackaddress . The last parameter is the function that will process the data once collected aka the callbackFunctionSignature . We want to return the data to this contract, so we put in address(this) , and our function that will be processing the data will be fulfill . We defined the fulfill function right below this one.

function fulfill(bytes32 _requestId, uint256 _price)

public

// Use recordChainlinkFulfillment to ensure only the requesting oracle can fulfill

recordChainlinkFulfillment(_requestId)

{

currentPrice = _price;

}

The uint256 _price parameter is where the Chainlink node will input the price gathered from making the http get request. In our example above, we are just setting the return value from the node to our currentPrice variable.

Back in the requestEthereumPrice function, we can then add parameters to our adatpers/tasks. Let’s go over what each adapter does:

httpget

The Chainlink node will make an HTTP GET request; usually, this is a simple API call.

The HTTP GET request that we want to make in the parameters passed to the req variable.

At the time of writing, the return value of this HTTP GET request is:

{"USD":391.41}

jsonparse

Once the node makes the HTTP GET request, it will go through the json and find only the value that we want. Storing the entire return of the HTTP GET request would be really expensive, as the more you store on the Ethereum chain the more ETH gas you have to pay. So, we want to return as little as possible.

req.add("path", "USD");

This will condense the return of the HTTP GET request to just the value

391.41 . It walks down the json of the {“USD”:391.41} return value. For longer json returns, you can add indexes of lists too. For example, if you had an object like:

{"USD": [ "price": {"ETH": 391.41}]}

We could walk down the path to that value with:

req.add("path", "USD.0.ETH");

multiply/times

Once we get the 391.41 value, we have to make it a whole number. Decimals don’t work in solidity, and we need to represent decimals using fixed-point math.

req.addInt("times", 100);

This will adapt our result once more to be 39141 (since we move the decimal place over twice by multiplying by 100).

ethuint256

You’ll notice in our code above, we don’t pass any parameters to this adapter; that’s because we don’t need to. This adapter just converts our answer of 39141 to the solidity understandable format.

ethtx

This one also doesn’t need any parameters. This is the adapter that actually posts the data back on-chain.

Now we use the sendChainlinkRequestTo method, with the address of the oracle we got from market.link, the request itself, and the oracle_payment.

sendChainlinkRequestTo(ORACLE_ADDRESS, req, ORACLE_PAYMENT);