Account Abstraction(ERC4337)を、具体的な処理を追ってしっかりと理解してみましょう。
こんにちは、CryptoGamesのユウキです。
本日は、こちらの「Stackup」を利用して、Account Abstractionを実際に行い、その仕組みを見ていこうと思います。
なお、こちらは2023年1月26日(木)に予定しているAccount Abstractionの勉強会用の資料です。
YouTubeはこちらからご確認できます。
(Webでの再生ができないですが、実際にYouTubeに行けば見ることができます。)
0 大まかな内容を理解する
内容に入る前に、仕組みを簡単に見てみましょう。
1. アカウントとは?
まず、アカウントには次の2つがあります。
- EOA(いわゆるウォレットアドレス)
- コントラクトアカウント
コントラクトアカウントには秘密鍵がありません。
また、コードが書かれているので、色々な処理を書くことができます。
一方、EOAには秘密鍵があります。
そして、プロトコル上、トランザクションの起点は必ずこのEOAである必要があります。
これをプロトコルを変えずに解決しようとしているのが、今回紹介するERC4337です。
2. 上の何が問題なの?
では、現状の何が問題なのか、また、AAにすることでどんなメリットがあるのかを見ていきましょう。
今回は2つしか取り上げませんが、こちらのbluesky-aozoraさんの翻訳記事のPart3がとても分かりやすいと思いました。
コントラクトアカウントはコードが書かれるので、特定の処理を行わせることができ、それがメリットへとつながっていきます。
3. セキュリティリスクの軽減
Web3での最重要項目の一つに、秘密鍵の管理がありますね。
秘密鍵を使って、署名を行います。
そのため、秘密鍵を紛失すると、署名が起こせなくなります。
また、盗難されると、誰かに勝手に署名されてしまいます。
ここではこの対応策を2つ見てみましょう。
①マルチシグウォレット
マルチシグウォレットはその名の通り、トランザクションを起こすのに、Signature(署名)が複数必要です。
例えば、3人のうち、2人の署名が必要とすれば、仮に1つの秘密鍵が盗難されても、その1つの秘密鍵だけではトランザクションを起こすことができません。
Gnosis Safeを使えば、簡単にマルチシグウォレットが作れるので、よかったら試してみてください。
②ソーシャルリカバリー
他にも、ヴィタリックはソーシャルリカバリーにも言及しています。
あらかじめ、ガーディアン(保護者)を決めておき、万一の秘密鍵を紛失した際に、変更することができるようにしています。
https://vitalik.ca/general/2021/01/11/recovery.html
この方法であれば、トランザクションの度にマルチシグのような複数の署名は必要なくなります。
4. 量子コンピュータへの対策
公開鍵は秘密鍵から生成されます。
ただし、公開鍵から秘密鍵は導かれないため、私たちは公開鍵を公開できます。
https://jba-web.jp/blogs/sugii_20200618
しかし、量子コンピュータの発展に伴い、公開鍵から秘密鍵を導くことが理論上可能になると言われています。
https://coinpost.jp/?p=256081
まだ将来の話や可能性の話かもしれませんが、これは個人的には非常に脅威であると感じています。
しかし、イーサリアムは、ECDSAという暗号技術を使うことがプロトコルとして決まっているため、そのプロトコルが変わらない限り、この脅威は去りません。
https://zoom-blc.com/what-is-ecdsa
しかし、Account Abstractionにより個々のロジックを変更することができるので、量子耐性の強い署名方法にすることができます。
https://medium.com/@bluesky-aozora/account-abstraction-アカウント抽象化-とは-9fa34a5de876
ただ、注意として、プロトコル自体が変わるわけではないので、ECDSAは変わらず残っています。
この辺りはややこしいですので、次で触れたいと思います。
5. 抽象化(Abstraction)について考えてみよう
①通常の処理
例えば、通常のトランザクションを考えてみましょう。
トランザクションの内容や、「本当にAさんなの?」というように、とても具体的です。
https://www.profound-dt.co.jp/blockchain/chap5/
②Account Abstractionの処理
では、Account Abstractionを見てみましょう。
具体的な検証や処理はエントリーポイントというコントラクトが行っています。
一方、先ほど具体的であった部分は、「本当にバンドラーさん(まとめてくれる人)?」であったり、処理の部分もとても抽象的です。
また、この部分はイーサリアムのプロトコルに沿って行われるので、この部分はECDSAという暗号技術が使われます。
このように、Account Abstractionは通常の処理に比べて、非常に抽象的です。
6. 主な仕組み
まずは、下の図を見てください。今は詳細な理解は不要です。
見ると、「Bundler」 がトランザクションを起こしています。
トランザクションの起点はEOAなので、「Bundler」 はEOAです。
そして、下のように、「UserOperation」 を、「Bundler」 に渡しています。
「UserOperation」 の中にはコントラクトアカウントや実行するために必要なデータが入っています。
そして、下のように、「UserOperation」 を、「Bundle transaction」 にまとめてもらっています。
つまり、EOAである 「Bundler」 さんがtransactionの起点となることで、私たちはコントラクトアドレスから実行 することができます。
これがERC4337 の主な仕組みです。
1 全体像を把握する
まずは、全体像を把握しましょう。
結局下のことが行われていますので、一つ一つ見ていきましょう。
1. UserOperationを作る
まずは、userが「UserOperation」を作っています。
「UserOperation」とは、
- 送り主は?
- 何を実行したい?
- ガスの上限は?
のような要素をまとめてパッケージにしたイメージです。
2. Bundlerが取ってくる
続いて、この「UserOperation」を「Bundler」が取ってきます。
「Bundler」とはその名の通り(bundle:束ねる)、「UserOperation」を束ねてくれます。
3. BundlerがUserOperationをトランザクションにまとめる
そして、 「Bundler」がその名の通り(bundle:束ねる)の、「UserOperation」を束ねることをしてくれます。
4. トランザクションがBlockに入る
最後に、3で作ったトランザクションが他のトランザクションと同じように、Blockに入っています。
ちなみに、この部分をもう少し詳しく見てみましょう。
「Bundler」は「EntryPoint」というコントラクトに「UserOperation」をまとめたものを送っています。
「EntryPoint」は大まかに、それぞれの「ウォレットコントラクト」を①検証し、それぞれのバックの中に入っている②処理を実行します。
ちなみに、それらができるのは、「UserOperation」の中にパッケージとして、「ウォレット」や「署名」などが入っているためです。
https://docs.stackup.sh/docs/introduction/erc-4337-overview
5. 全体像をもう一度見てみよう
これらを踏まえるとこのような流れになっています。
「UserOperation」というパッケージが「Bundler」でまとめられ、「EntryPoint」というコントラクトに送られます。
「EntryPoint」はそれぞれの「ウォレットコントラクト」に対して、①検証と②処理の実行を行います。
https://docs.stackup.sh/docs/introduction/erc-4337-overview
これで全体像としては、以上です。
わからなくなった時は、また全体像を見てみると、イメージがつきやすいかと思います。
2 実際にやってみよう
では、「Starkup」を使って実際にやってみましょう。
処理の流れについては、こちらもご参照ください。
では、やっていきます。
1. コードを見てみましょう
下のように、「config.json」という構成ファイルがあります。
全体像で出てきた、「Bundler」や「EntryPoint」がいますね。
2. BundlerのURLを取得する
下の、「Starkup」のページに行きます。
登録すると、次のように、Bundlerが利用ができるようになるので、ここから、URLをコピー。
下の、「bundlerURL」に貼り付けます。
ここで、全体像の復習ですが、UserOperationを送る先のBundlerのURLを設定していましたね。
3. 「ウォレット」アドレスを取得する
では、Userとなる、「ウォレット」アドレスを取得していきます。
この段階では、まだコントラクトアドレスではありません。
{
"bundlerUrl": "http://localhost:4337",
"rpcUrl": "https://rpc-mumbai.maticvigil.com/",
"signingKey": "",
"entryPoint": "0x1306b01bC3e4AD202612D3843387e94737673F53",
"simpleAccountFactory": "0xc99963686CB64e3B98DF7E877318D02D85DFE326"
}
こちらを実行します。
yarn run simpleAccount:address
下のように、アドレスが取得できました。
Polygonscan(mumbai)で見てみると、下のように「Address」となっています。
処理を行うために、外からこのアドレスに0.2maticを送りました。
4. 処理を実行する(transfer)
では、準備ができたので、処理を行なっていきましょう。
yarn run simpleAccount:transfer <受け取り先アドレス> <amount>
今回は、0.1 maticを別のアドレスに送ろうとしています。
下のようになりました。何やら、「UserOperation」ができていそうですね。
Polygonscan(mumbai)を見ると、コントラクトができていることがわかります。
作っているのは、下の「SimpleAccountFactory」になります。
5. transferの処理を具体的に見ていこう
まずは、下のように、アカウントの取得の際に、「SimpleAccountFactory」が引数に入っていることが確認できます。
また、余談ですが、コマンドに渡していた引数もこのように確認できました。
①UserOperationの作成について
そして、下のように、「UserOperation」が作られ、その中の「initCode」を見ると、「SimpleAccountFactory」のアドレスが確認できます。
ちなみに、全体像の復習ですが、この「UserOperation」が作られたのですね。
②initCodeとは
ちなみに、こちらの「initCode」はウォレットを作るためのコードです。
ウォレットが作られていない場合、「EntryPoint」を通じて、このコードからウォレットを作ってくれます。
https://medium.com/infinitism/erc-4337-account-abstraction-without-ethereum-protocol-changes-d75c9d94dc4a
これにより、「EntryPoint」が「initCode」をの内容を実行し、そのコードに従って、「simpleAccountFactory」がコントラクトを作成しました。
③UserOperationのBundlerへの送付
下のように、「sendUserOpToBundler」で、「Bundler」に「UserOperation」に送っています。
そして、「Bundler」が「UserOperation」をまとめて、「EntryPoint」に送るのは「Bundler」の仕事なので、これでこちらの処理としては完了しています。
流れとしては、このようになっていましたね。
6. EntryPointとウォレットコントラクトのやりとりを見てみる
①概要について
下のように、①検証と②処理の実行が行われていましたね。
そして、実はガスの支払いと使わなかったガスの返金も行われています。
②検証部分について
そして、検証の部分を具体的に見ると、「ウォレットコントラクト」から「EntryPoint」にガスが支払われています。
それが、Polygonscan(mumbai)ではここにあたります。
確かにガスが支払われていますね。
②実行部分について
では、実行部分を見てみましょう。
下のように、「EntryPoint」が「calldata」と共に「ウォレットコントラクト」を呼び出しています。
ここで、「calldata」とは、下のように、「UserOperation」に含まれる、実行のために必要なデータです。
実際に、Polygonscan(mumbai)で見てみると、下のように、「ウォレットコントラクト」から「受け取りアドレス」に対して、指定した0.1Maticがtransfer(送付)されていました。
最後に、下のように、使われなかったガスが「EntryPoint」から「ウォレットコントラクト」に返還されます。
実際に、Polygonscan(mumbai)で見てみると、どうやら、Bundlerに返されているようです。
ここの部分を運営に確認したところ、ドキュメントを修正する必要がありそうですという回答をいただきました。(2023/1/24)
7. transferを実行する(ウォレットがすでにできている状態)
では、最後にもう一度新しく、0.2Maricの送付の処理を行ってみましょう。
ここで、前回と異なるのは、「initCode」です。
こちらは、すでに「ウォレットコントラクト」が作成されているため、中身は特にないようですね。
処理はこのように実施されました。
3 おすすめの日本語記事
最後に、とても勉強になる日本語の記事を紹介します。
1. AA(Account Abstraction)の先にある、コントラクトウォレット中心の世界(m0t0k1ch1さん)
非常におすすめです!
私は、ヴィタリックの記事を読んだ後、「ここって、つまりこういうことだよね??」という疑問などについて、明確に説明 してくださっていて、とても助かりました。
「つまり、バンドラーさんって、EOAだよね??」というようなイメージを明確に答えてくれています。
また、私の記事の中で、書かせていただいた処理(例えば、エントリーポイントによる検証)が具体的に説明 されています。
ぜひ読んでいただきたい記事です。
2. 【EIP-4337】UserOperationをBundlerに投げてからTransactionが発行されるまで(taxioさん)
こちらも非常におすすめです!
バンドラーさんからトランザクションまでを細かく 説明してくれています。
実は、バンドラーは3つの構成要素 からなっています。
よく考えると、バンドラーさんはEOAなのに、それだけで、いろんな処理ができるって変ですもんね。
Account Abstractionについて、大まかに学んだ後、この記事を読むと、理解に深みが増すと思います。
3. Account Abstraction(アカウント抽象化)とは?(bluesky-aozoraさんによる翻訳記事)
最後も、とてもおすすめです!
こちらは、コードについては触れられていないので、エンジニアでない方も読みやすいと思います。
Account Abstractionについてはなんとなく理解したけど、それによって、どんな未来・可能性が待っているんだろう ということを細かく説明してくれています。
AAの未来を思い描くのにとても良いと思います。
4 最後に
今回は以上です。
どうしても、難しい概念なので、この記事だけでしっくりと理解するのは難しいかもしれません。
もう一度読み直していただいたり、実際に手を動かしてみる、また、何より上の3つの記事も合わせて読むことにより、多角的にAccount Abstractionをイメージできるのではと思います。
かなり長かったですが、最後までお読みいただき、ありがとうございました。
Discussion
大変参考になりました!!
よかったです!
ありがとうございます!
素晴らしい記事ありがとうございます!!