在Solidity合约中调用Chainlink预言机

在这个教程中,我们将学习如何搜索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实现一个回调函数以执行响应:
在Solidity合约中调用Chainlink预言机

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

2、用Chainlink Market搜索符合需求的预言机

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

在Solidity合约中调用Chainlink预言机

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

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

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

在Solidity合约中调用Chainlink预言机

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

在Solidity合约中调用Chainlink预言机

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

2.1 HTTP GET请求

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XEhjkfHd-1595382259128)(contract-oracle/http-get.png)]

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

2.2 JSON响应解析

在Solidity合约中调用Chainlink预言机

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

{ 
  “ market_data”:
    { 
      “ current_price”:
        { 
          “ usd”:“ PRICE_HERE” 
        } 
    } 
}

2.3 相乘计算

在Solidity合约中调用Chainlink预言机

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

2.4 ETH Int256

在Solidity合约中调用Chainlink预言机

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

2.5 ETH交易

在Solidity合约中调用Chainlink预言机

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

3、编写合约调用预言机

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

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按钮,你应该会看到价格:

在Solidity合约中调用Chainlink预言机

4、结论

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

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


原文链接:用ChainLink访问区块链外部数据 — 汇智网

上一篇:奇瑞汽车股份有限公司 奇瑞汽车将LMS Samtech Tea Pipe作为新车型开发项目的必备验证工具


下一篇:H5项目开发分享——用Canvas合成文字