Oracles
Oracles are data feeds that connect Ethereum to off-chain, real-world information so that you can query data in your smart contracts. For example, prediction market dapps use oracles to settle payments based on events. A prediction market may ask you to bet your ETH on who will become the next president of the United States. They'll use an oracle to confirm the outcome and payout to the winners.
Prerequisites
Make sure you're familiar with nodes, consensus mechanisms, and smart contract anatomy, specifically events.
What is an oracle
An oracle is a bridge between the blockchain and the real world. They act as on-chain APIs you can query to get information into your smart contracts. This could be anything from price information to weather reports. Oracles can also be bi-directional, used to "send" data out to the real world.
Watch Patrick explain Oracles:
Why are they needed?
With a blockchain like Ethereum, you need every node in the network to replay every transaction and end up with the same result, guaranteed. APIs introduce potentially variable data. If you were sending ETH based on an agreed $USD value using a price API, the query would return a different result from one day to the next. Not to mention, the API could be hacked or deprecated. If this happens, the nodes in the network wouldn't be able to agree on Ethereum's current state, effectively breaking consensus.
Oracles solve this problem by posting the data on the blockchain. So any node replaying the transaction will use the same immutable data that's posted for all to see. To do this, an oracle is typically made up of a smart contract and some off-chain components that can query APIs, then periodically send transactions to update the smart contract's data.
The oracle problem
As we mentioned, Ethereum transactions cannot access off-chain data directly. At the same time, relying on a single source of truth to provide data is insecure and invalidates the decentralization of a smart contract. This is known as the oracle problem.
We can avoid the oracle problem by using a decentralized oracle that pulls from multiple data sources; if one data source is hacked or fails, the smart contract will still function as intended.
Security
An oracle is only as secure as its data source(s). If a dapp uses Uniswap as an oracle for its ETH/DAI price feed, an attacker can move the price on Uniswap to manipulate the dapp's understanding of the current price. An example of how to combat this is a feed system like the one used by MakerDAO, which collates price data from many external price feeds instead of just relying on a single source.
Architecture
This is an example of a simple Oracle architecture, but there are more ways than this to trigger off-chain computation.
- Emit a log with your smart contract event
- An off-chain service has subscribed (usually using something like the JSON-RPC
eth_subscribe
command) to these specific logs. - The off-chain service proceeds to do some tasks as defined by the log.
- The off-chain service responds with the data requested in a secondary transaction to the smart contract.
This is how to get data in a 1 to 1 manner, however to improve security you may want to decentralize how you collect your off-chain data.
The next step might be to have a network of these nodes making these calls to different APIs and sources, and aggregating the data on-chain.
Chainlink Off-Chain Reporting (Chainlink OCR) has improved on this methodology by having the off-chain oracle network communicate with each other, cryptographically sign their responses, aggregate their responses off-chain, and send only one transaction on-chain with the result. This way, less gas is spent, but you still get the guarantee of decentralized data since every node has signed their part of the transaction, making it unchangeable by the node sending the transaction. The escalation policy kicks in if the node doesn't transact, and the next node sends the transaction.
Usage
Using services like Chainlink, you can reference decentralized data on-chain that has already been pulled from the real world and aggregated. Sort of like a public commons, but for decentralized data. You can also build your own modular oracle networks to get any customized data you're looking for. In addition, you can do off-chain computation and send information to the real world as well. Chainlink has the infrastructure in place to:
- Get crypto price feeds in your contract
- Generate verifiable random numbers (useful for gaming)
- Call external APIs β One novel use of this is Checking wBTC reserves
Here is an example of how to get the latest ETH price in your smart contract using a Chainlink price feed:
Chainlink Data Feeds
1pragma solidity ^0.6.7;23import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol";45contract PriceConsumerV3 {67 AggregatorV3Interface internal priceFeed;89 /**10 * Network: Kovan11 * Aggregator: ETH/USD12 * Address: 0x9326BFA02ADD2366b30bacB125260Af64103133113 */14 constructor() public {15 priceFeed = AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331);16 }1718 /**19 * Returns the latest price20 */21 function getLatestPrice() public view returns (int) {22 (23 uint80 roundID,24 int price,25 uint startedAt,26 uint timeStamp,27 uint80 answeredInRound28 ) = priceFeed.latestRoundData();29 return price;30 }31}32PrikaΕΎi sveKopiraj
You can test this in remix with this link
Chainlink VRF
Chainlink VRF (Verifiable Random Function) is a provably-fair and verifiable source of randomness designed for smart contracts. Smart contract developers can use Chainlink VRF as a tamper-proof random number generation (RNG) to build reliable smart contracts for any applications which rely on unpredictable outcomes:
- Blockchain games and NFTs
- Random assignment of duties and resources (e.g. randomly assigning judges to cases)
- Choosing a representative sample for consensus mechanisms
Random numbers are difficult because blockchains are deterministic.
Working with Chainlink Oracles outside of data feeds follows the request and receive cycle of working with Chainlink. They use the LINK token to send oracle providers oracle gas for returning responses. The LINK token is specifically designed to work with oracles and are based on the upgraded ERC-677 token, which is backwards compatible with ERC-20. The following code, if deployed on the Kovan testnet will retrieve a cryptographically proven random number. To make the request, fund the contract with some testnet LINK token that you can get from the Kovan LINK Faucet.
12pragma solidity 0.6.6;34import "@chainlink/contracts/src/v0.6/VRFConsumerBase.sol";56contract RandomNumberConsumer is VRFConsumerBase {78 bytes32 internal keyHash;9 uint256 internal fee;1011 uint256 public randomResult;1213 /**14 * Constructor inherits VRFConsumerBase15 *16 * Network: Kovan17 * Chainlink VRF Coordinator address: 0xdD3782915140c8f3b190B5D67eAc6dc5760C46E918 * LINK token address: 0xa36085F69e2889c224210F603D836748e7dC008819 * Key Hash: 0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f420 */21 constructor()22 VRFConsumerBase(23 0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9, // VRF Coordinator24 0xa36085F69e2889c224210F603D836748e7dC0088 // LINK Token25 ) public26 {27 keyHash = 0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4;28 fee = 0.1 * 10 ** 18; // 0.1 LINK (varies by network)29 }3031 /**32 * Requests randomness from a user-provided seed33 */34 function getRandomNumber(uint256 userProvidedSeed) public returns (bytes32 requestId) {35 require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet");36 return requestRandomness(keyHash, fee, userProvidedSeed);37 }3839 /**40 * Callback function used by VRF Coordinator41 */42 function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {43 randomResult = randomness;44 }45}46PrikaΕΎi sve
Chainlink Keepers
Smart contracts can't trigger or initiate their own functions at arbitrary times or under arbitrary conditions. State changes will only occur when another account initiates a transaction (such as a user, oracle, or contract). The Chainlink Keeper Network provides options for smart contracts to outsource regular maintenance tasks in a trust minimized and decentralized manner.
To use Chainlink Keepers, a smart contract must implement KeeperCompatibleInterface, which consists of two functions:
checkUpkeep
- Checks if the contract requires work to be done.performUpkeep
- Performs the work on the contract, if instructed by checkUpkeep.
The example below is a simple counter contract. The counter
variable is incremented by one by every call to performUpkeep
. You can check out the following code using Remix
1// SPDX-License-Identifier: MIT2pragma solidity ^0.7.0;34// KeeperCompatible.sol imports the functions from both ./KeeperBase.sol and5// ./interfaces/KeeperCompatibleInterface.sol6import "@chainlink/contracts/src/v0.7/KeeperCompatible.sol";78contract Counter is KeeperCompatibleInterface {9 /**10 * Public counter variable11 */12 uint public counter;1314 /**15 * Use an interval in seconds and a timestamp to slow execution of Upkeep16 */17 uint public immutable interval;18 uint public lastTimeStamp;1920 constructor(uint updateInterval) {21 interval = updateInterval;22 lastTimeStamp = block.timestamp;2324 counter = 0;25 }2627 function checkUpkeep(bytes calldata /* checkData */) external override returns (bool upkeepNeeded, bytes memory /* performData */) {28 upkeepNeeded = (block.timestamp - lastTimeStamp) > interval;29 // We don't use the checkData in this example. The checkData is defined when the Upkeep was registered.30 }3132 function performUpkeep(bytes calldata /* performData */) external override {33 lastTimeStamp = block.timestamp;34 counter = counter + 1;35 // We don't use the performData in this example. The performData is generated by the Keeper's call to your checkUpkeep function36 }37}38PrikaΕΎi sve
After deploying a Keeper-compatible contract, you must register the contract for Upkeep and fund it with LINK, to notify the Keeper Network about your contract, so your work is performed continuously.
Keepers projects
Chainlink API Call
Chainlink API Calls are the easiest way to get data from the off-chain world in the traditional way the web works: API calls. Doing a single instance of this and having only one oracle makes it centralized by nature. To keep it truly decentralized, a smart contract platform would need to use numerous nodes found in an external data market.
Deploy the following code in remix on the kovan network to test
This also follows the request and receive cycle of oracles and needs the contract to be funded with Kovan LINK (the oracle gas) to work.
1pragma solidity ^0.6.0;23import "@chainlink/contracts/src/v0.6/ChainlinkClient.sol";45contract APIConsumer is ChainlinkClient {67 uint256 public volume;89 address private oracle;10 bytes32 private jobId;11 uint256 private fee;1213 /**14 * Network: Kovan15 * Oracle: 0x2f90A6D021db21e1B2A077c5a37B3C7E75D15b7e16 * Job ID: 29fa9aa13bf1468788b7cc4a500a45b817 * Fee: 0.1 LINK18 */19 constructor() public {20 setPublicChainlinkToken();21 oracle = 0x2f90A6D021db21e1B2A077c5a37B3C7E75D15b7e;22 jobId = "29fa9aa13bf1468788b7cc4a500a45b8";23 fee = 0.1 * 10 ** 18; // 0.1 LINK24 }2526 /**27 * Create a Chainlink request to retrieve API response, find the target28 * data, then multiply by 1000000000000000000 (to remove decimal places from data).29 */30 function requestVolumeData() public returns (bytes32 requestId)31 {32 Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);3334 // Set the URL to perform the GET request on35 request.add("get", "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD");3637 // Set the path to find the desired data in the API response, where the response format is:38 // {"RAW":39 // {"ETH":40 // {"USD":41 // {42 // "VOLUME24HOUR": xxx.xxx,43 // }44 // }45 // }46 // }47 request.add("path", "RAW.ETH.USD.VOLUME24HOUR");4849 // Multiply the result by 1000000000000000000 to remove decimals50 int timesAmount = 10**18;51 request.addInt("times", timesAmount);5253 // Sends the request54 return sendChainlinkRequestTo(oracle, request, fee);55 }5657 /**58 * Receive the response in the form of uint25659 */60 function fulfill(bytes32 _requestId, uint256 _volume) public recordChainlinkFulfillment(_requestId)61 {62 volume = _volume;63 }64}65PrikaΕΎi sve
You can learn more about the applications of Chainlink by reading the Chainlink developers blog.
Oracle services
Build an oracle smart contract
Here's an example oracle contract by Pedro Costa. You can find further annotation in his article: Implementing a Blockchain Oracle on Ethereum.
1pragma solidity >=0.4.21 <0.6.0;23contract Oracle {4 Request[] requests; //list of requests made to the contract5 uint currentId = 0; //increasing request id6 uint minQuorum = 2; //minimum number of responses to receive before declaring final result7 uint totalOracleCount = 3; // Hardcoded oracle count89 // defines a general api request10 struct Request {11 uint id; //request id12 string urlToQuery; //API url13 string attributeToFetch; //json attribute (key) to retrieve in the response14 string agreedValue; //value from key15 mapping(uint => string) anwers; //answers provided by the oracles16 mapping(address => uint) quorum; //oracles which will query the answer (1=oracle hasn't voted, 2=oracle has voted)17 }1819 //event that triggers oracle outside of the blockchain20 event NewRequest (21 uint id,22 string urlToQuery,23 string attributeToFetch24 );2526 //triggered when there's a consensus on the final result27 event UpdatedRequest (28 uint id,29 string urlToQuery,30 string attributeToFetch,31 string agreedValue32 );3334 function createRequest (35 string memory _urlToQuery,36 string memory _attributeToFetch37 )38 public39 {40 uint lenght = requests.push(Request(currentId, _urlToQuery, _attributeToFetch, ""));41 Request storage r = requests[lenght-1];4243 // Hardcoded oracles address44 r.quorum[address(0x6c2339b46F41a06f09CA0051ddAD54D1e582bA77)] = 1;45 r.quorum[address(0xb5346CF224c02186606e5f89EACC21eC25398077)] = 1;46 r.quorum[address(0xa2997F1CA363D11a0a35bB1Ac0Ff7849bc13e914)] = 1;4748 // launch an event to be detected by oracle outside of blockchain49 emit NewRequest (50 currentId,51 _urlToQuery,52 _attributeToFetch53 );5455 // increase request id56 currentId++;57 }5859 //called by the oracle to record its answer60 function updateRequest (61 uint _id,62 string memory _valueRetrieved63 ) public {6465 Request storage currRequest = requests[_id];6667 //check if oracle is in the list of trusted oracles68 //and if the oracle hasn't voted yet69 if(currRequest.quorum[address(msg.sender)] == 1){7071 //marking that this address has voted72 currRequest.quorum[msg.sender] = 2;7374 //iterate through "array" of answers until a position if free and save the retrieved value75 uint tmpI = 0;76 bool found = false;77 while(!found) {78 //find first empty slot79 if(bytes(currRequest.anwers[tmpI]).length == 0){80 found = true;81 currRequest.anwers[tmpI] = _valueRetrieved;82 }83 tmpI++;84 }8586 uint currentQuorum = 0;8788 //iterate through oracle list and check if enough oracles(minimum quorum)89 //have voted the same answer has the current one90 for(uint i = 0; i < totalOracleCount; i++){91 bytes memory a = bytes(currRequest.anwers[i]);92 bytes memory b = bytes(_valueRetrieved);9394 if(keccak256(a) == keccak256(b)){95 currentQuorum++;96 if(currentQuorum >= minQuorum){97 currRequest.agreedValue = _valueRetrieved;98 emit UpdatedRequest (99 currRequest.id,100 currRequest.urlToQuery,101 currRequest.attributeToFetch,102 currRequest.agreedValue103 );104 }105 }106 }107 }108 }109}110PrikaΕΎi sveKopiraj
We'd love more documentation on creating an oracle smart contract. If you can help, create a PR!
Further reading
Articles
- What Is a Blockchain Oracle? - Chainlink
- Oracles β EthHub
- What is a Blockchain Oracle? - Patrick Collins
- Decentralised Oracles: a comprehensive overview β Julien Thevenard
- Implementing a Blockchain Oracle on Ethereum β Pedro Costa
- Why can't smart contracts make API calls? - StackExchange
- Why we need decentralized oracles - Bankless
- So you want to use a price oracle -samczsun
Videos
- Oracles and the Expansion of Blockchain Utility - Real Vision Finance
Tutorials
Example projects
Pomozite nam s ovom stranicom
Ako ste struΔnjak za tu temu i ΕΎelite dati svoj doprinos, uredite ovu stranicu i obasjajte je svojom mudroΕ‘Δu.
Bit Δete nagraΔeni i pomoΔi Δete Ethereumovoj zajednici!
Upotrebljavajte to fleksibilno predloΕΎak dokumentacije
Pitanja? Pitajte nas na kanalu #content na naΕ‘em PosluΕΎitelj Discord
Uredi stranicu