Okodukai Wallet (React.js + Hardhat + TheGraph)
No. | コントラクト名 | アドレス | ネットワーク |
---|---|---|---|
1 | FactoryManager | 0xdd0412fDdD27bd54115E63E62f04318C4B4154F4 | Mumbai |
2 | EntryPoint | 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 | Mumbai |
3 | DepositPaymaster | 0x93fdd51462FB20fB631F8CA38c3DeB87583311Ea | Mumbai |
- Sample Query (生成したFacotryコントラクトの情報を一括で取得するクエリ)
query MyQuery {
factoryCreateds(orderBy: id, orderDirection: desc) {
factoryId
factoryAddress
}
}
No. | トランザクションハッシュ | 概要 |
---|---|---|
1 | 0xe62537028fc2be51a7a0121926bf7ed024531577ce03f085135618fc1613ba26 | FactoryManagerコントラクトのデプロイ |
2 | 0xd16efa3e05c61dd0186434594f6c9004b7cc086ccc2cf6e12c3122fc985935e3 | FactoryManagerコントラクトからSimpleAccountFacotoryコントラクトを生成したTx |
3 | 0x0bf4ad5dd446d9b64e0e981506688b6d2159d1d1ad358317dad6380247f77c31 | FactoryManagerコントラクト経由でEntryPointコントラクトに対してaddStakeしたTx |
4 | 0x6b333e0b0587d3bfc7432f1cac0b163238cc9a0de27630d5fd7d263734c1b010 | SimpleAccountコントラクトからネイティブトークンを送金したTx |
5 | 0xaba33331fbd001e9a6f976c21c2abaf5f44ca20e6c6bc06a7a35b3cc183f596f | SimpleAccountコントラクトからERC20トークンを送金したTx |
Web3のマスアダプションのため。
お小遣いをあげる感覚で、ownerからユーザーに暗号資産を渡してあげられる + 管理ができる アプリをイメージしていました。
このようにすることで子供でも暗号資産を使えるようにするイメージです。
- 全体像
- コントラクトのコンセプト
AccountFactory
というコントラクトを追加して、ownerが複数のContractWallet
を管理できるようにする構造を考えていました。ownerになった人がContractWallet
に入金していくイメージです。
さらに、Factory生成時のタイミングでは Eventを発行させてThe Graph
を使ってインデックス化させ検索・管理しやすいアプリにしたいと考えていました。
Name | Github | |
---|---|---|
mashharuki | Github | |
hakua | Github | |
mameta | Github |
-
独自実装した
FactoryContract
とAccountContract
がちゃんと機能するようにバンドラーとエントリーポイントコントラクト・Paymasterコントラクトの仕組みをさらに調べること。 -
バンドラーとEntryPointコントラクトまでも自分たちで用意するのはとても大変(しかも独自実装が混ざるとさらに大変)だったので今回は除外したが、今後ハッカソンでこの辺りの機能拡張などが簡単にできる仕組みを考えると審査員受けしそうだと思った。
-
今回学んだことを今後開発するプロダクトやハッカソンのアイディアに流用することが当面の目標である。
-
アプリのエンドユーザー側は、Metamaskインストールしていない状態になるので、セキュリティの担保のためには結局KYCが重要になる。なので、GoogleアカウントでもログインできるようなSSOの仕組みを導入した認証機能などを追加してあげる必要がある。
- UserOperation - ユーザーの代わりに送信されるトランザクションを記述する構造体です。混乱を避けるため、"transaction "という名前は付けられていない。 トランザクションと同様に、"sender", "to", "calldata", "maxFeePerGas", "maxPriorityFee", "signature", "nonce" を含む。 トランザクションとは異なり、以下のようないくつかのフィールドを含んでいます。 また、"nonce "と "signature "フィールドの使用方法は、プロトコルで定義されているわけではなく、各アカウントの実装によって定義されています。
- Sender - ユーザーオペレーションを送信するアカウントコントラクト。
- EntryPoint - UserOperationのバンドルを実行するためのシングルトンコントラクトです。バンドラー/クライアントは、サポートされるエントリーポイントをホワイトリストに登録します。
- Bundler - 複数のUserOperationをバンドルし、EntryPoint.handleOps()トランザクションを作成するノード(ブロックビルダー)です。ネットワーク上のすべてのブロックビルダーがバンドラーであることを要求されるわけではないことに注意してください
- アグリゲーター - アグリゲートされた署名を検証するために、アカウントによって信頼されるヘルパー契約です。バンドラー/クライアントは、サポートされるアグリゲーターをホワイトリスト化します。
アカウントアブストラクションを実現するためのコンポーネント
- EntryPoint contract (エントリーポイントコントラクト)
- Paymaster contract (コントラクト)
- UserOperation (ユーザーが実行したいトランザクション本体のデータ)
- Bundler (トランザクションを束ねてブロックチェーンに送信するためのAPIサーバー)
- Miner (マイナー)
- client library (アカウントアブストラクションの機能を呼び出すためのクライアントライブラリ)
エントリーポイントのロジックを拡張し、他のユーザーのトランザクションをスポンサーすることができるペイマスターをサポートします。この機能は、アプリケーション開発者がユーザーの料金を補助したり、ユーザーがERC-20トークンで料金を支払うことを可能にしたり、その他多くのユースケースに使用することができます。
Paymasterは、dAppの利用者がトランザクション手数料を支払わずにdAppを使用できるようにするための機能です。Paymasterは、利用者の代わりにトランザクション手数料を支払うため、dAppの利用者はトランザクションを送信するときにETHを持っている必要がありません。
Paymasterは、dAppの所有者が管理するスマートコントラクトであり、dAppの利用者がPaymasterに対して任意の量のETHを送信し、Paymasterはトランザクション手数料を支払い、dAppに転送します。
ERC-2771は、Paymasterを実装するために必要なメソッドやイベントを定義しています。Paymasterを実装するには、ERC-2771で定義されたスマートコントラクトを作成し、必要なメソッドを実装する必要があります。
Paymasterの利点は、利用者がETHを持っていなくてもdAppを利用できるようになることです。これにより、ユーザーの利用率を向上させることができます。また、PaymasterはdAppの所有者が管理するため、手数料を自由に設定することができるため、dAppの収益性を向上させることもできます。
toEthSignedMessageHashは、Ethereumデジタル署名標準に従って、任意のメッセージに対して署名する前にハッシュ値を生成するために使用されるメソッドの1つです。
このメソッドは、web3.jsやSolidityなどのEthereum開発ツールキットで利用可能であり、以下のようなステップで使用することができます。
- メッセージをUTF-8形式でエンコードします。
- Ethereumの署名形式に必要なプレフィックス文字列 ("\x19Ethereum Signed Message:\n" + メッセージのバイト数)を追加します。
- 2で生成された文字列をハッシュ化します。
- ハッシュ値を16進数文字列に変換します。
Metamask Snapは、Metamaskブラウザ拡張機能に追加できる、分散型アプリケーション(dApps)のための拡張機能です。
Snapは、MetamaskのAPIを使用して、dAppsとのインタラクションを可能にすることができます。Snapは、dAppsがMetamaskのUIやAPIを直接利用することなく、dAppsがMetamaskと連携することを可能にすることができます。これにより、dAppsは、Metamask Snap APIを介してMetamaskのウォレット機能を利用することができます。
Metamask Snapを使用することで、ユーザーはMetamaskをアンロックすることなく、dAppsにアクセスすることができます。dAppsは、Metamask Snapを使用して、ユーザーにウォレットアドレスの確認やトランザクションの署名などの機能を提供することができます。
Metamask Snapは、Snap StoreというMetamaskのSnap拡張機能のマーケットプレイスで利用可能です。Snap Storeには、多数のSnapが提供されており、ユーザーは必要に応じてSnapを追加することができます。Snap Storeには、dAppの開発者が作成したSnapが含まれており、ユーザーはSnap Storeを通じてdAppsにアクセスすることができます。
Metamask Snapは、分散型アプリケーションとのインタラクションを簡素化し、ユーザーにとってよりシームレスなdAppエクスペリエンスを提供することを目的としています。 → AA系のアプリだとMetamaskはインストールしていない前提なのでそうすること。
No. | コントラクト名 | アドレス | ネットワーク |
---|---|---|---|
1 | SimpleAccountFactory | 0xA0B912d2797602863ce04F370b36330d80e76832 | Mumbai |
2 | EntryPoint | 0x607cAAF3fF8bB0469F1e9b1e3214008C0B1D05C6 | Mumbai |
3 | SimpleAccount | 生成したコントラクトウォレット | Mumbai |
- インストール
cd 4337-sample && npm i
- コンパイル
npm run compile
- テスト
npm run test
- EntryPointコントラクトのデプロイ & Verify
npm run entryPoint:deploy:mumbai
package.json
ファイルにデプロイしたコントラクトアドレスを埋め込むこと!!
npm run entryPoint:verify:mumbai
- SimpleAccountFactoryコントラクトのデプロイ & Verify
npm run simpleAccountFactory:deploy:mumbai
package.json
ファイルにデプロイしたコントラクトアドレスを埋め込むこと!!
npm run simpleAccountFactory:verify:mumbai
yarn
yarn run init
- コントラクトウォレット生成
yarn run simpleAccount address
- 実行結果
SimpleAccount address: 0xAcF13ddE0328fC1D971b14b46601f72EfCde988a
✨ Done in 9.51s.
- ネイティブトークンの送金
yarn run simpleAccount transfer --to 0x51908F598A5e0d8F1A3bAbFa6DF76F9704daD072 --amount 0.05
- 実行結果
Signed UserOperation: {
sender: '0xAcF13ddE0328fC1D971b14b46601f72EfCde988a',
nonce: '0x0',
initCode: '0x9406cc6185a346906296840746125a0e449764545fbfb9cf000000000000000000000000e6d171e50dc760f74e1e5c78f3f4e1e2df72cb5e0000000000000000000000000000000000000000000000000000000000000000',
callData: '0xb61d27f600000000000000000000000051908f598a5e0d8f1a3babfa6df76f9704dad07200000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: '0x814c',
verificationGasLimit: '0x583f4',
preVerificationGas: '0xaf9c',
maxFeePerGas: '0x670cebc0',
maxPriorityFeePerGas: '0x670ceba0',
paymasterAndData: '0x',
signature: '0xf41970f318f4c9425ac22689fcf8d361fff35cc8134cbb69a2b65de733a6657131982677a02d9f89a6dce63bf272be036e33b78d02bfb8404a878b8ebe6d5f881b'
}
UserOpHash: 0xed45d1eb9ecd6457172aeed91e4cd6b13ef907eedd7a27661cabbf1d1a603634
Waiting for transaction...
Transaction hash: 0xcc122aca392ae5096f9404d868f4e4336f2f81f8933bdead8e1ca25909a9c09e
✨ Done in 25.13s.
- ERC20のトークン(LINKトークン)を送信する
yarn run simpleAccount erc20Transfer --token 0x326C977E6efc84E512bB9C30f76E30c160eD06FB --to 0x51908F598A5e0d8F1A3bAbFa6DF76F9704daD072 --amount 0.1
- 実行結果
Transferring 0.1 LINK...
Signed UserOperation: {
sender: '0xAcF13ddE0328fC1D971b14b46601f72EfCde988a',
nonce: '0x1',
initCode: '0x',
callData: '0xb61d27f6000000000000000000000000326c977e6efc84e512bb9c30f76e30c160ed06fb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044a9059cbb00000000000000000000000051908f598a5e0d8f1a3babfa6df76f9704dad072000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000',
callGasLimit: '0x9922',
verificationGasLimit: '0xed10',
preVerificationGas: '0xaeb8',
maxFeePerGas: '0x6507a5de',
maxPriorityFeePerGas: '0x6507a5c0',
paymasterAndData: '0x',
signature: '0xb0a132bd539cfadcc4e05b2f6753f88ad6d53fa0a7e2379d642cc5295b98e2ee107d7a45bf76766cd7f1ca9dc98a8c34f3ae4182a2808e36617d0ef85456aedb1c'
}
UserOpHash: 0x1a4b3f80da3e0c6fd52dd4c1657e14f837eaf4a32f1bf13a98cf7365be7b2144
Waiting for transaction...
Transaction hash: 0x93117543b9382f20f58c27811887dfebac7833080f89132682ad509f0e220cdb
✨ Done in 21.65s.
- ERC20を承認するコマンド
yarn run simpleAccount erc20Approve --token 0x326C977E6efc84E512bB9C30f76E30c160eD06FB --spender 0x51908F598A5e0d8F1A3bAbFa6DF76F9704daD072 --amount 0.5
- 実行結果
Approving 0.5 LINK...
Signed UserOperation: {
sender: '0xAcF13ddE0328fC1D971b14b46601f72EfCde988a',
nonce: '0x2',
initCode: '0x',
callData: '0xb61d27f6000000000000000000000000326c977e6efc84e512bb9c30f76e30c160ed06fb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044095ea7b300000000000000000000000051908f598a5e0d8f1a3babfa6df76f9704dad07200000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000000000',
callGasLimit: '0xc623',
verificationGasLimit: '0xed10',
preVerificationGas: '0xaeb8',
maxFeePerGas: '0x6507a5e2',
maxPriorityFeePerGas: '0x6507a5c0',
paymasterAndData: '0x',
signature: '0xdeeef33f860c1224d0cbc9e72f9c9a942c4da9661b80ae9f9b5268790e51a0382511f8c8e2543bd02a04eaf4ac2846d2ebeb0999607782be4e36ab0f2e2c539d1b'
}
UserOpHash: 0xa9c59076dc2aed6216a8eafaa335a40898a5b470a82b2ff873b42834d57e29d6
Waiting for transaction...
Transaction hash: 0xc96ac903a0130cfbd2fdc0a9dd9553cb040b909d981a9465dc2120d1ab03d6a2
✨ Done in 21.18s.
- 一気に複数のERC20トークンした場合
yarn run simpleAccount batchErc20Transfer --token 0x326C977E6efc84E512bB9C30f76E30c160eD06FB --to 0x51908F598A5e0d8F1A3bAbFa6DF76F9704daD072,0x1295BDc0C102EB105dC0198fdC193588fe66A1e4 --amount 0.01
- 実行結果
基本的にPaymasterで使用したいトークンの設定を追加で行い、--withPaymaster
をつけることで実行できる。
- ネイティブトークンの送金
yarn run simpleAccount transfer --to 0x51908F598A5e0d8F1A3bAbFa6DF76F9704daD072 --amount 0.05 --withPaymaster
- 独自の実装を混ぜ込むのが難しい。(Solidityレベルでは可能だが、フロント、APIを合わせると話は別。ちょっと変えただけでも上手く動かない。)
- Bundlerの開発が大変(上述の独自実装を組み込むことに加えてそれを考慮した設計にしないといけない。)
- userOpのデータを作るのは、
userOp.js
などのSDKを使わないとめちゃくちゃめんどくさい。 - 上記点を上手く組み合わせるだけでもかなり大変。
- まず、QuickStartをやる。
- コントラクトのソースとバンドラーのAPIの内容を理解する。
- 標準仕様で、
userOp.js
を使ってReact.js
などで開発したフロントエンドリクエストを投げられる様にすること。 - まずは上記でフロントから動かすこと。(普通にライブラリを使ってリクエストを投げる。)
- 独自実装を組み込んだ
FactoryContract
及びAccountContract
のデプロイ方法と適用方法を調べること。
現在はStackupが指定したトークンのみしか使えない(USDC、テストネットだと特定のトークンStackup 6 Decimal Test Token)
- EIP-4337
- FireWallet - Github
- Account-Abstruction
- NPM AccountAbstruction
- jiffyScan
- 【GitHub】jiffyScan
- 【StackUp Docs】AA introduction
- AAsnap
- stackup-bundler Sample source
- 【npm】Userop.js
- MetaMask/snaps-monorepo
- extend-the-functionality-of-metamask
- Template Snap monorepo
- Create a gas estimation snap
- Hardhatの使い方メモ(4) テスト - イベントのテスト方法
- ERC4337に関するメモ
- 発表資料
- tailwindcomponents