Ethereum
SmartContract
web3.js

main.netでethereumを送金するサンプル(Web3.js)

はじめに

あまり日本語の説明がなく、gasPriceとgasLimitの設定など少し手こずったので、
Web3.jsを使ったEthereumを送金するサンプルとポイントの覚書です。

private環境では、適当にGasを設定していても、
マイニングされていたのが、mainnet上では上手に設定しないと、マイナーに処理してもらえないので、
適切にGasPriceとGasLimitを設定してあげることが必要となります。

エラー例

GasPriceとGasLimitが適切でない場合は下記のようなエラーに遭遇します。

Unhandled rejection Error: Transaction was not mined within 50 blocks, please make sure your transaction was properly send. Be aware that it might still be mined!

GasPriceとGasLimitが低いため、マイナーが処理してくれない可能性がある

Unhandled rejection Error: Returned error: insufficient funds for gas * price + value

GasPriceとGasLimitの設定が不適切で、送金元に所持しているEtherを超えている可能性がある

Returned error: exceeds block gas limit

GasLimitの設定が大きすぎる

使用するモジュール

(トランザクションの送信)
https://www.npmjs.com/package/ethereumjs-tx
(ウォレットの作成)
https://www.npmjs.com/package/ethereumjs-wallet

送金する

1.読み込み

HttpProvierとして設定するのは、自身の環境として作成したGethのURL。
ここではINFRAを設定。
(参考) INFRA : https://infura.io/

npm install web3@0.20.0
var Web3 = require('web3');
web3 = new Web3(new Web3.providers.HttpProvider('https://mainnet.infura.io/自分のアカウント'));

2.ethereumjs-txの読み込み

var Tx = require('ethereumjs-tx');
var privateKey = new Buffer('---private key---', 'hex');

3.rawTxの設定(gasPriceとgasLimitを設定する)

var rawTx = {
  nonce: '0x07',
  gasPrice: web3.utils.toHex(web3.utils.toWei('0.00000009', 'ether')),
  gasLimit: web3.utils.toHex(22000),
  to: '0x418d0ABF2Bdfa98A8873fFA3CcD538AE76b9E21e',
  value: web3.utils.numberToHex(web3.utils.toWei('0.0001', 'ether')),
  data: web3.utils.asciiToHex('hello')  
}

4.トランザクションの送信

var tx = new Tx(rawTx);
tx.sign(privateKey);
var serializedTx = tx.serialize(); 
console.log(serializedTx.toString('hex')); 
web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex')) 
.on('receipt', console.log);

5.結果

スクリーンショット 2017-11-17 19.19.33.png

6.設定値の取得

rawTxに設定するGasPriceやTransactionの件数などは下記を実行することで参考値を取得できます。

//gasPrice
web3.eth.getGasPrice(function(error, result){console.log("gasPrice:");console.log(result);console.log(web3.utils.toHex(result)); });

//transactionCnt
web3.eth.getTransactionCount(fromAddress,function(error, result){console.log("transactionCnt:");console.log(result); });

//chainId
web3.eth.net.getId(function(error, result){console.log("chainId:");console.log(result); });

//blockNumber
web3.eth.getBlock(function(error, result){console.log("blockNumber:");console.log(result); });

//estimateGas
web3.eth.estimateGas(txData,function(error, result){console.log("gasLimit:");console.log(result);console.log(web3.utils.toHex(result)); });

どれも非同期処理なので、Promiseを用いるなど工夫が必要

const getGasPrice = () => {
    return new Promise((resolve, reject) => {
        web3.eth.getGasPrice((error, result) => {
            if (error) reject(error);
            resolve(web3.toHex(result.toNumber()));
        });
    });
};

Walletの作成

サンプル

送金に使用するwalletなどもethereumjs-wallet/hdkey
を利用することで作成することができます。
下記はbip39を用いることで秘密鍵から、人間が覚えやすいパスワードの生成を行なっています。

function generatewallet() {
    var bip39 = require('bip39')
    var mnemonic = bip39.generateMnemonic()
    const hdkey = require('ethereumjs-wallet/hdkey')
    privateKey = hdkey.fromMasterSeed(mnemonic)._hdkey._privateKey
    const Wallet = require('ethereumjs-wallet')
    const wallet = Wallet.fromPrivateKey(privateKey)
    console.log("address:" + wallet.getChecksumAddressString());
    console.log("mnemonic:" + mnemonic);
}

function importwallet(mnemonic) {
    const hdkey = require('ethereumjs-wallet/hdkey')
    privateKey = hdkey.fromMasterSeed(mnemonic)._hdkey._privateKey
    console.log("privatekey:" + privateKey);
    const Wallet = require('ethereumjs-wallet')
    const wallet = Wallet.fromPrivateKey(privateKey);
}

おしまい