Chainlink Oracle Series (Part 1)

avatar
ZAN Team
4 days ago
This article is approximately 1655 words,and reading the entire article takes about 3 minutes
In the blockchain field, an oracle is a system that can provide external information to smart contracts on the chain. As the middleware connecting smart contracts and the world outside the blockchain, the oracle plays an extremely critical infrastructure role. Its main function is to provide data for smart contracts in the blockchain.

In the blockchain field, an oracle is a system that can provide external information to smart contracts on the chain. As the middleware connecting smart contracts and the world outside the blockchain, the oracle plays an extremely critical infrastructure role. Its main function is to provide data for smart contracts in the blockchain.

For example, if we create a smart contract on the Ethereum network, and this contract needs to access the trading volume data of crude oil on a certain day. However, the smart contract itself cannot obtain this kind of real-world data off-chain, so it needs to be implemented through an oracle. In this case, the smart contract will write the crude oil trading volume on the required date into the event log, and then a process will be started off-chain to monitor and subscribe to this event log. When a request in a transaction is monitored, the process will upload the crude oil trading volume information on the specified date to the smart contract by submitting an on-chain transaction and calling the relevant method of the contract.

Chainlink Oracle Series (Part 1)

Data from https://defillama.com/oracles

Chainlink

In the blockchain, the Chainlink oracle has the largest market share. Chainlink is a decentralized oracle project that provides real-world data to the blockchain in the most secure way. Chainlink has established a virtuous cycle ecosystem around the LINK token through economic incentives based on the implementation of the basic oracle principle. The Chainlink oracle needs to be triggered by the transfer of LINK tokens. LINK is an ERC 677 contract on the Ethereum network. The oracle function based on the LINK ERC 677 token belongs to the request/response mode.

transferAndCall in ERC 677 tokens

Chainlink Oracle Series (Part 1)

The oracle is essentially the party that provides the service. When ChainLink designed the oracle framework, the first thing it thought of was how the oracle users could pay the oracle for the service. However, since the standard homogeneous token contract ERC 20 cannot meet the requirement of providing services after payment, ChainLink proposed a standard suitable for oracle service scenarios - ERC 677.

As can be seen from the above code, ERC 677 actually just adds a transferAndCall method based on the standard ERC 20. This method combines payment and service request into one, meeting the needs of oracle business scenarios.

Chainlink Oracle Series (Part 1)

When a user performs a transferAndCall, in addition to ERC 20 transfers, it will also determine whether the to address is a contract address. If so, the onTokenTransfer method of the to address will be called. (Here, there is only one method in ERC 677 Receiver: onTokenTransfer)

We can also go to Etherscan to view the contract source code of the LINK token: https://etherscan.io/address/0x514910771af9ca656af840dff83e8264ecf986ca#code

Chainlink Oracle Series (Part 1)

It can be seen that LINK Token actually inherits the transferAndCall method of ERC 677 except for the verification of the _to address when it is implemented. Note: Before requesting the oracle service, you must first determine whether the oracle is trustworthy, because the oracle needs to be paid before providing services to consumers. (Everyone can provide oracle services)

Chainlink Oracle Series (Part 1)

Oracle credibility classification

On-chain oracle request

Lets take a look at how the onTokenTransfer method of the oracle contract is implemented:

Chainlink Oracle Series (Part 1)

When the oracle consumer uses the transferAndCall method to pay the fee and request the oracles service, the to address here is the address of the requested oracle. The onTokenTransfer method in the oracle will first verify whether the transfer is a LINK token (onlyLINK), which is actually to determine whether msg.sender is the address of the Link token contract. Then it will determine whether the length of _data exceeds the maximum limit. Finally, it will determine whether there is a function selector starting with oracleRequest in _data. Of course, the function selector here can be customized according to the services provided by the oracle, and it does not have to be oracleRequest, depending on what kind of interface the oracle exposes to the outside world.

When all these modifiers are checked, the current function caller and the transfer amount are checked to see if they are the same as those in _data. After all these security checks are passed, the current oracle contract is called through a delegatecall. Of course, because the function selector in _data has been checked, it is actually the oracleRequest method that is called.

Chainlink Oracle Series (Part 1)

First, concatenate the oracle requester and the nonce he sent and then hash them as the requestId for this request, and check the commitments mapping to see if it is a unique id. If the check is OK, set an expiration time, add the requestId to the commitments, and concatenate _payment, _callbackAddress, _callbackFunctionId and expiration as the value. Most importantly, issue an OracleRequest event, which contains the request data _data, which is a Concise Binary Object Representation (CBOR) data. The encoding format is lightweight and concise, and can be simply understood as a binary JSON format. This data can be in various forms, depending on how the off-chain nodes are designed.

For example, a Chainlink: ETH/USD Aggregator has a transaction that contains an OracleRequest event:

Chainlink Oracle Series (Part 1)

OracleRequest Event Example

From this event, we can see that the ETH/USD price aggregator 0xF79D6aFBb6dA890132F9D7c355e3015f15F3406F sent a price data request to the oracle: 0x7e94a8a23687d8c7058ba5625db2ce358bcbd244. If the oracle returns the request data, we can know the returned contract address: 0xF79D6aFBb6dA890132F9D7c355e3015f15F3406F, the method ID to be called: 6 A 9705 B 4, and the expiration time: 1618185924.

Off-chain node response

3.1 Call fulfillOracleRequest off-chain

Chainlink Oracle Series (Part 1)

First check:

  • onlyAuthorizedNode: The function caller (msg.sender) must be the owner of the contract or in the authorized list;

  • isValidRequest: still checks whether the requestId exists in the commitments mapping;

  • Concatenate payment, callbackAddress, _callbackFunctionId and expiration, and check whether they are the corresponding values of the requestId in the commitments map.

If all these checks pass, the cost of this request is added to withdrawableTokens to record the amount that can be withdrawn. The _requestId is then deleted from the commitments mapping. Finally, the remaining gas amount is calculated to see if it is greater than MINIMUM_CONSUMER_GAS_LIMIT, which is the minimum amount of gas required to execute the callback function of the contract that issued the request.

If all the above checks are passed, the callback function of the requester contract can be formally called in the form of call.

The response to the request should be as fast as possible, so it is recommended to use ZANs node service ( https://zan.top/home/node-service?chInfo=ch_WZ ) to improve the response speed. You can find the corresponding RPC link in the node service console to increase the speed of sending transactions off-chain.

Chainlink Oracle Series (Part 1)

3.2 Callback Function

We previously learned from oracleRequest that the callback function id is 6 A 9705 B 4 , and the method is chainlinkCallback(bytes 32, int 256

Chainlink Oracle Series (Part 1)

Chainlink Oracle Series (Part 1)

validateChainlinkCallback is a customizable function, here is a modifier:

Chainlink Oracle Series (Part 1)

In pendingRequests, check whether the oracle corresponding to the request for _requestId matches. And emit the event ChainlinkFulfilled:

Chainlink Oracle Series (Part 1)

If all the checks are passed, then the responses can be further processed, where the answers mapping is updated. If it is a price oracle, the price data of the response is assigned to currentPrice to update the price accordingly:

Chainlink Oracle Series (Part 1)

The above is the complete process of the general oracle service.

Let’s take a “requestEthereumPrice” method in the “TestnetConsumer” contract provided by Chainlink as an example to briefly explain the process of price oracle request response. This function is defined as follows:

Chainlink Oracle Series (Part 1)

The function it implements is to obtain the ETH/USD transaction price from the specified API (cryptocompare). The parameters passed into the function are the specified oracle address and jobId. After a series of request parameters are assembled, the sendChainlinkRequestTo method is called to send the request. sendChainlinkRequestTo is an interface method defined in the library provided by Chainlink, and is defined as follows:

Chainlink Oracle Series (Part 1)

After receiving the transfer, the Oracle contract will trigger the onTokenTransfer method, which will check the validity of the transfer and record more detailed data information by issuing the OracleRequest event.

This log will be found in the oracle contract log. The nodes under the chain will subscribe to the log of this topic. After obtaining the recorded log information, the node will parse the specific information of the request and obtain the result of the request through the network API call. Then, by submitting the transaction, the fulfillOracleRequest method in the Oracle contract is called to submit the data to the chain.

After performing a series of checks, this method will return the results to the consumer contract through the previously recorded callback address and callback function.

As a developer, I just want to use the existing currency pair prices without specifying these URLs myself. Is that possible?

The answer is yes. The first way to use it is as follows:

Chainlink Oracle Series (Part 1)

First, each trading pair has a separate Price Feed, also called Aggregator, which is actually an AggregatorProxy, as shown below:

Chainlink Oracle Series (Part 1)

The specific implementation of this interface is relatively simple, you can refer to the AAVE/ETH pair: https://etherscan.io/address/0x6Df09E975c830ECae5bd4eD9d90f3A95a4f88012#code

There are 5 query methods in total:

  • decimals(): The number of digits of precision of the returned price data, usually 8 or 18

  • description(): usually the name of the trading pair, such as ETH / USD

  • version(): Mainly used to identify the type of Aggregator that the Proxy points to

  • getRoundData(_roundId): Get the current price data based on the round ID

  • latestRoundData(): Get the latest price data

In most application scenarios, the contract may only need to read the latest price, that is, call the last method, and the answer in the return parameter is the latest price.

In addition, most applications use USD as the unit of measurement for reading tokens. If so, you will find that the precision of a pair priced in USD is uniformly 8 digits, so generally there is no need to handle different precision issues for different tokens.

This article was written by XiG (X account @SHXiGi ) of ZAN Team (X account @zan_team ).

Original article, author:ZAN Team。Reprint/Content Collaboration/For Reporting, Please Contact report@odaily.email;Illegal reprinting must be punished by law.

ODAILY reminds readers to establish correct monetary and investment concepts, rationally view blockchain, and effectively improve risk awareness; We can actively report and report any illegal or criminal clues discovered to relevant departments.

Recommended Reading
Editor’s Picks