以太坊开发实战:通过truffle-contract与智能合约交互

本文详细介绍如何使用truffle-contract库与以太坊智能合约交互,包括合约部署、调用合约函数、处理交易和捕获事件等核心操作。

以太坊开发实战:通过truffle-contract与智能合约交互

与以太坊的智能合约交互,除了使用web3.js,还可以使用另外一个Javascript库,就是truffle-contract。truffle-contract对以太坊的智能合约做了更好的抽象,相比于web3.js,使用truffle-contract操作智能合约更加方便。

truffle-contract具有以下特色:

  • 同步的交易:可以确保在交易生效之后再继续执行其他操作
  • 返回Promise:每个封装的合约函数会返回Promise,可以对它进行.then操作,避免了回调地狱(callback hell)问题
  • 为交易提供了默认参数:例如fromgas
  • 为每个同步的交易返回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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI周红伟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值