随着 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-xDAIChain cd Use-Chainlink-On-xDAIChain
truffle
我的项目初始化:
truffle init
truffle
我的项目构造如下:
这里的 client
目录非 truffle
我的项目所蕴含,build
目录则是编译合约后存储 ABI 数据的地位。咱们次要编写合约,合约部署脚本以及我的项目配置信息。
2. 编写合约
在 contracts
文件夹中,新建一个合约:GetETHUSDPrice.sol
,内容如下:
// SPDX-License-Identifier: MIT pragma 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 ETH Summary ======= > 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 网络的 RPC const 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 ABI const 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 |