**


随着DeFi利用翻新在以太坊网络上的减速迭代,各类DeFi协定的自由组合,以及预言机桥接内部数据的加持,逻辑复杂度更高的DeFi利用协定在不断涌现。一方面,对开发者来说,部署一个具备肯定复杂度的智能合约我的项目所要付出的老本开始逐步攀升,动辄十几个到几十个以太坊的费用,价格不菲。另一方面,对于用户而言,应用这些DeFi协定所要付出的gas费用也在逐步减少。因为以太坊网络自身受限于PoW共识算法(现阶段支流,非以太坊2.0)带来的低TPS,使得交易的手续费变高,但变高是用的人多所导致的市场博弈的后果。


而从另一个踊跃的角度来看,用的人多正反映着生态的凋敝,以及市场的关注度高,翻新在以太坊生态中层出不穷,所以如何放弃智能合约利用依然留存在以太坊生态的同时还能升高手续费、晋升交易速度等体验,正是Layer 2网络想要探讨的课题。


在本文中咱们将通过实例来演示如何在Layer 2网络xDAIChain上部署智能合约,并通过Chainlink预言机为部署在xDAIChain上的智能合约提供高质量的、防篡改的内部数据,在案例局部咱们会展现Chainlink的喂价机制如何在xDAIChain上应用。

xDAIChain简介


xDAIChain是一种以太坊网络的Layer 2实现计划,所采纳的实现形式是基于侧链机制,它采纳了新的共识算法POSDAO,一种基于dPoS的共识算法模型。xDAIChain上的交易确认工夫更快,约为5秒,同时在xDAIChain上的交易手续费更低,500笔交易所要付出的费用约为0.01刀。另外正如它的名称所示意的,在xDAIChain链上的原生代币是XDAI,和主网上的DAI1:1兑换,领取交易费用为稳固币,可能给予用户更好的交易成本预期。

合约调用喂价和链下调用喂价的比拟

Matic也是一种侧链实现,在Chainlink社区的之前文章中有专门解说如何在Matic网络上应用Chainlink预言机。Matic网络上曾经实现了Chainlink的整合,因而能够在Matic网络上链上调用Chainlink合约,蕴含喂价,随机数生成等性能。以后在xDAI上,Chainlink的整合还未齐全公开,因而本文中的示例中,实用于曾经部署在主网或者Kovan等测试网上的Chainlink智能合约,并以Kovan测试网作为示例,主网或者其余测试网能够类比迁徙。架构如下:



以Chainlink喂价为例,当初Chainlink官网文档上提供了Matic的喂价合约地址,然而xDAI没有,所以可能在xDAIChain上获取链下价格数据所要采纳的形式略有不同。咱们将通过Node.js脚本取以太坊网络上喂价合约提供的数据,并将其被动更新到xDAIChain上的合约中。


上面咱们将进入到教程的实际环节。

xDAI智能合约的部署筹备工作

为了后续步骤的推动,咱们须要先筹备好部署合约的账户,本教程采纳的钱包为MetaMask,对于钱包的网络设定,以及代币的获取会顺次开展。


但在此之前,须要阐明的一个点是,xDAI网络没有测试网络能够应用,所以部署合约也是间接部署到xDAI侧链的主网,所耗费的是具备实在价值的资产。尽管费用不会很高,但基于测试目标,咱们能够抉择在另一个测试网络POA Sokol网络上执行部署、交互测试。等确认无误后,只须要批改一点配置文件,即可无缝迁徙到xDAI测试网络。


另外,xDAIChain上的原生代币为XDAI,POA Sokol上的原生代币为POA。xDAIChain提供的获取原生代币的水龙头地址为:https://xdai-faucet.top/,能够获取0.01XDAI。





然而在行文时,拜访此水龙头发现并不能通过这个网站实现XDAI的获取,通过debug发现,拜访人数过多导致无奈申请,在官网社群中有开发者给出答案说是临时不可用,因为这是有实在价值的代币。在社群中能够申请管理员给0.01XDAI用于开发测试,告知你的钱包地址即可,或者能够通过购买DAI,并通过资产桥:https://docs.tokenbridge.net/xdai-bridge/about 转换为在xDAIChain上的XDAI。


另注:在社群中询问此问题时,会有一些间接私信你的其余用户,经常顶着社群管理员的头像和名字(社群容许名称和头像与实在管理员雷同,且私聊不会显示社群中的tag)会给出一些所谓的通过walletconnect这样的网站,个别会说因为数据库更新导致无奈连贯,而后给出一个钓鱼网站,须要你输出本人的私钥或者助记词来从新连贯,这都是属于骗取公有信息,留神防备。

POA Sokol测试网络信息增加


POA Sokol网络是另一种侧链实现,基于POA共识算法,其中POA共识算法能够看作是对dPoS算法的一种改良,它要求参加竞选的节点提供真实世界的信用信息。


在POA Sokol网络上获取测试代币POA则简略许多。步骤开展如下。

步骤一:设置钱包网络信息

点击MetaMask菜单栏,选择网络,下拉到Custom RPC,点击进入,配置网络信息如下:



要害信息字段如下:

  • RPC地址:https://sokol.poa.network
  • 链ID:77
  • 原生代币符号:POA
  • 区块浏览器地址:https://blockscout.com/poa/sokol


配置实现后,点击保留,此时查看钱包余额:





上面进入测试代币获取步骤。

步骤二:获取测试代币

拜访测试代币水龙头地址:https://faucet-sokol.herokuapp.com/,并输出本人的钱包地址:




查看钱包地址余额,有两种形式:

  • 通过浏览器,输出本人的钱包地址查看

    • https://blockscout.com/poa/sokol/address/0x28383b9717ca0468C580dF7b970A4897a0f11202/transactions
  • 等交易实现,在Metamask中查看


显示余额为:100 POA






总的来说这个步骤和在Kovan测试网上获取代币流程简直统一,须要稍加留神的是设定钱包的RPC信息有所不同。

xDAIChain网络信息补充

xDAIChain的钱包中配置网络RPC信息如下:

  • RPC地址:https://dai.poa.network
  • 链ID:100
  • 原生代币符号:XDAI
  • 区块浏览器地址:https://blockscout.com/poa/xdai













钱包准备就绪后,开始执行我的项目创立和部署阶段,咱们将基于truffle框架来演示此过程,此框架对于工程合约我的项目开发来说必不可少。

在xDAI智能合约中应用PriceFeed


注:本局部的我的项目工程文件托管在Github仓库,地址为:https://github.com/Bingyy/Use-Chainlink-On-xDAIChain


上面演示的是如何从头开始创立我的项目并部署。

1. 我的项目创立

如果机器上没有装置truffle,能够通过命令行执行:

npm install -g truffle

新建一个我的项目名:Use-Chainlink-On-xDAIChain

mkdir Use-Chainlink-On-xDAIChaincd Use-Chainlink-On-xDAIChain

truffle我的项目初始化:

truffle init

truffle我的项目构造如下:

这里的client目录非truffle我的项目所蕴含,build目录则是编译合约后存储ABI数据的地位。咱们次要编写合约,合约部署脚本以及我的项目配置信息。

2. 编写合约

contracts文件夹中,新建一个合约:GetETHUSDPrice.sol,内容如下:

// SPDX-License-Identifier: MITpragma solidity >=0.4.22 <0.8.0;contract GetETHUSDPrice {  uint256 eth_usd_price; // 平安起见倡议用SafeMath    function setETHUSDPrice(uint256 _price) external {        eth_usd_price = _price;    }    function getETHUSDPrice() public view returns(uint256) {        return eth_usd_price;    }}

此合约有一个状态变量,eth_usd_price用于保留从Chainlink喂价获取的实在的价格数据。

3. 合约部署

3.1 配置文件编写

编辑truffle-config.js

const HDWalletProvider = require('@truffle/hdwallet-provider');// const infuraKey = "fj4jll3k.....";//const fs = require('fs');// const mnemonic = fs.readFileSync(".secret").toString().trim();const privateKey = fs.readFileSync(".secret").toString().trim();

这里我的项目脚本依赖@truffle/hdwallet-provider,装置:

npm install @truffle/hdwallet-provider

部署时须要助记词或者私钥签名,在我的项目顶层目录中建设一个文件,.secret,如果是要应用Github仓库保留我的项目,留神将此文件名增加到.gitignore文件中,否则会泄露敏感信息,造成损失。


配置网络信息,在networks字段中增加:

sokol: {      provider: () => new HDWalletProvider(privateKey, `https://sokol.poa.network`),      network_id: 77,      gas: 500000,      gasPrice: 1000000000},xdai: {      provider: () => new HDWalletProvider(privateKey, "https://dai.poa.network"),      network_id: 100,      gas: 500000,      gasPrice: 1000000000 },

为了不便,这里间接将两个网络信息都配置进来,执行部署的时候指定网络名即可。

3.2 合约部署脚本

migrations目录下,新建一个脚本,3_get_ethusd_price.js,内容如下:

const GetETHUSDPrice = artifacts.require("GetETHUSDPrice");module.exports = function (deployer) {    deployer.deploy(GetETHUSDPrice);};


truffle中部署脚本的编号是有意义的,会依照程序执行,咱们也能够执行单个部署脚本,这里的数字编号须要依据以后我的项目中的合约来安顿。


3.3 执行部署命令

truffle migrate -f 3 --to 3 --network xdai --skip-dry-run

参数解释:只执行第三号脚本,同时留神增加--skip-dry-run,如果不增加这个指令,则会部署到xdai-fork网络上,这是一个模仿网络,非实在网络,且在区块浏览器中不可查。也能够在truffle-config中配置字段skipDryRun,这里特地放到命令行是为了强调一下。


部署过程如下:

3_get_ethusd_price.js=====================   Deploying 'GetETHUSDPrice'   --------------------------   > transaction hash:    0x1ee31f52fcccef0899e31d040233222f51949998046ac9762528089bff2d4980   > Blocks: 2            Seconds: 9   > contract address:    0xd3a86c2b36fD3DA6bbd64423d1a494eed47a2052   > block number:        14137854   > block timestamp:     1611206580   > account:             0x28383b9717ca0468C580dF7b970A4897a0f11202   > balance:             0.009903595   > gas used:            96405 (0x17895)   > gas price:           1 gwei   > value sent:          0 ETH   > total cost:          0.000096405 ETH   > Saving artifacts   -------------------------------------   > Total cost:         0.000096405 ETHSummary=======> Total deployments:   1> Final cost:          0.000096405 ETH

这里显示的是ETH为单位,实际上是耗费的POA代币,在POA Sokol上的原生代币是POA,位置相当于ETH在Ethereum网络上。


当初合约部署实现,能够看出部署合约的费用耗费相比于以太坊来说极低。合约部署实现后,咱们进入到与合约交互的步骤。

4. 与合约交互

在我的项目文件夹中建设一个client文件夹,用于寄存交互脚本。咱们将通过Node.js来编写脚本,并应用web3.js库,装置:

npm install web3

为了与合约交互,咱们须要晓得合约的ABI和部署的合约地址。

const Web3 = require('web3')const fs = require('fs');const HDWalletProvider = require('@truffle/hdwallet-provider');// 账户相干敏感信息,私钥签名,无0x前缀const privateKey = fs.readFileSync("../.secret").toString().trim();// 账户地址:本人的账户地址const account1 = '0x28383b9717ca0468C580dF7b970A4897a0f11202'


这里须要交互的账户地址,须要有肯定的测试代币,本文以部署合约账户为例。


设置RPC:

// 设置sokol网络的RPCconst provider = new HDWalletProvider(privateKey, 'https://sokol.poa.network')const web3 = new Web3(provider)// Kovan上的RPC须要从Infura中获取const provider_kovan = new HDWalletProvider(privateKey, 'https://kovan.infura.io/v3/afc48dd54b2b408aa43e79ce09c5d1f5')const web3_kovan = new Web3(provider_kovan)

这里咱们须要两个web3实例,一个用于POA Sokol网络,另一个利用于Kovan网络。


已部署的合约信息:

// 侧链合约信息,用于存取喂价数据const GetETHUSDPriceABI = [{ "inputs": [{ "internalType": "uint256", "name": "_price", "type": "uint256" }], "name": "setETHUSDPrice", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "getETHUSDPrice", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }]const GETETHUSDPriceAddress = "0xd3a86c2b36fD3DA6bbd64423d1a494eed47a2052"

其中ABI数据能够在build/contracts目录下找到对应的合约的ABI数据,另外举荐代码中将其稀释为一行,能够应用在线转换工具:https://tools.knowledgewalls.com/online-multiline-to-single-line-converter


构建合约实例:

const getETHUSDPriceInstance = new web3.eth.Contract(GetETHUSDPriceABI, GETETHUSDPriceAddress)

当初咱们就有了能够交互的合约实例,但在此之前咱们须要先理解如何应用在Kovan上的Chainlink的喂价合约,咱们无需部署,只须要晓得它的ABI和合约地址即可,其中合约地址能够拜访:https://docs.chain.link/docs/reference-contracts,在Kovan局部找到合约地址。地址为:0x9326BFA02ADD2366b30bacB125260Af641031331


合约的ABI能够在Kovan区块浏览器获取:


https://kovan.etherscan.io/address/0x9326BFA02ADD2366b30bacB125260Af641031331


为了与之交互,咱们也须要失去它的实例,代码如下:

// KOVAN ETHUSD PriceFeed ABIconst ETHUSDPriceFeedABI = [{ "inputs": [{ "internalType": "address", "name": "_aggregator", "type": "address" }, { "internalType": "address", "name": "_accessController", "type": "address" }], "stateMutability": "nonpayable", "type": "constructor" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "int256", "name": "current", "type": "int256" }, { "indexed": true, "internalType": "uint256", "name": "roundId", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "updatedAt", "type": "uint256" }], "name": "AnswerUpdated", "type": "event" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "uint256", "name": "roundId", "type": "uint256" }, { "indexed": true, "internalType": "address", "name": "startedBy", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "startedAt", "type": "uint256" }], "name": "NewRound", "type": "event" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "from", "type": "address" }, { "indexed": true, "internalType": "address", "name": "to", "type": "address" }], "name": "OwnershipTransferRequested", "type": "event" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "from", "type": "address" }, { "indexed": true, "internalType": "address", "name": "to", "type": "address" }], "name": "OwnershipTransferred", "type": "event" }, { "inputs": [], "name": "acceptOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "accessController", "outputs": [{ "internalType": "contract AccessControllerInterface", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "aggregator", "outputs": [{ "internalType": "address", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "_aggregator", "type": "address" }], "name": "confirmAggregator", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "decimals", "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "description", "outputs": [{ "internalType": "string", "name": "", "type": "string" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "uint256", "name": "_roundId", "type": "uint256" }], "name": "getAnswer", "outputs": [{ "internalType": "int256", "name": "", "type": "int256" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "uint80", "name": "_roundId", "type": "uint80" }], "name": "getRoundData", "outputs": [{ "internalType": "uint80", "name": "roundId", "type": "uint80" }, { "internalType": "int256", "name": "answer", "type": "int256" }, { "internalType": "uint256", "name": "startedAt", "type": "uint256" }, { "internalType": "uint256", "name": "updatedAt", "type": "uint256" }, { "internalType": "uint80", "name": "answeredInRound", "type": "uint80" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "uint256", "name": "_roundId", "type": "uint256" }], "name": "getTimestamp", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "latestAnswer", "outputs": [{ "internalType": "int256", "name": "", "type": "int256" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "latestRound", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "latestRoundData", "outputs": [{ "internalType": "uint80", "name": "roundId", "type": "uint80" }, { "internalType": "int256", "name": "answer", "type": "int256" }, { "internalType": "uint256", "name": "startedAt", "type": "uint256" }, { "internalType": "uint256", "name": "updatedAt", "type": "uint256" }, { "internalType": "uint80", "name": "answeredInRound", "type": "uint80" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "latestTimestamp", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "owner", "outputs": [{ "internalType": "address payable", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "uint16", "name": "", "type": "uint16" }], "name": "phaseAggregators", "outputs": [{ "internalType": "contract AggregatorV2V3Interface", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "phaseId", "outputs": [{ "internalType": "uint16", "name": "", "type": "uint16" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "_aggregator", "type": "address" }], "name": "proposeAggregator", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "proposedAggregator", "outputs": [{ "internalType": "contract AggregatorV2V3Interface", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "uint80", "name": "_roundId", "type": "uint80" }], "name": "proposedGetRoundData", "outputs": [{ "internalType": "uint80", "name": "roundId", "type": "uint80" }, { "internalType": "int256", "name": "answer", "type": "int256" }, { "internalType": "uint256", "name": "startedAt", "type": "uint256" }, { "internalType": "uint256", "name": "updatedAt", "type": "uint256" }, { "internalType": "uint80", "name": "answeredInRound", "type": "uint80" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "proposedLatestRoundData", "outputs": [{ "internalType": "uint80", "name": "roundId", "type": "uint80" }, { "internalType": "int256", "name": "answer", "type": "int256" }, { "internalType": "uint256", "name": "startedAt", "type": "uint256" }, { "internalType": "uint256", "name": "updatedAt", "type": "uint256" }, { "internalType": "uint80", "name": "answeredInRound", "type": "uint80" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "_accessController", "type": "address" }], "name": "setController", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "_to", "type": "address" }], "name": "transferOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "version", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }]const ETHUSDPriceFeedAddress = "0x9326BFA02ADD2366b30bacB125260Af641031331"

构建喂价合约实例:

const ETHUSDPriceFeedInstance = new web3_kovan.eth.Contract(ETHUSDPriceFeedABI, ETHUSDPriceFeedAddress)


写两个函数,一个用于从咱们本人部署的合约获取数据,一个通过从Kovan上读取Chainlink的喂价数据并将其更新到POA Sokol链上。

// 将Kovan上的数据更新到侧链上async function setETHUSDPriceOnSideChain() {    // step 1: get data    let res = await ETHUSDPriceFeedInstance.methods.latestRoundData().call({        from: account1    })    const ETHUSDPrice = res.answer;    console.log("ETHUSD Price is: ", ETHUSDPrice) // BigNumber     // step 2: set data to sidechain    getETHUSDPriceInstance.methods.setETHUSDPrice(ETHUSDPrice).send({        from: account1    }).on('receipt', receipt => {        console.log('receipt: ', receipt)    })}// 从侧链上获取ETHUSD价格信息async function getETHUSDPriceFromSideChain() {    // 读取此喂价合约    let price = await getETHUSDPriceInstance.methods.getETHUSDPrice().call({        from: account1    })    console.log("latest price: ", price)}

4. 脚本获取Chainlink喂价数据

调用setETHUSDPriceOnSideChain函数,即可将ETHUSD价格信息数据更新到侧链,通过调用getETHUSDPriceFromSideChain函数即可从侧链上获取价格信息。

latest price:  132972000000

5. xDAIChain智能合约部署和交互

部署只须要执行:

truffle migrate -f 3 --to 3 --network xdai --skip-dry-run




xDAIChain上部署的合约地址为:0xe8713F35044eFf25C6340b6837C777F0d04a8461


与xDAIChain上合约交互须要批改几个信息:

const provider = new HDWalletProvider(privateKey, 'https://dai.poa.network')const web3 = new Web3(provider)const GETETHUSDPriceAddress = "0xe8713F35044eFf25C6340b6837C777F0d04a8461"

其余信息不必批改,应用流程雷同。

总结


以上就是如何在侧链上应用Chainlink喂价的一种办法,对于曾经实现集成Chainlink预言机的Layer 2网络,如Matic,能够间接在合约中调用Chainlink预言机,本文采纳的办法是一种链下脚本桥接侧链和主链的一种形式,具体执行时须要留神脚本执行的定时刷新,以及监控脚本的运行状态,如果不更新,会呈现价格偏离,从而被其余的套利机器人攻打。


参考工具链接:
JSON转换地址:https://tools.knowledgewalls.com/online-multiline-to-single-line-converter
Github地址:https://github.com/Bingyy/Use-Chainlink-On-xDAIChain
xDAI文档:https://www.xdaichain.com/
xDAI水龙头地址:https://xdai-faucet.top/
POA水龙头地址https://faucet-sokol.herokuapp.com/




如果你是开发者,想要疾速为你的利用连贯到Chainlink的价格参考数据,拜访开发者文档,并接入Discord技术探讨。如果你想要安顿一个电话来更深刻探讨Matic/Chainlink的集成,请在此处分割。
English channels
Website | Twitter | Reddit | YouTube | Telegram | Events | GitHub | Price Feeds | DeFi
中文渠道
中武官网 | 知乎 | SegmentFault | CSDN |