用ChainLink访问区块链外部数据【Solidity合约开发】

在这个教程中,我们将学习如何搜索Chainlink Market以找到满足 需求的Chainlink预言机(Oracle),以及如何编写Solidity智能合约实现 通过预言机访问区块链外部数据(例如货币价格)的功能。

用自己熟悉的语言学习 以太坊DApp开发Java | Php | Python | .Net / C# | Golang | Node.JS | Flutter / Dart

由于区块链生态系统的本质,从链上的智能合约直接访问链下数据是不可能的。但是, Chainlink为区块链预言机提供了一个平台,这些预言机 充当链上和链外数据之间的桥梁。预言机使智能合约能够从区块链 外部获取数据。

可以将每个预言机节点配置为执行各种任务,具体取决于其支持的适配器。 其中一些适配器包括HTTP GET,HTTP POST,JSON Parse,Multiply等的实现。

1、Chainlink预言机简介

假设我们要创建一个智能合约,该合约将根据CoinGecko上的以太坊美元价格做出不同 的响应。我们知道智能合约没有办法调用外部HTTP API,但是oracle节点可以。

通过请求-响应周期处理,智能合约就可以从oracle节点请求数据,该节点 被配置为执行HTTP GET请求,并为oracle实现一个回调函数以执行响应:

我们不能简单地使用任意预言机,因为每个预言机都被配置为执行特定的任务,这 具体取决于其支持的适配器。为了找到满足要求的高质量预言机,我们必须使用像 Chainlink Market之类的清单服务。

Chainlink的预言机列表服务有助于我们找到满足要求的预言机。流行的API通常具有 预配置的对某些端点的请求的预言机实现,这会使我们的开发更加容易。在Chainlink Market 主页搜索栏中键入“ CoinGecko”,我们可以确认是否有预言机已经实现了所需的CoinGecko端点:

如上图所示,我们的确得到了一些结果!

“节点”部分列出了符合搜索字符串的预言机节点。这可能意味着它们支持从CoinGecko API检索数据的作业。 在可用的三个节点中,Omniscience-Ropsten已验证(带圆圈),这表明了其可信度。此外它还有数量最高 的运行作业(Jobs)。

向下滚动,我们可以在作业(Jobs)标题下看到ETH-USD CoinGecko。这看起来很完美,因为它似乎 准确描述我们想要检索的数据,并使用经过验证的节点。单击该链接可以查看该作业的更多信息:

上图显示了预言机节点的详细信息。在左侧(红色矩形内)是Oracle的链上地址。如果要使用此oracle, 则需要记下该地址。在屏幕的右侧是三个选项卡:适配器、数据源和作业。单击作业(Jobs)并滚动, 直到找到ETH-USD CoinGecko。单击该链接以显示工作信息页面:

上图显示了作业信息页面,在该页面中可以查看其在请求时工作的详细信息。突出显示了作业ID和运行 此作业的成本(这些也需要记下)。页面右侧是“任务列表”。这是作业在被调用时执行操作的列表。 每个任务使用一个被支持的适配器,逐个创建任务链。让我们遍历列表中的每个任务,以找出作业 如何获取所需的数据:

2.1 HTTP GET请求

第一个任务是使用HTTP GET调用CoinGecko API。我们可以从参数中的URL确认它发出了正确的CoinGecko请求。 这将返回JSON响应结果。

2.2 JSON响应解析

由于任务1返回JSON,因此下一个任务需要对其进行解析以便访问我们需要的目标数据。 任务2使用JSON Parse适配器通过提供的路径遍历返回的JSON对象。例如,任务2路径中的 目标数据将位于以下JSON结构中:

1
2
3
4
5
6
7
8
9
{ 
“ market_data”:
{
“ current_price”:
{
“ usd”:“ PRICE_HERE”
}
}
}

2.3 相乘计算

我们已经从JSON结果中得到了价格,但这还没有处理完。由于Solidity无法处理小数, 因此任务3将价格乘以100,000,000以确保可以将其表示为整数。

2.4 ETH Int256

然后,任务4将结果转换为编码的int256。

2.5 ETH交易

最后,任务5创建一个以太坊交易,以将结果发送回原始合约。

3、编写合约调用预言机

现在,让我们写一个请求预言机服务的合约。Chainlink提供了一个模板合约ChainlinkClient, 我们将在此基础上进行扩展:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
pragma solidity 0.6.0;

import "https://github.com/smartcontractkit/chainlink/evm-contracts/src/v0.6/ChainlinkClient.sol";
import "https://github.com/smartcontractkit/chainlink/evm-contracts/src/v0.6/vendor/Ownable.sol";

contract ExampleOracleClient is ChainlinkClient, Ownable {
address constant private ORACLE = 0x83dA1beEb89Ffaf56d0B7C50aFB0A66Fb4DF8cB1;
string constant private JOB_ID = "93547cb3c6784ec08a366be6211caa24";
uint256 constant private ORACLE_PAYMENT = 1 * LINK / 10;

uint256 public currentPrice;

event RequestEthereumPriceFulfilled(
bytes32 indexed requestId,
uint256 indexed price
);

constructor() public Ownable() {
setPublicChainlinkToken();
}

function requestEthereumPrice() public onlyOwner {
Chainlink.Request memory req = buildChainlinkRequest(stringToBytes32(JOB_ID), address(this), this.fulfillEthereumPrice.selector);
sendChainlinkRequestTo(ORACLE, req, ORACLE_PAYMENT);
}

function fulfillEthereumPrice(bytes32 _requestId, uint256 _price) public recordChainlinkFulfillment(_requestId) {
emit RequestEthereumPriceFulfilled(_requestId, _price);
currentPrice = _price;
}

function withdrawLink() public onlyOwner {
LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
require(link.transfer(msg.sender, link.balanceOf(address(this))), "Unable to transfer");
}

function stringToBytes32(string memory source) private pure returns (bytes32 result) {
bytes memory tempEmptyStringTest = bytes(source);
if (tempEmptyStringTest.length == 0) {
return 0x0;
}

assembly { // solhint-disable-line no-inline-assembly
result := mload(add(source, 32))
}
}
}

上面的ExampleOracleClient合约,利用预言机向CoinGecko请求以太坊的最新美元价格。 让我们逐行说明:

  • 第7行:节点详细信息页面找到的预言机地址
  • 第8和9行:前面找到的作业ID和价格
  • 第11行: currentPrice是由执行请求的预言机填充的字段。
  • 第19行: setPublicChainlinkToken()是ChainlinkClient合同中提供的功能,用于设置当前网络上LINK令牌的地址。
  • 第22–25行: requestEthereumPrice()使用oracle地址、作业ID、价格和回调函数构建Chainlink请求。然后调用sendChainlinkRequestTo(),它使用父ChainlinkClient合同提供的另一个功能来请求数据。
  • 第27行: Oracle用于完成请求的回调函数
  • 第32行:使所有者能够从合约中提取LINK令牌的功能
  • 第37行:用于构建请求的辅助功能实现

尝试将此合约粘贴到Remix IDE中并部署到Ropsten测试网。部署后, 向其地址发送一些Ropsten LINK(可以在此处找到Ropsten LINK Faucet)。 当该交易成功完成后,单击requestEthereumPrice方法按钮。稍等一会儿后,单击currentPrice按钮, 你应该会看到价格:

4、结论

Chainlink预言机是强大的工具,可实现外部世界与区块链之间的互操作性。诸如Chainlink Market之类的 清单服务是一种有用的目录服务,用于查找最适合需求的预言机。

在本教程示例中,我们找到了一个满足需求的预言机作业,该作业已经配置为从目标服务请求数据。 预言机还支持接受GET请求URL作为参数并从中获取数据的作业。这意味着你可以使用Chainlink预言机 从任何外部API检索数据。


原文链接:How to Call APIs From Ethereum Smart Contracts

汇智网翻译整理,转载请标明出处