ethers.js で使える独自 Signer を作る
https://github.com/odanado/aws-kms-provider で ethers に対応するときのメモ
前提知識
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-provider と abstract-signer にそれぞれのインタフェースが定義されている
抽象的な Signer の実装として、Wallet や VoidSignerinherits などがある
やること
Signer の具体化をすれば良さそう
各メソッドは aws-kms-signer をベースに実装する
Wallet クラスのインタフェースのここが嫌
コンストラクタの一番最後の引数で provider?: Provider
を取るのが具体化された Signer の慣習ぽいけど、この形は引数が増えたときに弱いので嫌い
Factory 関数の引数は Object にしてほしいという話 | potato4d D(iary) の話に通じるところがある
Signer の設計のここが嫌
自分の中で Signer の責務は「アドレスを得ること」と「ハッシュ化されたメッセージに署名をすること」の2つ
ref: https://github.com/odanado/aws-kms-provider/blob/master/packages/aws-kms-signer/src/signer/signer.ts
ethers の Signer の責務はそうなってないのが違和感がある
例えば signMessage
は、生のメッセージが引数で渡されて、例の prefix をつけたり、メッセージのハッシュ化は Signer の責務になる
こちらのほうが Signer ができることが多く、関心事の分離に失敗していると思うけど、どうなんだろう
signTransaction
は、トランザクションが引数で渡されて、返り値で返すのはその署名ではなく RLP エンコードされたトランザクションデータなのも面倒。Signer 側で毎回 RLP しないといけない
できました
Buffer 型なメッセージへのサインだけを行う関数を持つ ISigner
を ethers.js の Signer に変換するアダプターを実装する形にしました