Open6

ethers.js で使える独自 Signer を作る

odanodan

前提知識

Providers とは

A Provider is an abstraction of a connection to the Ethereum network, providing a concise, consistent interface to standard Ethereum node functionality.
https://docs.ethers.io/v5/api/providers/

Signers とは

A Signer in ethers is an abstraction of an Ethereum Account, which can be used to sign messages and transactions and send signed transactions to the Ethereum Network to execute state changing operations.
https://docs.ethers.io/v5/api/signer/

なので、 Provider が Ethereum のノードと署名する君、 Signer がメッセージに署名する君らしい
Provider の実装は Signer の実装を依存に持つ形

パッケージは abstract-providerabstract-signer にそれぞれのインタフェースが定義されている

抽象的な Signer の実装として、Wallet や VoidSignerinherits などがある

odanodan

やること

Signer の具体化をすれば良さそう
各メソッドは aws-kms-signer をベースに実装する

odanodan

Wallet クラスのインタフェースのここが嫌

https://github.com/ethers-io/ethers.js/blob/b1458989761c11bf626591706aa4ce98dae2d6a9/packages/wallet/src.ts/index.ts#L40

コンストラクタの一番最後の引数で provider?: Provider を取るのが具体化された Signer の慣習ぽいけど、この形は引数が増えたときに弱いので嫌い

Factory 関数の引数は Object にしてほしいという話 | potato4d D(iary) の話に通じるところがある

odanodan

Signer の設計のここが嫌

自分の中で Signer の責務は「アドレスを得ること」と「ハッシュ化されたメッセージに署名をすること」の2つ
ref: https://github.com/odanado/aws-kms-provider/blob/master/packages/aws-kms-signer/src/signer/signer.ts

ethers の Signer の責務はそうなってないのが違和感がある
https://github.com/ethers-io/ethers.js/blob/master/packages/abstract-signer/src.ts/index.ts

例えば signMessage は、生のメッセージが引数で渡されて、例の prefix をつけたり、メッセージのハッシュ化は Signer の責務になる
こちらのほうが Signer ができることが多く、関心事の分離に失敗していると思うけど、どうなんだろう

signTransaction は、トランザクションが引数で渡されて、返り値で返すのはその署名ではなく RLP エンコードされたトランザクションデータなのも面倒。Signer 側で毎回 RLP しないといけない
https://github.com/ethers-io/ethers.js/blob/b1458989761c11bf626591706aa4ce98dae2d6a9/packages/wallet/src.ts/index.ts?_pjax=%23js-repo-pjax-container%2C div[itemtype%3D"http%3A%2F%2Fschema.org%2FSoftwareSourceCode"] main%2C [data-pjax-container]#L117