TRON开发者指南 | 第二十期:关于智能合约——自定义Oracle执行

欢迎来到

波场TRON开发者指南

在这里

您将找到最全面的指南与文档

助力您完美使用

【TRON Developer Guide 】

智能合约能够运行算法计算,并存储和检索数据。 由于合同仅限于区块链,因此无法从 Tron 合同中提出网络请求。 Oracles 解决这个问题是通过观察的区块链上的事件以及将网络请求的结果发布返回给合同的方式。 通过这种方式, 合约可以与链下交互。

源代码可以在[这里](https://github.com/tronprotocol/custom-oracle)找到。

Developing the Smart Contract


以下为有 oracle 监听发出的事件的合约。 oracle 将根据一个事件,请求获取 Tron 的价格数据,然后将其写回智能合约。

pragma solidity ^0.4.24;

contract PriceOracle {

// Address of oracle set in the contract constructor

address oracleAddress;

// Price data

string price;

string rank;

string marketCap;

string vol24H;

string perChange1H;

string perChange1D;

string perChange7D;

// Function called on creation of contract, sets oracle address

constructor (address _oracleAddress) public {

oracleAddress = _oracleAddress;

}

// Event emitted when price is updated from oracle

event PriceUpdate (

string price,

string rank,

string marketCap,

string vol24H,

string perChange1H,

string perChange1D,

string perChange7D

);

// Event emitted when a price update is initiated

event InitUpdate();

// Function called to return price data

function getPriceData() public returns (string, string, string, string, string, string, string) {

return (price, rank, marketCap, vol24H, perChange1H, perChange1D, perChange7D);

}

// Function called to initate price update

function initUpdate() public {

emit InitUpdate();

}

// function called by oracle to update price data within contract

function updatePrice (

string _price,

string _rank,

string _marketCap,

string _vol24H,

string _perChange1H,

string _perChange1D,

string _perChange7D

)

public

{

require(msg.sender == oracleAddress);

price = _price;

rank = _rank;

marketCap = _marketCap;

vol24H = _vol24H;

perChange1H = _perChange1H;

perChange1D = _perChange1D;

perChange7D = _perChange7D;

emit PriceUpdate (

price,

rank,

marketCap,

vol24H,

perChange1H,

perChange1D,

perChange7D

);

}

}

部署智能合约


现在我们已经编写了智能合约,我们将使用 Tron Studio将其部署到 Shasta 测试网上。 将 PriceOracle.sol 合约复制并粘贴到 Tron Studio 中。



将你现有的设置配置指向 Shasta 测试网 。 确保将你的网络环境也切换到测试网。




开发及运行Oracle


合约已编译完成,Tron Studio已指向Shasta测试网,现在一起开发可以监听事件的oracle,从外部API获取价格信息并写回给合约。

运行 mkdir PriceOracle 并通过在终端中运行 cd PriceOracle 进入项目目录。

接下来,运行 npm init 以启动Node.js实例,配置package.json属性,并在文本编辑器中打开项目目录。

继续,在项目目录中运行 npm install tronweb 和*npm install request ,以向oracle添加必要的依赖项。

最后,创建一个名为 index.js 的新javascript文件,并将以下代码复制到该文件中。

● index.js

Copy

// Initiate request object

const request = require("request");

// Initiate TronWeb object

const TronWeb = require('TronWeb');

const HttpProvider = TronWeb.providers.HttpProvider;

// Full node http endpoint

const fullNode = new HttpProvider("https://api.shasta.trongrid.io");

// Solidity node http endpoint

const solidityNode = new HttpProvider("https://api.shasta.trongrid.io");

// Contract events http endpoint

const eventServer = "https://api.shasta.trongrid.io";

// Private key of oracle

const privateKey = '';

// Create instance of TronWeb

const tronWeb = new TronWeb(

fullNode,

solidityNode,

eventServer,

privateKey

);

// Create instance of contract object

const contract = {

"PriceOracle.sol:PriceOracle": {

"address": "",

"abi":

}

};

// Initiate PriceOracle contract object

const priceOracle = tronWeb.contract(contract["PriceOracle.sol:PriceOracle"].abi, contract["PriceOracle.sol:PriceOracle"].address);

// Function to watch for events on PriceOracle contract

function startEventListener() {

// Watch for InitUpdate event

priceOracle.InitUpdate().watch((err, {result}) => {

if (err) return console.error('Failed to bind event listener:', err);

// Make request to fetch price data from https://api.coinmarketcap.com

request("https://api.coinmarketcap.com/v2/ticker/1958/", function (err, response, body) {

if (err) return;

// Parse price data in API response

const json = JSON.parse(body);

const data = json.data;

const rank = data.rank;

const price = data.quotes.USD.price;

const marketCap = data.quotes.USD.market_cap;

const vol24H = data.quotes.USD.volume_24h;

const perChange1H = data.quotes.USD.percent_change_1h;

const perChange1D = data.quotes.USD.percent_change_24h;

const perChange7D = data.quotes.USD.percent_change_7d;

// Call state changing function updatePrice within PriceOracle contract to write price data

priceOracle.updatePrice(price.toString(), rank.toString(), marketCap.toString(),

vol24H.toString(), perChange1H.toString(), perChange1D.toString(), perChange7D.toString()).send({

shouldPollResponse: true,

callValue: 0

}).catch(function (err) {

console.log(err)

});

})

});

// Watch for PriceUpdate event

priceOracle.PriceUpdate().watch((err, {result}) => {

if (err) return console.error('Failed to bind event listener:', err);

console.log(result);

});

}

// Call startEventListener function to watch for events in PriceOracle contract

startEventListener();

用您希望用作 oracle 的波场账户的私钥指定 privateKey 变量。

在 Tron Studio 中复制构造函数参数框中的 Oracle 的公共地址(私钥变量所对应的公钥在 index.js 文件中)并在 Shasta 测试网中部署合约。

注意:如果 Oracle 的波场帐户没有任何测试网 TRX,部署将失败。 你可在这里接受 TRX 测试币。




复制已部署的合约地址并用此工具将其转化为十六进制的 string。



复制该 16 进制的 string 并在 index.js 文件中合约对象内指定其至“地址”变量。



下一步,从 Tron Studio 中复制已部署的合约 ABI,并将其指定至 index.js 文件中合约对象内的 “abi” 变量。




让我们通过运行在项目指令集终端的 node index.js 开启 oracle。

Oracle 现在正在监听部署的 PriceOracle 合约上的事件。 在 Tron Studio 中,调用 initUpdate 函数来更新合同中的价格数据。




一旦成功调用 initUpdate 函数,initUpdate 事件将发出,oracle 将接受此事件,调用并解析价格数据的api回应,调用 PriceOracle updatePrice 合约函数并通过 oracle index.js 文件中的代码来书写价格数据。




一旦通过 updatePrice 函数成功写出价格数据, PriceUpdate 事件将发出。 Oracle 将接收该发出事件,并通过此代码显示合同中的价格数据。 您将在项目的控制台中看到。






恭喜您,您已在波场区块链上成功开发了自定义的oracle。

Full Code示例

● PriceOracle.sol

Copy

pragma solidity ^0.4.24;

contract PriceOracle {

address oracleAddress;

string price;

string rank;

string marketCap;

string vol24H;

string perChange1H;

string perChange1D;

string perChange7D;

constructor (address _oracleAddress) public {

oracleAddress = _oracleAddress;

}

event PriceUpdate (

string price,

string rank,

string marketCap,

string vol24H,

string perChange1H,

string perChange1D,

string perChange7D

);

event InitUpdate();

function getPriceData() public returns (string, string, string, string, string, string, string) {

return (price, rank, marketCap, vol24H, perChange1H, perChange1D, perChange7D);

}

function initUpdate() public {

emit InitUpdate();

}

function updatePrice (

string _price,

string _rank,

string _marketCap,

string _vol24H,

string _perChange1H,

string _perChange1D,

string _perChange7D

)

public

{

require(msg.sender == oracleAddress);

price = _price;

rank = _rank;

marketCap = _marketCap;

vol24H = _vol24H;

perChange1H = _perChange1H;

perChange1D = _perChange1D;

perChange7D = _perChange7D;

emit PriceUpdate (

price,

rank,

marketCap,

vol24H,

perChange1H,

perChange1D,

perChange7D

);

}

}

● index.js

Copy

// Initiate request object

const request = require("request");

// Initiate TronWeb object

const TronWeb = require('TronWeb');

const HttpProvider = TronWeb.providers.HttpProvider;

// Full node http endpoint

const fullNode = new HttpProvider("https://api.shasta.trongrid.io");

// Solidity node http endpoint

const solidityNode = new HttpProvider("https://api.shasta.trongrid.io");

// Contract events http endpoint

const eventServer = "https://api.shasta.trongrid.io";

// Private key of oracle

const privateKey = 'b815adfd6ef133d5a878869cb3a2b31f32d4c1481132a71300c3e125be0ab1a1';

// Create instance of TronWeb

const tronWeb = new TronWeb(

fullNode,

solidityNode,

eventServer,

privateKey

);

// Create instance of contract object

const contract = {

"PriceOracle.sol:PriceOracle": {

"address": "4100CB5944750274A723EB22064201BF2BA1089F55",

"abi": [{

"constant": false,

"inputs": [],

"name": "initUpdate",

"outputs": [],

"payable": false,

"stateMutability": "nonpayable",

"type": "function"

}, {

"constant": false,

"inputs": [],

"name": "getPriceData",

"outputs": [{"name": "", "type": "string"}, {"name": "", "type": "string"}, {

"name": "",

"type": "string"

}, {"name": "", "type": "string"}, {"name": "", "type": "string"}, {

"name": "",

"type": "string"

}, {"name": "", "type": "string"}],

"payable": false,

"stateMutability": "nonpayable",

"type": "function"

}, {

"constant": false,

"inputs": [{"name": "_price", "type": "string"}, {"name": "_rank", "type": "string"}, {

"name": "_marketCap",

"type": "string"

}, {"name": "_vol24H", "type": "string"}, {

"name": "_perChange1H",

"type": "string"

}, {"name": "_perChange1D", "type": "string"}, {"name": "_perChange7D", "type": "string"}],

"name": "updatePrice",

"outputs": [],

"payable": false,

"stateMutability": "nonpayable",

"type": "function"

}, {

"inputs": [{"name": "_oracleAddress", "type": "address"}],

"payable": false,

"stateMutability": "nonpayable",

"type": "constructor"

}, {

"anonymous": false,

"inputs": [{"indexed": false, "name": "price", "type": "string"}, {

"indexed": false,

"name": "rank",

"type": "string"

}, {"indexed": false, "name": "marketCap", "type": "string"}, {

"indexed": false,

"name": "vol24H",

"type": "string"

}, {"indexed": false, "name": "perChange1H", "type": "string"}, {

"indexed": false,

"name": "perChange1D",

"type": "string"

}, {"indexed": false, "name": "perChange7D", "type": "string"}],

"name": "PriceUpdate",

"type": "event"

}, {"anonymous": false, "inputs": [], "name": "InitUpdate", "type": "event"}]

}

};

// Initiate PriceOracle contract object

const priceOracle = tronWeb.contract(contract["PriceOracle.sol:PriceOracle"].abi, contract["PriceOracle.sol:PriceOracle"].address);

// Function to watch for events on PriceOracle contract

function startEventListener() {

// Watch for InitUpdate event

priceOracle.InitUpdate().watch((err, {result}) => {

if (err) return console.error('Failed to bind event listener:', err);

// Make request to fetch price data from https://api.coinmarketcap.com

request("https://api.coinmarketcap.com/v2/ticker/1958/", function (err, response, body) {

if (err) return;

// Parse price data in API response

const json = JSON.parse(body);

const data = json.data;

const rank = data.rank;

const price = data.quotes.USD.price;

const marketCap = data.quotes.USD.market_cap;

const vol24H = data.quotes.USD.volume_24h;

const perChange1H = data.quotes.USD.percent_change_1h;

const perChange1D = data.quotes.USD.percent_change_24h;

const perChange7D = data.quotes.USD.percent_change_7d;

// Call state changing function updatePrice within PriceOracle contract to write price data

priceOracle.updatePrice(price.toString(), rank.toString(), marketCap.toString(),

vol24H.toString(), perChange1H.toString(), perChange1D.toString(), perChange7D.toString()).send({

shouldPollResponse: true,

callValue: 0

}).catch(function (err) {

console.log(err)

});

})

});

// Watch for PriceUpdate event

priceOracle.PriceUpdate().watch((err, {result}) => {

if (err) return console.error('Failed to bind event listener:', err);

console.log(result);

});

}

// Call startEventListener function to watch for events in PriceOracle contract

startEventListener();

发表评论
留言与评论(共有 0 条评论)
   
验证码:

相关文章

推荐文章

'); })();