在使用web3开发时,如果需要通过js发送一笔交易或者调用合约中的某个方法时,都会提示:Error: authentication needed: password or unlock,这时我们一般会在geth解锁该账户再重新发起。
但是如果需要在前端js实现通过某个事件发送一笔交易或者调用合约某个方法,这样便无法实现。本文将介绍通过用私钥对交易进行签名从而发起交易。
1.发送一笔交易
我们将使用web3提供的函数sendRawTransaction:
//signedTransactionData为已经签名的16进制交易数据
web3.eth.sendRawTransaction(signedTransactionData [, callback])
实例代码
//导入ethereumjs-tx库,通过npm install安装
var Tx = require('ethereumjs-tx');
//_from为发起交易的地址
var _from = "0xc73dfe8e6ba891ea1ea70cd23f3af0eac85fd6e7";
//nonce随机数,这里取该账号的交易数量
var number = web3.eth.getTransactionCount(_from).toString(16);
var privateKey = new Buffer('地址对应的私钥', 'hex');
var rawTx = {
nonce: '0x'+number,//随机数
//gasPrice和gasLimit如果不知道怎么填,可以参考etherscan上的任意一笔交易的值
gasPrice: '0x77359400',
gasLimit: '0x295f05',
to: '0xc886c791708402c26fbf7c156845e0732cd243de',//接受方地址或者合约地址
value: '0x100',//发送的金额,这里是16进制,实际表示发送256个wei
data: ''
}
//使用私钥对原始的交易信息进行签名,得到签名后的交易数据
var tx = new Tx(rawTx);
tx.sign(privateKey);
var serializedTx = tx.serialize();
web3.eth.sendRawTransaction('0x' + serializedTx.toString('hex'), function(err, hash) {
if (!err){
console.log(hash);
}else{
console.log(err);
}
});
这个方法逻辑很简单,是将0xc73dfe8e6ba891ea1ea70cd23f3af0eac85fd6e7账户的256个wei发送到0xc886c791708402c26fbf7c156845e0732cd243de账户中。
-
发送前先查询0xc886c791708402c26fbf7c156845e0732cd243de的余额:
执行实例代码发送交易,返回这笔交易的hash
- 待这笔交易完成后,在查看账户余额,多了256个wei
2.如何调用合约方法
调用合约方法其实也是往以太网络发送一笔交易的过程,那如何通过代码调用合约方法呢?
大致逻辑基本相同,只需要修改rawTx中的to和data即可:
var rawTx = {
nonce: '0x'+number,//随机数
//gasPrice和gasLimit如果不知道怎么填,可以参考etherscan上的任意一笔交易的值
gasPrice: '0x77359400',
gasLimit: '0x295f05',
to: '合约地址',
value: '0x0',//如果你的合约方法是payable,可以接受eth的话可以给value赋值
data: '合约方法的16进制数据'
}
- 这里需要说明的是data,当调用合约方法时,data需要填写合约方法的16进制数据,那这个数据怎么获得呢?
通过remix IDE调用你的合约方法,然后在控制台中点击detail,
如下图,我通过IDE调用了合约的drawing方法,可以看到detail中的input就是我后续要的data,将“0xb77200b1”填写到rawText中的data即可通过js调用合约的drawing方法了。
3.如何调用带参数的合约方法
根据上个例子已经了解如何通过代码调用合约方法,但是如果合约方法需要传递参数应该如何操作呢?
首先我们先在remix中调用一个需要参数的合约方法:
可以看到,我调用了createGame方法,在input中0x41cb3b7b为方法名,其他为参数。我们只需要生成同样的input放入到rawTx的data即可。
那如何生成这个input的16进制数据呢?
3.1 在线生成16进制数据
这个网站是专门用于生成abi的16进制数据。
按照上面步骤填入信息后,会自动生成16进制数据,非常方便。
3.2通过代码生成16进制数据
这种方法较为灵活,可以直接在js代码中生成。你需要引入ethereumjs-abi库,官方地址:https://github.com/ethereumjs/ethereumjs-abi
var abi = require('ethereumjs-abi')
var paramsData = abi.rawEncode(["uint", "uint", "uint", "uint", "string", "string"], [1,2,3,4,"a","b").toString('hex');
rawEncode第一个入参为类型数组,即合约方法的入参类型。
第二个参数为数据数据,和类型对应的,每个类型的值为多少。
最后paramsData为参数的16进制数据,拼接上合约方法名的16进制即可,如:
var data = "0x41cb3b7b"+paramsData;
//将data传入到rawTx发起交易
...