INFURAではプライベートキーを提供していない関係で、sendTransactionを利用することができません。しかし、ethereumjs-txを利用してトランザクションを生成すれば、デプロイしたコントラクトに対してステートを変更することが可能です。
※ethereumjs-tx@2〜 に関しては下記ページをご覧下さい。
ethereumjs-tx version 2 を利用する [Tx is not a constructor][invalid sender]
開発環境
macOS High Sierra
Truffle v4.1.8
node v8.9.3
web3@1.0.0-beta.34
ethereumjs-tx@1.3.4
下記関連ページでは、プライベートネットであるGanache上でコントラクトをデプロイしました。
web3.jsでブラウザからコントラクトにアクセスする[Ganache]
下記は、そのデプロイしたコントラクトのコードですが、set関数にはコントラクトのステートを変更させる処理が記述されています。web3ではこの処理をsendTransactionによって実行する(set関数を呼び出す)ことできます(上記ページ参照)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
pragma solidity ^0.4.23; contract sample { string public name = "taro"; function set(string _name) public { name = _name; } function get() constant public returns (string) { return name; } } |
ただ、INFURAでデプロイしたコントラクトに対しては、sendTransactionを利用することができません。先に述べたようにINFURAではプライベートキーを提供していないので、web3だけでは署名付きのトランザクションを生成することができず、コントラクトのステートを変更させるような処理を行えないからです。
しかし、ethereumjs-txを利用すればトランザクションを生成することが可能となります。今回は、set関数の引数に”hanako”と指定するような処理をトランザクションに設定し、”taro”から”hanako”とコントラクトのステートを変更させるような処理をしてみます。
まずは前提として、上記のコントラクトコードをINFURAにデプロイします。その手順に関しては下記のページを参照して下さい。※下記ページ内のHelloWorld.solを、そのまま上記のコントラクトコードに置き換えて下さい。
TruffleでINFURAにコントラクトをデプロイする[web3.js]
コントラクトをデプロイすることができたら、Node.jsによってそのコントラクトにアクセスします。
web3とethereumjs-txをインストールしておきます。
1 2 |
npm install web3 npm install ethereumjs-tx |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
const Web3 = require('web3'); const Tx = require('ethereumjs-tx'); //取得したAPIキーを設定する const provider = new Web3.providers.HttpProvider('https://ropsten.infura.io/APIキー'); const web3 = new Web3(provider); //MetaMaskのアカウントの秘密鍵です const account = 'アカウントのアドレス'; const privateKey = Buffer.from('秘密鍵', 'hex'); //デプロイしたコントラクトのアドレスとABI情報を設定する const contractAddress = 'コントラクトのアドレス'; const abi = [ ABI情報 ]; const contract = new web3.eth.Contract(abi, contractAddress, { from: account, gasLimit: 3000000, }); //set関数に引数を設定 const contractFunction = contract.methods.set("hanako"); const functionAbi = contractFunction.encodeABI(); let estimatedGas; let nonce; 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 = { nonce: '0x' + nonce, gasPrice: web3.utils.toHex(web3.utils.toWei('4', 'gwei')), gasLimit: web3.utils.toHex(210000), from: account, to: contractAddress, data: functionAbi }; 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)); }) }); }); |
33行目
nonceには、トランザクションを生成するアカウント(つまりfromに設定しているアカウント)のnonceの値が設定されます。
参照ページ
https://stackoverflow.com/questions/48838899/sending-signed-transactions-to-ropsten