以太坊开发实战:通过truffle-contract与智能合约交互
以太坊開發實戰:通過truffle-contract與智能合約交互
與以太坊的智能合約交互,除了使用web3.js,還可以使用另外一個Javascript庫,就是truffle-contract。truffle-contract對以太坊的智能合約做了更好的抽象,相比于web3.js,使用truffle-contract操作智能合約更加方便。
truffle-contract具有以下特色:
- 同步的交易:可以確保在交易生效之后再繼續執行其他操作
- 返回Promise:每個封裝的合約函數會返回Promise,可以對它進行.then操作,避免了回調地獄(callback hell)問題
- 為交易提供了默認參數:例如from或gas
- 為每個同步的交易返回logs、交易receipt和交易hash
下面介紹如何在應用中使用truffle-contract與智能合約交互。
- Ubuntu 16.04 64位
- nodejs 6.10.0
- npm 3.10.10
示例合約
還是以上一篇文章中的MetaCoin合約為例,確保啟動了一個以太坊節點,并且已將下面的MetaCoin合約部署到節點中。
| pragma solidity ^0.4.2; contract MetaCoin { mapping (address => uint) balances; event Transfer(address indexed _from, address indexed _to, uint256 _value); function () { balances[tx.origin] = 10000; } function sendCoin(address receiver, uint amount) returns(bool sufficient) { if (balances[msg.sender] < amount) return false; balances[msg.sender] -= amount; balances[receiver] += amount; Transfer(msg.sender, receiver, amount); return true; } function getBalance(address addr) returns(uint) { return balances[addr]; } } |
?
接下來就可以按照下面的步驟在項目中通過truffle-contract來使用這個合約。
安裝truffle-contract
首先新建一個Nodejs項目并初始化:
| $ mkdir truffle-contract-test && cd truffle-contract-test $ npm init |
?
接下來安裝truffle-contract:
| $ npm install web3 --save $ npm install truffle-contract --save |
?
注:安裝truffle-contract并不要求先安裝web3,這里安裝web3是因為后面會用到。
初始化合約對象
與web3.js類似,要使用truffle-contract,需要先初始化合約對象,然后連接到一個以太坊節點。在truffle-contract-test目錄下新建index.js文件,在其中輸入以下代碼:
| var Web3 = require("web3"); var contract = require("truffle-contract"); // 合約ABI var contract_abi = [{ "constant": false, "inputs": [{ "name": "receiver", "type": "address" }, { "name": "amount", "type": "uint256" }], "name": "sendCoin", "outputs": [{ "name": "sufficient", "type": "bool" }], "payable": false, "type": "function" }, { "constant": false, "inputs": [{ "name": "addr", "type": "address" }], "name": "getBalance", "outputs": [{ "name": "", "type": "uint256" }], "payable": false, "type": "function" }, { "inputs": [], "payable": false, "type": "constructor" }, { "anonymous": false, "inputs": [{ "indexed": true, "name": "_from", "type": "address" }, { "indexed": true, "name": "_to", "type": "address" }, { "indexed": false, "name": "_value", "type": "uint256" }], "name": "Transfer", "type": "event" }]; // 通過ABI初始化合約對象 var MetaCoin = contract({ abi: contract_abi // 如果要部署合約,還要指定合約代碼: // unlinked_binary: ... }); // 連接到以太坊節點 var provider = new Web3.providers.HttpProvider("http://localhost:8545"); MetaCoin.setProvider(provider); |
?
接下來,可以使用MetaCoin的以下三個函數:
- at(contract_address):通過指定的合約地址獲取MetaCoin合約實例
- deployed():通過默認的合約地址獲取MetaCoin合約實例
- new():部署新的合約,并且獲取新部署的合約實例
調用合約函數
可以像下面這樣調用getBalance函數:
| // 改成你自己的賬戶地址 var account_one = "0x68b73956d704007514e9257813bdc58cdf3c969a"; // 合約地址,改成你自己的合約地址 var contract_address = "0xb2cdd356e58280906ce53e1665697b50f88aac56"; MetaCoin.at(contract_address).then(function(instance){ return instance.getBalance.call(account_one); }).then(function(balance){ console.log(balance.toNumber()); }).catch(function(err){ console.log(err); }); |
?
首先通過MetaCoin.at()獲取合約實例,在.then鏈式調用中,回調函數會在參數中獲取到合約實例instance,接下來就可以在回調函數中使用合約實例來調用getBalance函數,再繼續通過.then鏈式調用,通過回調函數獲得getBalance的返回值balance。
再來看看調用sendCoin函數的情況:
| // 改成你自己的賬戶地址 var account_one = "0x68b73956d704007514e9257813bdc58cdf3c969a"; var account_two = "0x9c3c1a2f5ef913fac44f0348a78f68d835f3f26e"; // 合約地址,改成你自己的合約地址 var contract_address = "0xb2cdd356e58280906ce53e1665697b50f88aac56"; MetaCoin.at(contract_address).then(function(instance){ // 調用sendCoin會向區塊鏈發送一筆交易 return instance.sendCoin(account_two, 100, {from:account_one}); }).then(function(result){ // 這個回調函數在交易生效之后才會被執行 // result對象包含以下三個字段: // result.tx => 交易hash,是一個string // result.receipt => 交易執行結果,是一個對象 // result.logs => 交易產生的事件集合,是一個對象數組 console.log(result); }).catch(function(err){ console.log(err); }); |
?
這里,調用sendCoin會向區塊鏈發送一筆交易,在交易生效之后,才會執行回調函數,回調函數的參數中包含了交易hash、交易執行結果以及交易產生的事件。
捕獲事件
可以通過result.logs獲取交易觸發的事件:
| // 改成你自己的賬戶地址 var account_one = "0x68b73956d704007514e9257813bdc58cdf3c969a"; var account_two = "0x9c3c1a2f5ef913fac44f0348a78f68d835f3f26e"; // 合約地址,改成你自己的合約地址 var contract_address = "0xb2cdd356e58280906ce53e1665697b50f88aac56"; MetaCoin.at(contract_address).then(function(instance){ // 調用sendCoin會向區塊鏈發送一筆交易 return instance.sendCoin(account_two, 100, {from:account_one}); }).then(function(result){ // 這個回調函數在交易生效之后才會被執行 // result.logs是一個數組,數組的每個元素是一個事件對象 // 通過查詢result.logs可以獲得感興趣的事件 for (var i = 0; i < result.logs.length; i++) { var log = result.logs[i]; if (log.event == "Transfer") { console.log("from:", log.args._from); console.log("to:", log.args._to); console.log("amount:", log.args._value.toNumber()); break; } } }).catch(function(err){ console.log(err); }); // 輸出: from: 0x68b73956d704007514e9257813bdc58cdf3c969a to: 0x9c3c1a2f5ef913fac44f0348a78f68d835f3f26e amount: 100 |
?
sendCoin執行完后會觸發一個Transfer事件,在回調函數中,通過查詢result.logs可以獲取到這個事件,進而可以得到事件的參數值。
一個完整的例子
下面是一個完整的例子:
| var Web3 = require("web3"); var contract = require("truffle-contract"); // 合約ABI var contract_abi = [{ "constant": false, "inputs": [{ "name": "receiver", "type": "address" }, { "name": "amount", "type": "uint256" }], "name": "sendCoin", "outputs": [{ "name": "sufficient", "type": "bool" }], "payable": false, "type": "function" }, { "constant": false, "inputs": [{ "name": "addr", "type": "address" }], "name": "getBalance", "outputs": [{ "name": "", "type": "uint256" }], "payable": false, "type": "function" }, { "inputs": [], "payable": false, "type": "constructor" }, { "anonymous": false, "inputs": [{ "indexed": true, "name": "_from", "type": "address" }, { "indexed": true, "name": "_to", "type": "address" }, { "indexed": false, "name": "_value", "type": "uint256" }], "name": "Transfer", "type": "event" }]; // 通過ABI初始化合約對象 var MetaCoin = contract({ abi: contract_abi // 如果要部署合約,還要指定合約代碼: // unlinked_binary: ... }); // 連接到以太坊節點 var provider = new Web3.providers.HttpProvider("http://localhost:8545"); MetaCoin.setProvider(provider); // 改成你自己的賬戶地址 var account_one = "0x68b73956d704007514e9257813bdc58cdf3c969a"; var account_two = "0x9c3c1a2f5ef913fac44f0348a78f68d835f3f26e"; // 合約地址,改成你自己的合約地址 var contract_address = "0xb2cdd356e58280906ce53e1665697b50f88aac56"; var coin; MetaCoin.at(contract_address).then(function(instance){ coin = instance; // 首先查看賬戶二的余額 return coin.getBalance.call(account_two); }).then(function(balance_of_account_two){ console.log("Balance of account two is", balance_of_account_two.toNumber()); // 從賬戶一向賬戶二轉100個幣 return coin.sendCoin(account_two, 100, {from:account_one}); }).then(function(result){ console.log("Sent 100 coin from account one to account two."); // 再次查看賬戶二的余額 return coin.getBalance.call(account_two); }).then(function(balance_of_account_two){ console.log("Balance of account two is", balance_of_account_two.toNumber()); }).catch(function(err){ console.log("Error:", err.message); }); |
?
| // 輸出 Balance of account two is 3400 Sent 100 coin from account one to account two. Balance of account two is 3500 |
總結
以上是生活随笔為你收集整理的以太坊开发实战:通过truffle-contract与智能合约交互的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 开启 Truffle Ganache
- 下一篇: 设置Network id: 5