📑

ethers.jsでコントラクトのRead-onlyメソッドを叩いたときの戻り値

2022/08/10に公開

Read-Onlyメソッドを叩いたときの戻り値

ethers.jsでは、Read-Onlyメソッドは以下のシンタックスで叩きます。

contract.METHODNAME( ...args [ , overrides ] ) ⇒ Promise< any >

戻り値はPromise<any>となっていますが、single valueの場合は値がそのまま返り、それ以外の場合はResult型が返ります。

https://docs.ethers.io/v5/api/contract/contract/#Contract-functionsCall

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.

https://docs.ethers.io/v5/api/utils/abi/interface/#Result

基本的には配列で返りますが、構造体が返される場合はプロパティアクセスも可能な変則的なオブジェクトです。

実装を調べると以下のようになっています。

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と同様

https://docs.ethers.io/v5/api/contract/contract/#contract-callStatic

通常のWriteメソッドは戻り値がPromise<TransactionResponse>なので、eventをemitすることでテスト等を行うと思います。
event経由は多少手間である一方で、callStaticを使うことで直接戻り値を扱うことができ便利です。

ただし、callStaticの名称の通り、この呼び出し方をした場合はコントラクトの状態更新は行われないことに注意してください。

Discussion