truffle与合约交互

来源:互联网 发布:网络flash插件未安装 编辑:程序博客网 时间:2024/06/03 02:15

与以太坊的智能合约交互,除了使用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.0npm 3.10.10

示例合约

还是以上一篇文章中的MetaCoin合约为例,确保启动了一个以太坊节点,并且已将下面的MetaCoin合约部署到节点中。

// 本文中用到的MetaCoin合约pragma solidity ^0.4.2;contract MetaCoin {    mapping (address => uint) balances;    event Transfer(address indexed _from, address indexed _to, uint256 _value);    function MetaCoin() {        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");// 合约ABIvar 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: 0x68b73956d704007514e9257813bdc58cdf3c969ato: 0x9c3c1a2f5ef913fac44f0348a78f68d835f3f26eamount: 100sendCoin执行完后会触发一个Transfer事件,在回调函数中,通过查询result.logs可以获取到这个事件,进而可以得到事件的参数值。

一个完整的例子

下面是一个完整的例子:

var Web3 = require("web3");var contract = require("truffle-contract");// 合约ABIvar 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 3400Sent 100 coin from account one to account two.Balance of account two is 3500
原创粉丝点击