ethers.jsでコントラクトのRead-onlyメソッドを叩いたときの戻り値
Read-Onlyメソッドを叩いたときの戻り値
ethers.jsでは、Read-Onlyメソッドは以下のシンタックスで叩きます。
contract.METHODNAME( ...args [ , overrides ] ) ⇒ Promise< any >
戻り値はPromise<any>
となっていますが、single valueの場合は値がそのまま返り、それ以外の場合はResult
型が返ります。
Result型
Result型については、ethers.jsの公式docを見ると以下のように書かれています。
A Result is an array, so each value can be accessed as a positional argument.
Additionally, if values are named, the identical object as its positional value can be accessed by its name.
基本的には配列で返りますが、構造体が返される場合はプロパティアクセスも可能な変則的なオブジェクトです。
実装を調べると以下のようになっています。
export interface Result extends ReadonlyArray<any> {
readonly [key: string]: any;
}
console.logすると少し戸惑うかも
たとえばsolidityソース上で以下のような構造体があったとします。
struct User {
uint256 age;
string name;
}
関数の戻り値がUser
構造体だった場合を考えましょう。
const result = await contract.func();
console.log(result);
// 単純な配列が返ってきているように見える
// [{"type":"BigNumber","hex":"0x02"},"Tanaka"]
console.log(result.age);
// アクセスしてみるとプロパティも生えているのがわかる
// {"type":"BigNumber","hex":"0x02"}
Arrayを継承している影響
Result
型がReadonlyArray
を継承しているので、console.log
したときの表示のされ方もArray
に準拠する形になっています。
オブジェクトのプロパティアクセスが出来るので、Object.keys()
などを使用すると多少戸惑うかもしれません。
【参考】callStaticでも同様
Writeメソッドであっても、callStatic
を使用するとRead-Onlyメソッドと同じような形でResult
型で返るようになります。
const result = await contract.callStatic.func();
// 以下Read-Onlyと同様
通常のWriteメソッドは戻り値がPromise<TransactionResponse>
なので、eventをemitすることでテスト等を行うと思います。
event経由は多少手間である一方で、callStatic
を使うことで直接戻り値を扱うことができ便利です。
ただし、callStatic
の名称の通り、この呼び出し方をした場合はコントラクトの状態更新は行われないことに注意してください。
Discussion