Allow the blockchain access to your API with Oracle proxies
Oracles are one of my favorite blockchain features(?), don’t know if they are features but they are awesome. They allow you to use real-world data in your smart contract, and I’m all about real-world use-cases.
One of the Oracle leaders is of course Chainlink. They have a solid network of oracles and also a very easy-to-use oracle contracts.
There are a few different types of oracle services they provide:
Secure random number generator
This service is called Chainlink VRF which stands for Verifiable Random Function, this means the random values coming out of this function can be verified that they are indeed random. There is a cryptographic proof generated for each random number that makes us confident that the random value hasn’t been tempered by oracle operators, miners or developers.
Data feeds
The most common usage of oracles is to get conversion rates between currencies. We can get the conversion rates for tokens from decentralized exchanges but to get the rates for the US Dollar or Euro against Ethereum for example, we must use oracle data feeds. So that is what Chainlink data feed oracles do, they provide a conversion rate between currencies across many different chains, full list here.
Any API
This is my favorite part, Chainlink allows us to call any Web2.0 API and use that data in our smart contracts. This opens up possibilities for any normal business domain to join the blockchain space and build something cool on top of its data. There are some limitations here, the API calls are actually done by Oracle providers so it’s difficult to fetch user-specific information from an API, we can’t pass in an authentication token or custom header, as far as I’ve discovered.
What we are building
Any API provider can make their data available on the Blockchain. In fact, there is nothing they need to do to make the data available, developers can use Oracles to call any API. However, to actually use the oracle network it costs money, in the case of Chainlink, you must pay in their Link token. So an API provider can create an oracle client proxy for their API that they can fund themselves to drive the adoption of their data to the blockchain.
We will write a contract that an API provider can fund and the users can make some API calls for free. Of course, we’ll create some checks so one person doesn’t spend all the calls.
I will start the contract by copying the single-word example from Chainlink’s documentation.
The logic above is very well explained in Chainlink’s docs so I’m not going to go over it. But here we have a simple call to Coinmarketcap’s API to fetch the Ethereum 24 hour trading volume.
Now let’s say Coinmarketcap or some of their competitors want to promote their data on the blockchain. We are going to add some functions that allow their users to call this API for free, once per day.
Funding the contract
Step 1 is to have LINK tokens available in the smart contract, because during the call to the oracle, the ChainlinkClient that we inherit from will need to send 0.1 LINK token on every call for updating the data. However, once we make the first API call, the value will be there to be read for free (except gas fees). But after some time the data is stale and it needs to be re-fetched again. There is nothing to code here, the tokens just need to be transferred to the contract address once it is deployed.
Free call function
Let’s create a function that is free to call but it will limit users to call it once per day or once every 6,000 blocks mined. For this, we will start with a modifier.
This modifier makes sure that one address makes only one free API call per 6,000 blocks.
Then I modified the requestVolumeData from the original example, first renamed it to requestFreeData and added the onlyOncePerDay modifier.
Then because we want other contracts to call this one and other contracts should receive the API result we need to add two function arguments, the other contract address and the other contract’s function.
Previously this same contract was the receiver of the API data in the fulfill function, but now we’ll let our users provide their own contract address and function selector from their contract that will receive the API result.
Using our Proxy in the real world
Let’s create another Client contract that will use our Oracle proxy from above to make some free calls and try out our service.
It’s a small bit of code so I’ll paste all of it at once.
Our Client must know the address of our Oracle proxy from above so we pass it in the constructor, and it must import the contract so it knows it’s interface.
Then we just have a simple getApiData function that calls the free function from our oracle proxy, here we pass in the address of this Client contract as well as the callback function selector from this contract. The function selector returns the first 4 bytes of the function signature which is enough to uniquely identify the function withing a contract. This is similar to JavaScript or Python where you can pass in function as arguments, same principle.
One more thing that needs to be mentioned is that in our callback function we must call recordChainlinkFulfillment that will notify Chainlink the request has returned data, otherwise we might get multiple calls and also overload the Chainlink network unnecessarily. And in order to call this, our contract again must inherit from ChainlinkClient.