ethers.js 使い方メモ
Hardhatではethers.jsを使っているので、Web UIサイトを作成するときにもweb3.jsではなくethers.jsを使ってみることにしました。
コントラクトを扱うには、Provider作成→Signer作成→Contract作成、という流れになります。Read-onlyならSignerは不要です。
Provider
Ethereumネットワーク → DefaultProvider
// APIキーを指定 const provider = ethers.getDefaultProvider("homestead", {etherscan: "XXX", infura: "XXX", alchemy: "XXX"});
// APIキーを省略 const provider = ethers.getDefaultProvider("homestead");
ネットワーク名は "homestead", "rinkeby", "ropsten" のような名前か chainIDを指定します。
オプションで、etherscan, infura, alchemyなどのAPIキーを指定できます。 (省略しても使えますが、共有のAPIキーが使われるので遅くなります。)
ローカルネットワーク → DefaultProvider
const provider = ethers.getDefaultProvider("http://localhost:8545");
PolygonやBSCなど → JsonRpcProvider
JsonRpcProviderでRPC URL を指定します。
const provider = new ethers.providers.JsonRpcProvider(rpcURL);
MetaMaskと接続 → Web3Provider
const provider = new ethers.providers.Web3Provider(window.ethereum)
Signer (Wallet)
Signerとは署名するためのクラスで、WalletはSignerの一種です。
秘密鍵からWalletを作成
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);
ニモニックからWalletを作成
const wallet = ethers.Wallet.fromMnemonic(MNEMONIC).connect(provider);
MetaMaskのアカウントを使う
const provider = new ethers.providers.Web3Provider(window.ethereum); const signer = provider.getSigner();
コントラクトを扱う
コントラクトアドレス、ABI、ProviderまたはSignerからContractを作成します。
const contract = new ethers.Contract(contractAddress, abi, provider); // read-only
const contract = new ethers.Contract(contractAddress, abi, signer); // read/writeの場合
後は、関数を呼び出すだけです。
Read
Read関数なら、そのままawaitで値を取得できます。
const value = await contract.getValue();
console.log(value);
Write
Write関数の場合はtransactionが返ってきます。
const tx = await contract.setValue(123); const receipt = await tx.wait(); // マイニングされるまで待つ
イベント
イベントはcontract.onで受信します。
contract.on("event_name", (params)=>{ // イベント発生時の処理 }) // contract.once(...)なら一度だけ
ABIについて
従来のJSON形式のABIファイルももちろん使えますが、ethers.jsではHuman-Readable ABIというのにも対応していて、 Solidityの関数の1行目だけを切り取ったような形式を用意するだけでよいので便利です。
// Human-Readable ABI (シンプル) const abi = [ "function transferFrom(address from, address to, uint value)", "function balanceOf(address owner) view returns (uint balance)", "event Transfer(address indexed from, address indexed to, address value)" ];
// 従来のABI (長い) const abi = `[ { "type": "function", "name": "transferFrom", "constant": false, "payable": false, "inputs": [ { "type": "address", "name": "from" }, { "type": "address", "name": "to" }, { "type": "uint256", "name": "value" } ], "outputs": [ ] }, ...