使用 web3js 很容易调用不需要签名的函数(例如不更新合约状态的函数)。但是,除了手动解锁我的 MetaMask 钱包和在Remix环境中调用函数之外,尚不清楚如何调用需要签名的函数。
在第一次将我的 dapp 部署到 Ropsten 之后,我需要调用createItem(string name, uint price)100 次来items最初填充数组。由于我不想在 Remix 中手动执行此操作,因此我想编写一个自动执行此操作的脚本。
看起来我还需要ethereumjs-tx在web3js没有 MetaMask 的情况下以编程方式签署交易。我还需要有我的account和privateKey。有了所有这些信息和官方的 web3js 文档,我想出了以下内容:
// Call an external function programatically
const web3 = new Web3(new Web3.providers.HttpProvider("https://ropsten.infura.io"))
const account = "ACCOUNT_ADDRESS"
const privateKey = new Buffer('PRIVATE_KEY', 'hex')
const contract = new web3.eth.Contract(abi, CONTRACT_ADDRESS, {
from: account,
gas: 3000000,
})
const functionAbi = contract.methods.myFunctionName(myArgument).encodeABI()
let estimatedGas
contract.methods.myFunctionNAme(myArgument).estimateGas({
from: account,
}).then((gasAmount) => {
estimatedGas = gasAmount.toString(16)
})
const txParams = {
gasPrice: '0x' + estimatedGas,
to: CONTRACT_ADDRESS,
data: functionAbi,
from: account,
}
const tx = new Tx(txParams)
tx.sign(privateKey)
const serializedTx = tx.serialize()
web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex')).
on('receipt', console.log)
Run Code Online (Sandbox Code Playgroud)
代码运行,但txParams实际上缺少一个键:nonce. 运行此程序时,您会收到以下错误:
Unhandled rejection Error: Returned error: nonce too low
Run Code Online (Sandbox Code Playgroud)
以下是我的问题:
nonce部署合约的参数?参考:
更新:
感谢 Adam,现在我学会了如何获取nonce. 所以我添加了以下代码:
let nonce
web3.eth.getTransactionCount(account).then(_nonce => {
nonce = _nonce.toString(16)
})
const txParams = {
gasPrice: '0x' + gasPrice,
to: CONTRACT_ADDRESS,
data: functionAbi,
from: account,
nonce: '0x' + nonce,
}
Run Code Online (Sandbox Code Playgroud)
但现在我不断遇到这个异常:
未处理的拒绝错误:返回错误:rlp:输入字符串对于 uint64 来说太长,解码为 (types.Transaction)(types.txdata).AccountNonce
除了让我找到这个具有异常处理程序的文件(https://github.com/ethereum/go-ethereum/blob/master/rlp/decode.go)之外,谷歌搜索没有帮助。有谁知道如何解决这个问题?
一般看起来是正确的。我唯一的问题是你打算如何加载私钥?您需要提示输入私钥,或者在密钥库中导入/读取并提示输入密码。您可以使用keythereum来完成此操作(有关示例代码,请参阅密钥导入部分)。
这nonce只是用于为帐户订购交易的增量编号。要获得正确的值,只需使用web3.eth.getTransactionCount(account)
编辑 - 使用带有锁定帐户的 Ganache 运行示例(--secure选项):
简单合同.sol
pragma solidity ^0.4.19;
contract SimpleContract {
uint public val = 4;
function increment(uint amt) public {
val += amt;
}
function get() public constant returns (uint) {
return val;
}
}
Run Code Online (Sandbox Code Playgroud)
测试.js
const Web3 = require('web3');
const Tx = require('ethereumjs-tx');
const provider = new Web3.providers.HttpProvider("http://localhost:8545");
const web3 = new Web3(provider);
const account = '0x9a6d82ef3912d5ab60473124bccd2f2a640769d7'; // Ganache
const privateKey = Buffer.from('70f1384b24df3d2cdaca7974552ec28f055812ca5e4da7a0ccd0ac0f8a4a9b00', 'hex');
const contractAddress = '0x6dd7c1c13df7594c27e0d191fd8cc21efbfc98b4'; // Deployed manually
const abi = [{"constant":true,"inputs":[],"name":"val","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"amt","type":"uint256"}],"name":"increment","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}];
const contract = new web3.eth.Contract(abi, contractAddress, {
from: account,
gasLimit: 3000000,
});
const contractFunction = contract.methods.increment(3);
const functionAbi = contractFunction.encodeABI();
let estimatedGas;
let nonce;
console.log("Getting gas estimate");
contractFunction.estimateGas({from: account}).then((gasAmount) => {
estimatedGas = gasAmount.toString(16);
console.log("Estimated gas: " + estimatedGas);
web3.eth.getTransactionCount(account).then(_nonce => {
nonce = _nonce.toString(16);
console.log("Nonce: " + nonce);
const txParams = {
gasPrice: '0x09184e72a000',
gasLimit: 3000000,
to: contractAddress,
data: functionAbi,
from: account,
nonce: '0x' + nonce
};
const tx = new Tx(txParams);
tx.sign(privateKey);
const serializedTx = tx.serialize();
contract.methods.get().call().then(v => console.log("Value before increment: " + v));
web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex')).on('receipt', receipt => {
console.log(receipt);
contract.methods.get().call().then(v => console.log("Value after increment: " + v));
})
});
});
Run Code Online (Sandbox Code Playgroud)
结果:
$ npm run my_test
> hello_world_dapp@1.0.0 my_test C:\cygwin\home\adamk\eth\hello_world_dapp
> node ./test.js
Getting gas estimate
Estimated gas: 6919
Nonce: 5
Value before increment: 19
{ transactionHash: '0xb6fdfc36cc32cb01a2be8832a387da586a44a37c1241bbf2979745536f206ed4',
transactionIndex: 0,
blockHash: '0xb6ee8d4e45585010d9a12d48aa37a478eb6021aad78599f1719cb424ab364bb5',
blockNumber: 10,
gasUsed: 26905,
cumulativeGasUsed: 26905,
contractAddress: null,
logs: [],
status: 1 }
Value after increment: 22
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5501 次 |
| 最近记录: |