Skip to content
  • 更新日: 2024年3月28日

ethers.jsEthereumプロジェクトのためのJavaScriptライブラリであり、v6とv5のバージョン間にはいくつかの重要な変更があります。ここでは、それらの主な変更点について解説します。説明およびサンプルコードは、公式ドキュメントから和訳・引用しています。詳細な情報はこちらを参照してください。

開発者が心に留めておく必要がある最大の変更です。
v5では、プロジェクトは大きなサブパッケージの集合のmonorepoとして管理されていました。v6では、すべての Import はルートパッケージで利用可能です。また、より細かい制御を行いたい人のために、pkg.exportsは特定のフォルダを直接利用可能にしています。

v5の Import

v5では、多くのもの(全てではない)がルートパッケージで利用可能でした。

import { ethers } from "ethers"

いくつかのパッケージは追加プロパティの後ろにグループ化されていますが、

import { providers } from "ethers"
const { InfuraProvider } = providers

詳細なアクセス制御を行うには、サブパッケージからのインポートが必要でした。

import { InfuraProvider } from "@ethersproject/providers"

v6の Import

v6では、すべてがルートパッケージで利用可能です。

import { ethers } from "ethers"
import { InfuraProvider } from "ethers"

pkg.exportsは、詳細なアクセス制御を提供します。

import { InfuraProvider } from "ethers/providers"

Provider

これも最大の変更です。Web3Provider(これまで link-web3 Provider をラップするために使用されていた)がBrowserProviderと呼ばれるようになりました。

EIP-1193 Providerのラッピング

v5

provider = new ethers.providers.Web3Provider(window.ethereum)

v6

provider = new ethers.BrowserProvider(window.ethereum)

トランザクションのブロードキャスト

また、トランザクションをネットワークにブロードキャストする方法が変更されました。

v5

provider.sendTransaction(signedTx)

v6

provider.broadcastTransaction(signedTx)

Contracts

v6では、コントラクトがES6 Proxyであり、実行時にメソッド名を解決できます。

Ambiguous Methods(曖昧なメソッド)

v5のコントラクト

v5では、曖昧なメソッドの場合、正規化されたシグネチャでメソッドを検索する必要がありました。また、重複した定義を実行時に検出する方法がなかったため、コンソールに警告が表示されていました。

abi = [
  "function foo(address bar)"、
  "function foo(uint160 bar)"、
]
contract = new Contract(address, abi, provider)
// 必要なメソッドにアクセスするために、 正規化された完全修飾シグネチャを指定する必要がある
contract["foo(address)"](addr)

// シグネチャが正規化されていないため、これらは失敗する
contract["foo(address )"](addr)
contract["foo(address addr)"](addr)

// こちらもメソッドが曖昧なので、失敗する
contract.foo(addr)

v6のコントラクト

v6ではシグネチャを正規化する必要はなく、Typed APIは目的のメソッドにアクセスするためのよりクリーンな方法を提供しています。

abi = [
  function foo(address bar)",
  function foo(uint160 bar)",
]
contract = new Contract(address, abi, provider)
// どれも成功する
contract["foo(address)"](addr)
contract["foo(address )"](addr)
contract["foo(address addr)"](addr)

// これはまだ失敗する
// どのメソッドが意図されたものなのかを知る方法がないため
contract.foo(addr)

// しかし、型付きAPIなら成功する
// Contractに型付け情報を提供することができるため
contract.foo(Typed.address(addr))

その他のメソッド操作

v5では、コントラクトは一連のメソッド・バケットを含み、そのメソッド・バケットに、より一般的でない操作を実行するためのすべてのシグネチャと曖昧でない名前が付けられていました。v6では、各メソッドには、それ自身のあまり一般的でない操作が直接付加されています。

v5のその他の操作

// デフォルトのアクションは、メソッドに基づいて送信または呼び出しを選択する
// type (pure, view, constant, non-payable or payable)
contract.foo(addr)

// これは、デフォルトのアクションを実行するが
// Resultオブジェクトを返す
contract.functions.foo(addr)

// 強制的に呼び出す
contract.callStatic.foo(addr)

// ガスを見積もる
contract.estimateGas.foo(addr)

// トランザクションを生成する
contract.populateTransaction.foo(addr)

v6のその他の操作

// 動作は同じ
contract.foo(addr)

// 呼び出しを実行し、結果オブジェクトを直接返す
contract.foo.staticCallResult(addr)

// 呼び出しを強制的に使用する (支払い可能、支払い不可能の場合でも)
contract.foo.staticCall(addr)

// トランザクションを強制的に送信する(pureとviewの場合でも同様)
contract.foo.send(addr)

// ガスを見積もる
contract.foo.estimateGas(addr)

// トランザクションを入力する
contract.foo.populateTransaction(addr)

BigNumber

v6では、BigNumberクラスが、ES2020 BigIntに置き換わりました。ES2020 BigIntは、最近のJavaScript環境で提供されている組み込みです。BigNumber と同様、ES2020 BigInt は整数しか扱えないことに注意しましょう。
JavaScriptのES2020 BigIntを使い始めるためのオンラインドキュメントはたくさんあります
( 例:ES2020の新機能 – とほほのWWW入門 )。
また、FixedNumber クラスは、固定小数点演算を行うために存在します。

大きな数値の作成

v5でBigNumberを使う

value = BigNumber.from("1000")

v6でBigIntを使う(リテラル記法を使う)

// 接尾辞 n に注意
value = 1000n

// 文字列に対するBigInt関数の使用
value = BigInt("1000")

大きな数値の簡単な計算

v5 で2つの値を加算する

sum = value1.add(value2)

v6 で BigInt を使用して2つの値を加算する

// 両方の値がBigIntでなければならない
sum = value1 + value2

大きな数値の単純比較

v5 で等しいかどうかをチェックする

isEqual = value1.eq(value2)

v6 で BigInt を使用

isEqual = (value1 == value2)

Signature(シグネチャ)

Signatureは、すべてのパースとシリアライズを容易にするクラスとなりました。

シグネチャ操作

v5

splitSig = splitSignature(sigBytes)
sigBytes = joinSignature(splitSig)

v6

splitSig = ethers.Signature.from(sigBytes)
sigBytes = ethers.Signature.from(splitSig).serialized

Transaction(トランザクション)

v5に存在したトランザクションヘルパーは、すべて Transaction クラスに含まれます。さらに、処理するためにサポートされている、任意のトランザクション形式を扱うことができます。

トランザクションの解析

v5

tx = parseTransaction(txBytes)
txBytes = serializeTransaction(tx)
txBytes = serializeTransaction(tx, sig)

v6

tx = Transaction.from(txBytes)

v6( tx はオプションでシグネチャを含むことができる)

txBytes = Transaction.from(tx).serialized

Utilities(ユーティリティ)

Bytes32 string helpers

v5

bytes32 = ethers.utils.formatBytes32String(text)
text = ethers.utils.parseBytes32String(bytes32)

v6

bytes32 = ethers.encodeBytes32String(text)
text = ethers.decodeBytes32String(bytes32)

constants(定数)

v5

ethers.constants.AddressZero
ethers.constants.HashZero

v6

ethers.ZeroAddress
ethers.ZeroHash

データ操作

v5

slice = ethers.utils.hexDataSlice(value, start, end)
padded = ethers.utils.hexZeroPad(value, length)

v5(数値を16進数に変換する)

hex = hexlify(35)

v6

slice = ethers.dataSlice(value, start, end)
padded = ethers.zeroPadValue(value, length)

v6(数値を16進数に変換する)

hex = toBeHex(35)

defaultAbiCoder

v5では、AbiCoderのプロパティを使用していました。

coder = AbiCoder.defaultAbiCoder

v6 では、AbiCoder の静的関数であり、シングルトン・パターンを使用します。初めて呼び出されたときに AbiCoder が生成され、それ以降の呼び出しではその最初のインスタンスが返されます。

coder = AbiCoder.defaultAbiCoder()

コンテンツの取得

v5(body付属、特殊なものはなし)

data = await ethers.utils.fetchJson(url, json, processFunc)

v5で接続をオーバーライドする

req = {
  url, user: "username", password: "password"
  // これらなどのプロパティは FetchRequest と同等
};
data = await ethers.utils.fetchJson(req, json, processFunc)

v6

req = new ethers.FetchRequest(url)

// bodyを設定(任意)
req.body = json

// 認証情報を設定(任意)
req.setCredentials("username", "password")

// processFunc を設定する(任意)
req.processFunc = processFunc

// リクエストを送信する
resp = await req.send()

希望する形式によって、response bodyを取得します。

// Uint8Array
data = resp.body

// Utf8String(無効な場合に返す)
data = resp.bodyText

// Object(無効な場合に返す)
data = resp.bodyJson

16進数変換

v5

hex = ethers.utils.hexValue(value)
array = ethers.utils.arrayify(value)

v6

hex = ethers.toQuantity(value)
array = ethers.getBytes(value)

solidity 非標準パック

v5

ethers.utils.solidityPack(types, values)
ethers.utils.solidityKeccak256(types, values)
ethers.utils.soliditySha256(types, values)

v6

ethers.solidityPacked(types, values)
ethers.solidityPackedKeccak256(types, values)
ethers.solidityPackedSha256(types, values)

プロパティ操作

v5

ethers.utils.defineReadOnly(obj, "name", value)

v6

ethers.defineProperties(obj, { name: value });

commify

v5

ethers.utils.commify("1234.5")

v6では、これらのローカル固有のユーティリティの一部を削除しています。しかしこの機能は簡単に再現でき、希望の出力形式に応じて調整できます。

function commify(value) {
  const match = value.match(/^(-?)([0-9]*)(\.?)([0-9]*)$/);
  if (!match || (!match[2] && !match[4])) {
    throw new Error(`bad formatted number: ${ JSON.stringify(value) }`);
  }

  const neg = match[1];
  const whole = BigInt(match[2] || 0).toLocaleString("en-us");
  const frac = match[4] ? match[4].match(/^(.*?)0*$/)[1]: "0";

  return `${ neg }${ whole }.${ frac }`;
}

commify("1234.5");

削除されたクラスと関数

Loggerクラスは、いくつかのErrorユーティリティ関数に置き換えられました。
checkPropertiesshallowCopy は削除され、.mapObject.assign が使われるようになりました。

参考にしたページ

https://docs.ethers.org/v6/migrating/

ブロックチェーンを学び、新しいことをサービスを作りたい人が集まるコミュニティーを運営しています。
・これから実現したいサービスやプロダクトにブロックチェーンを使いたい
・ブロックチェーンが自分の課題を解決する糸口としたい
・ブロックチェーンの技術を学んでプロダクト開発をしたい

興味のある方は詳細をご覧ください!

Back To Top
Search