Account Abstractionを、具体的な処理を追ってしっかりと理解してみましょう。
この記事に辿り着いてくださり、ありがとうございます!
この記事の内容を大幅にグレードアップしたのがこちらの記事です。
よかったらご参考にどうぞ。
以下、過去に書いた内容です。
==============
こんにちは、CryptoGamesのユウキです。
本日は、こちらの「Starkup」を利用して、Account Abstractionを実際に行い、その仕組みを見ていこうと思います。
なお、ちょっと長いですが、こちらのヴィタリックの記事はとても参考になると思います。
0 大まかな内容を理解する
内容に入る前に、仕組みを簡単に見てみましょう。
1. 問題の所在
まず、アカウントには次の2つがあります。
- EOA(いわゆるウォレットアドレス)
- コントラクトアカウント
コントラクトアカウントには秘密鍵がありません。
また、コードが書かれているので、色々な処理を書くことができます。
一方、EOAには秘密鍵があります。
そして、プロトコル上、トランザクションの起点は必ずこのEOAである必要があります。
これをプロトコルを変えずに解決しようとしているのが、今回紹介するERC4337です。
2. 主な仕組み
まずは、下の図を見てください。今は詳細な理解は不要です。
見ると、「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) コードを準備する
まずは、git cloneを行います。
git clone https://github.com/stackup-wallet/erc-4337-examples.git
下のようになりました。
続いて、yarn installで依存関係を入れていきます。
yarn install
下のようになりました。
最後に、yarn run initで、configファイルを初期化します。
yarn run init
下のように、「config.json」ができました。
全体像で出てきた、「Bundler」や「EntryPoint」がいますね。
2) BundlerのURLを取得する
下の、「Starkup」のページに行きます。
下のように、「Create instance」を行います。
これで、BundlerのURLができます。
ただ、このままでは利用ができません。
使用するためには「Settings」からプランへの登録が必要です。
登録すると、利用ができるようになるので、ここから、URLをコピー。
下の、「bundlerURL」に貼り付けます。
ここで、全体像の復習ですが、UserOperationを送る先のBundlerのURLを設定していましたね。
追記
このまま処理を進めていくと、下のようなエラーに遭遇するようになりました。
確認すると、「EntryPoint」のコントラクトアドレスが変更されたようです。
https://github.com/stackup-wallet/erc-4337-examples
そのため、「config.json」の「entryPoint」も変更を行ってください。
Default value is set to 0x78d4f01f56b982a3B03C4E127A5D3aFa8EBee686.
3) 「ウォレット」アドレスを取得する
では、Userとなる、「ウォレット」アドレスを取得していきます。
この段階では、まだコントラクトアドレスではありません。
こちらを実行します。
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)で見てみると、、、あれ?なんか違うアドレスにガスが返還されていますね。
ここの部分、なぜこうなっているのか(正しい処理なのか)わからなかったので、ここは分かり次第更新していきたいと思います。
7) transferを実行する(ウォレットがすでにできている状態)
では、最後にもう一度新しく、0.2Maricの送付の処理を行ってみましょう。
ここで、前回と異なるのは、「initCode」です。
こちらは、すでに「ウォレットコントラクト」が作成されているため、中身は特にないようですね。
処理はこのように実施されました。
今回は以上です。
かなり長かったですが、最後までお読みいただき、ありがとうございました。
Discussion