最近話題のweb3を使ったアプリケーション作りたいと思い、とりあえずプログラムでトークンを送信することに挑戦しました。
公式のコードを参考にやってみました。
https://ethereum.org/ja/developers/tutorials/send-token-etherjs/
ほぼこの通りなのですが、このままではエラーが出るので修正しました。(後述)
動作確認環境
- macOS Ventura
- Node.js v20.0.0
準備
Remix(トークン作成)
作り方はこちら
https://qiita.com/tatsuya1970/items/b68da529bcf1a92c5d10
トークンを作成したら、トークンのコントラクトアドレスを控える。
あとで作成する index.js と同じディレクトリに、 abi.json として保存します。
ウォレットの秘密鍵
ここではMetamaskを例にします。
右上の3本点をクリック
アカウントの詳細 > Show Privatekey
この秘密鍵を控えておく。
Infura
Infuraは、Ethereumノードへのアクセスを提供するクラウドサービスです。
https://www.infura.io/
なお、その他は触らないこと。
よかれと思い、ここのチェックをオンにしたため、後々凄くハマってしまいました。
開発
ether.js
Ethereumブロックチェーンのライブラリ ethers.js と
環境変数設定のライブラリ dotenv をインストールします。
$ npm install --save ethers
$ npm install --save dotenv
コード
ほぼ公式のコードと同じです。
修正・追加箇所
修正箇所
(修正前) window.ethersProvider
(修正後) provider
追加箇所
同じディレクトリに保存したABIのJSONファイルを読み出す箇所を追加
const fs = require('fs');
const send_abi = JSON.parse(fs.readFileSync('./abi.json', 'utf8'));
コード
環境変数
さきほど控えた環境変数を設定
INFURA_PROJECT_ID=INFURAのプロジェクトID
PRIVATE_KEY=送信元のウォレットのプライベートキー
メイン
'use strict';
require("dotenv").config();
const { ethers } = require("ethers");
const infuraProjectId = process.env.INFURA_PROJECT_ID;
const provider = new ethers.providers.InfuraProvider('goerli', infuraProjectId);
let private_key = process.env.PRIVATE_KEY;
let send_token_amount = "1";
let to_address = "送信先のアドレス";
let send_address = "送信元のアドレス";
let gas_limit = "0x100000";
let wallet = new ethers.Wallet(private_key);
let walletSigner = wallet.connect(provider);
let contract_address = "先ほど控えたトークンのコントラクトアドレス";
send_token(
contract_address,
send_token_amount,
to_address,
send_address,
private_key
);
function send_token(
contract_address,
send_token_amount,
to_address,
send_account,
private_key
) {
let wallet = new ethers.Wallet(private_key);
let walletSigner = wallet.connect(provider);
provider.getGasPrice().then((currentGasPrice) => {
let gas_price = ethers.utils.hexlify(parseInt(currentGasPrice));
console.log(`gas_price: ${gas_price}`);
if (contract_address) {
const fs = require('fs');
const send_abi = JSON.parse(fs.readFileSync('./abi.json', 'utf8'));
// general token send
let contract = new ethers.Contract(
contract_address,
send_abi,
walletSigner
) ;
// How many tokens?
let numberOfTokens = ethers.utils.parseUnits(send_token_amount, 18);
console.log(`numberOfTokens: ${numberOfTokens}`);
// Send tokens
contract.transfer(to_address, numberOfTokens).then((transferResult) => {
console.dir(transferResult);
console.log("sent token");
})
} // ether send
else {
const tx = {
from: send_account,
to: to_address,
value: ethers.utils.parseEther(send_token_amount),
//nonce: window.ethersProvider.getTransactionCount(
nonce: provider.getTransactionCount(
send_account,
"latest"
),
gasLimit: ethers.utils.hexlify(gas_limit), // 100000
gasPrice: gas_price,
}
console.dir(tx);
try {
walletSigner.sendTransaction(tx).then((transaction) => {
console.dir(transaction)
console.log("Send finished!");
})
} catch (error) {
console.log("failed to send!!");
}
}
});
}
これで実行すると、
TypeError: Cannot read properties of undefined (reading 'InfuraProvider')
困った。
詰んだと思ったら、このブログにヒントがありました。
https://qiita.com/Voldemort/items/b53d9bfe50db5920c425
バージョン5.xにダウングレードするとうまくいきました。
$ npm uninstall ethers
$ npm i -S ethers@5.7.2
結果
送金できました。
https://goerli.etherscan.io/tx/0x8238bc31332f2694767afd6adbceb1eaf39f24b8980428a267bd5965d7be6fd9