Smart Contracts, APIs, and How You Can Make Them Communicate
Today, blockchain technology is being used more than ever. The complexity of available tools and possibilities provided by new protocols, such as Ethereum’s Smart-Contracts, allows it to be used as a solution in many industries, from supply chains to gambling or voting systems.
ClanPlay is introducing a marketplace of in-game actions and chose blockchain as a fundamental technology, as it allows us to provide the features described on our Whitepaper in a trust-less and efficient way. The core feature of our system is the ability to make contracts between players, which are resolved based on 3rd party game data.
While all contracts are deployed to a blockchain, the Authorization Nodes that track in-game actions and resolve the contracts operate off-chain.
Which brings us to the question: How can a Smart contract communicate with an external server API?
Our problem is that a Smart contract, as an object on the blockchain, can’t just send an HTTP request. It would contradict a fundamental principle of all blockchain protocols — their deterministic nature.
The determinism of a blockchain means that the result of any transaction must always be the same, regardless of where, when and how many times you perform it. However, if a transaction logic depends on an external request, the result might vary due to connection problems or the external server’s state, which would break the determinism and the ability to reach a consensus.
Does it mean there is no way to request data from an external server? Nope, there are some tricks
Ask the Oracle
The most common solution is an “oracle pattern”.
- The Oracle service is observing Smart Contract events.
- When the contract emits a special type of event with a request definition, the Oracle service requests the data from an external API.
- A response is then injected by the Oracle service into the smart contract using one of its methods.
Coming up is a review of an existing out-of-the-box solution, and a review of how you can build your own from scratch.
Oraclize.it provides a ready-made “oracle pattern” solution with their query feature that can be used to send a request and receive the response to the callback method of your contract.
The service is popular among blockchain developers and is integrated natively with major protocols, such as Ethereum and Bitcoin mainnets and testnets. It is a good option for a fast start.
Yet, using a pre-made solution carries some disadvantages:
- The request definition and all the parameters are stored on a blockchain which is publicly accessible. This raises a security issue if you need to use it to access any API methods which require privacy.
- Relying on a third-party infrastructure makes you susceptible to their downtime and security breaches.
- Obviously, Oraclize.it is not free. You will have to pay Gas to perform on-blockchain actions, and additional commissions which can become quite substantial
Do It Yourself
After reviewing a pre-made solution and looking at its disadvantages, you might decide that you’re better off with creating your own. As a use-case, we will create a simple betting system.
Some third-party API in our sample returns the winner by matchId. Our BettingArenaContract will be used to place a bet in Ether by matchId. The accumulated prize will be distributed among the winners according to the response of the API.
- The way the contracts works:
- Users place bets using the join method
- Resolve function initiate the raffle for a match by an emission of an HTTPRequest event. We should use events and not just a storage because they are much less expensive in Gas.
- An external service (oracle) (we will review it’s possible implementation later) observes the event and sends the request to the API to figure out the winner.
- Oracle calls distributePrize method of the contract to distribute rewards.
2. We used only one trusted address as a source of external data, but we can easily switch to a set of trusted addresses, which can be managed by logic with multiple signatures if needed.
3. In a real-life contract, the join should be limited by time to prevent joining after the match is finished
4. The entity performing ‘resolve’ and ‘distributePrize’ calls, should be included in the prize distribution to motivate usage and compensate the Gas spent for the call
5. Responses must be matched with their corresponding requests, which is challenging as their order isn’t defined. We use getRequestsID() function to generate a unique request id which will be used by an oracle as an indexing parameter in the distributePrize function
Example of an HTTPRequest event object:
External Observer Implementation
You can use a web3.js framework in the backend to read and observe the events. After setting up this framework, you can get the contract object by address and access its events by name.
As you can see, while requesting data from an external server brings complexity and additional expenses to your system, it gives much more flexibility and opportunities, including off-chain data sources, which can open up valuable use cases.