## Abstract Account abstraction introduces new core components to make managing crypto simple. It has potential, but it can be difficult for builders and users to use all its core components. Users should not take on the burden of understanding Account abstraction. Wallet providers should serve as the gateway into this new paradigm of smart account management. The transition from using EOAs to smart accounts must be seamless. The following document proposes a solution that simplifies interacting with ERC-4337 core components. This solution does not change ERC-4337 but rather sits between dapps and ERC-4337 infrastructure to manage interaction with ERC-4337 core components(Entrypoint, Paymasters, Smart Account). ## Motivation This proposal avoids any adjustments to ERC-4337. It seeks to achieve the following goals: - **Allow dapps to integrate account abstraction**: Allow dapps to support smart accounts as first-class citizens without distrusting existing EOA flows. - **Support any compliant ERC-4337 Bundler, Smart Account and Paymaster**: Allow for seamless integration and interaction between these components. - **Allow users to manage their smart account**: Users can elect paymasters, create smart accounts, and make deposits/withdrawals/stakes to an Entry Point contract. - **Web3 Permissionless**: Users do not require special permission, account sign-up, or KYC to use the software. ## Soultion Our solution is to use a MetaMask Snap to modify the functionality of MetaMask to support ERC-4337. Doing so will give builders the tools to modify dapps to support Account Abstraction. The Snap; `ERC-4337 Relayer` facilitates seamless interactions between dApps and the ERC-4337 infrastructure. How does the ERC-4337 Relayer work: 1. ERC-4337 Relayer will generate a private key using a deterministic 256-bit value specific to the Snap and the user's MetaMask account(i.e., snapId + MetaMask secret recovery phrase). 2. The private key is used to create the relayer Ethereum account. The relayer account is the owner of the user's ERC-4337 smart accounts and will sign/send user operations on behalf of the user. 3. ERC-4337 Relayer will prompt users to sign all user operations giving the relayer account permission to get the user Op to a Bundler. 5. ERC-4337 Relayer uses a default list of Bundlers, but users can update this list to use any Bundler they choose. 6. Once a user operation is successfully included in a Bundlers transaction, ERC-4337 Relayer notifies the user via a MetaMask notification. ![ERC-4337 Relayer Snap Architecture](https://hackmd.io/_uploads/Hk3C66WF3.jpg) ## Specification **Definitions** - **MetaMask** - A non-custodial wallet(aka self-custody wallet) - **MetaMask Snaps** - Snaps is an open-source system that allows anyone to safely extend the functionality of MetaMask, creating new web3 end-user experiences. - **Relayer account** - Ethereum account embedded inside the Snap. Is the owner of the user's ERC-4337 smart accounts and will sign/send user operations on behalf of the user. ERC-4337 Relayer uses MetaMask Snaps `JSON-RPC API` and `Snaps exports` to modify the functionality of MetaMask to support ERC-4337. ### Permissions ERC-4337 Relayer must request permission from the user to use MetaMask Snaps `JSON-RPC API` and `Snaps exports`. The snaps manifest file defines these permissions. Specify these permissions in the manifest file as follows: ```json { "initialPermissions": { "snap_dialog": {}, "endowment:rpc": { "dapps": true, "snaps": false }, "endowment:ethereum-provider": {}, "snap_getEntropy": {}, "endowment:network-access": {}, "snap_manageState": {}, "endowment:cronjob": { "jobs": [ { "expression": "* * * * *", "request": { "method": "your_method_name" } } ] } } } ``` ### JSON-RPC API The are three restricted JSON-RPC API methods used `snap_dialog`, `snap_getEntropy`, and `snap_manageState`. Including them in the snaps manifest file will give full access to these restricted JSON-RPC API methods. - **snap_dialog** - Displays a dialog in the MetaMask UI. There are three types of dialogs Alert, Confirmation, and Prompt. - **snap_getEntropy** - Gets a deterministic 256-bit entropy value, specific to the Snap and the user's account. Other snaps can't access this entropy, and the value changes if the user's secret recovery phrase changes. - **snap_manageState** - Allows the Snap to persist up to 100 MB of data to disk and retrieve it at will. The data is automatically encrypted using a snap-specific key and decrypted when retrieved. #### snap_getEntropy ERC-4337 Relayer facilitates the signing of user operations on behalf of the user using an embedded Ethereum account(relayer account). The relayer accounts private key is generated using the`snap_getEntropy` JSON-RPC API. This deterministic generated private key is never exposed to the user and depends on the user's MetaMask secret recovery phrase and the ERC-4337 Relayer snapId. If a user's secret recovery phrase or ERC-4337 Relayer snapId changes, the smart account will not be accessible. This limitation is discussed further in the [possible challenges](#Possible-challenges) section, leaving room for introducing a smart account recovery system. #### snap_dialog The `snap_dialog` confirmation type will be the primary UI element to prompt users to sign user operations. A user can choose to accept or reject the `snap_dialog` confirmation. Rejected confirmation will throw the error from ERC-4337 Relayer with a massage 'User rejected User Operation'. While accepted, confirmations will be signed off by the relayer account and sent to an ERC-4337 Bundler. :::danger ⚠️ The ERC-4337 Relayer facilitates the signing of user operations on behalf of the user. The private key for the account that owns a user's smart account is embedded inside ERC-4337 Relayer. Their safety is ERC-4337 Relayer's responsibility, so do not make users sign anything that will result in loss of funds. ::: Example confirmation asking the user to sign a userOp: ```typescript await snap.request({ method: 'snap_dialog', params: { type: 'confirmation', content: panel([ heading(`(https://mysite.com) - Do you want to send a User operation?`), text(`Target: <target_contract_address>`), text(`ChainId: <chainId>`), text(`Entry point contract: <address_of_entrypoint>`), text( `Smart contract account: <smart_account_sending_userOp>`, ), ]), }, }) ``` #### snap_manageState The `snap_manageState` method allows ERC-4337 Relayer to persist up to 100 MB of data to disk and retrieve it at will. This 100 MB of storage is used to maintain a list of Bundlers to relay userOps to and also allows ERC-4337 Relayer to keep track of the status(pending/confirmed) of all userOps relayed through the Snap. Each smart account managed by ERC-4337 Relayer will get a separate storage slot to track userOp status while the list of Bundlers state is shared across all smart accounts. Users will only need to configure the list of Bundlers once for all smart accounts, and each smart account userOp activity is tracked independently from another. It is also important to note that the proposed initial state data structure allows independent tracking of smart account userOp activity but does not account for the chainId of userOp. The initial data structure would need to be extended to support chainIds; more details on this limitation are discussed further in the [possible challenges](#Possible-challenges) section. Using `snap_manageState` to store state: ```typescript const state = { bundlerUrls: { '0x539': 'http://localhost:3000/rpc', // 1337 '0x1': '', // ethereum mainnet '0x5': '', // goerli '0x89': '', // polygon mainnet '0x13881': '', // polygon mumbai }, scAccounts: { '0': { userOpHashesConfirmed: [], userOpHashesPending: [], }, '1': { userOpHashesConfirmed: [], userOpHashesPending: [], }, }, }; await snap.request({ method: 'snap_manageState', params: { operation: 'update', newState: state }, }); ``` Using `snap_manageState` to request state: ```typescript let state = (await snap.request({ method: 'snap_manageState', params: { operation: 'get' }, })) as { bundlerUrls: { [chainId: string]: string }; scAccounts: { [scIndex: string]: { userOpHashesConfirmed: string[]; userOpHashesPending: string[]; }; }; } | null; ``` ### MetaMask Snaps exports Two Snaps exports are used, `onRpcRequest` and `onCronjob`. - **onRpcRequest** - Allows ERC-4337 Relayer to communicate with dapps and other snaps. - **onCronjob** - Allows ERC-4337 Relayer to run periodic actions for the user (cron jobs). #### onRpcRequest Whenever the ERC-4337 Relayer receives a JSON-RPC request, the `onRpcRequest` handler method is called. This handler method will handle interactions with ERC-4337 Bundlers, the Entrypoint contract, Smart Account contracts, and Paymasters contracts. ERC-4337 Relayer will warp all ERC-4337 `eth` and `debug` namespaces to relay JSON-RPC requests to Bundler. Providing a wrapper will allow dapps to easily send RCP requests to complaint Bundlers. Custom code is used to manage ERC-4337 Smart accounts. ERC-4337 Relayer manages an eth-infinitism ERC-4337 v0.6.0 `SimpleAccount`. The `onRpcRequest` handler that warps all ERC-4337 `eth` and `debug` namespaces: ```typescript import { OnRpcRequestHandler } from '@metamask/snaps-types'; import { ethers } from 'ethers'; export const onRpcRequest: OnRpcRequestHandler = async ({ origin, request, }) => { const bc = new ethers.providers.JsonRpcProvider( 'https://bundlerUrl.io', { name: 'Connected to ERC-4337 Bundler Node', chainId: 1, } ); switch (request.method) { case 'eth_chainId': return await bc.send(request.method, request.params); case 'eth_supportedEntryPoints': return await bc.send(request.method, request.params); case 'eth_sendUserOperation': return await bc.send(request.method, request.params); case 'eth_estimateUserOperationGas': return await bc.send(request.method, request.params); case 'eth_getUserOperationReceipt': return await bc.send(request.method, request.params); case 'eth_getUserOperationByHash': return await bc.send(request.method, request.params); case 'web3_clientVersion': return await bc.send(request.method, request.params); case 'debug_bundler_clearState': return await bc.send(request.method, request.params); case 'debug_bundler_dumpMempool': return await bc.send(request.method, request.params); case 'debug_bundler_sendBundleNow': return await bc.send(request.method, request.params); case 'debug_bundler_setBundlingMode': return await bc.send(request.method, request.params); case 'debug_bundler_setReputation': return await bc.send(request.method, request.params); case 'debug_bundler_dumpReputation': return await bc.send(request.method, request.params); default: throw new Error('Method not found.'); } }; ``` #### onCronjob A cronjob that runs every minute will make an RPC request a Bundlers `eth_getUserOperationReceipt` method to get the status of user operations made by ERC-4337 Relayer. ERC-4337 Relayer will use MetaMask snap internal state to keep a list of `pending` and `confirmed` userOpHashes. MetaMask `snap_dialog` will alert users with a pop-up notification for all confirmed user operations. Dapps can interact with the notification system to build dapp specific user operation activity UI. A Cronjob that runs every minute and alerts the user with a notification for any confirmed userOps: ```typescript import { OnCronjobHandler } from '@metamask/snaps-types'; export const onCronjob: OnCronjobHandler = async ({ request }) => { switch (request.method) { case 'checkUserOperationReceiptReady': return snap.request({ method: 'snap_dialog', params: { type: 'alert', content: panel([ heading('Transaction Confirmed'), ]), }, }); default: throw new Error('Method not found.'); } }; ``` ### SDK An SDK can reduce the learning curve for builders that want to integrate ERC-4337 Relayer into a dapp. The SDK will wrap Snaps [wallet_invokeSnap](https://docs.metamask.io/snaps/reference/rpc-api/#wallet_invokesnap) to send RPC requests without builders having to understand how MetaMask Snaps works under the hood. The SDK can also expose functions to handle the installation of ERC-4337 Relayer for users that do not have the Snap already installed in their MetaMask wallet. ## Possible challenges and limitations 1. **Limitation in ERC-4337 Relayer internal state**: The current implementation of `snap_manageState` does not support the inclusion of chainId in the state. This limitation may impact managing state-specific operations related to different blockchain networks. Finding a solution or alternative approach to incorporate chainId in the state management process would be necessary to overcome this limitation. 2. **Data storage limit**: The project has identified a MetaMask Snap `100MB data storage limit`. This limitation may impact the amount of data stored and managed within the ERC-4337 Relayer snap. Exploring strategies to optimize data storage, such as compression techniques or external storage solutions, could help overcome this limitation. 3. **Issue with embedded Relayer account**: The current implementation of using `snap_getEntropy` to create the Relayer account poses an issue if a user changes their seed phrase or if ERC-4337 Relayer increments its version. In such cases, the smart account managed by ERC-4337 Relayer becomes inaccessible. To address this, the ERC-4337 Relayer would require a recovery mechanism that enables ownership transfer/fund transfer in scenarios where users change their seed phrase or when ERC-4337 Relayer releases a software update. A recovery mechanism would ensure users retain access to funds in such situations. ## Outcome The project aims to integrate and adopt the ERC-4337 Relayer snap successfully. Success would entail builders downloading the ERC-4337 Relayer snap and actively interacting with dapps through it. In terms of scope, the project would involve developing and launching the first version of the Snap, which would serve as a ready-to-use tool for builders. This version should provide seamless integration with dapps and offer functionalities to support Account Abstraction within the Ethereum ecosystem. The project's completion state will be reached when the first version of the Snap is successfully launched and will involve thorough testing, ensuring stability, and an audit from a 3rd party. The impact of the project's success would be observed through increased adoption of the ERC-4337 Relayer snap by builders. This adoption would contribute to the growth and expansion of ERC-4337, making it easier for builders to integrate smart accounts into dapps. ## Implementation - [ERC-4337 Relayer Github Repo](https://github.com/transeptorlabs/erc-4337-relayer) ## Roadmap This roadmap provides a comprehensive view of the project's timeline. - [ ] **ERC-4337 Relayer Snap** - [x] ERC-4337 bundler wrapper Snap rpc methods - [x] eth_chainId - [x] eth_supportedEntryPoints - [x] eth_sendUserOperation - [x] eth_estimateUserOperationGas - [x] eth_getUserOperationReceipt - [x] eth_getUserOperationByHash - [x] eth_chainId - [x] web3_clientVersion - [x] debug_bundler_clearState - [x] debug_bundler_dumpMempool - [x] debug_bundler_sendBundleNow - [x] debug_bundler_setBundlingMode - [x] debug_bundler_setReputation - [x] debug_bundler_dumpReputation - [x] Smart account management Snap rpc method - [x] sc_account - [x] get_confirmed_userOperationReceipts - [x] add_bundler_url - [x] get_bundler_urls - [x] clear_activity_data - [ ] 80% Unit test coverage - [ ] 3rd party audit - [ ] Deploy v0.1.0 to NPM - [ ] Support ERC-4337 Paymaster - allow users to select a Paymaster to sponsor userOp gas fees. - [x] Allow user to create an ERC-4337 Smart account - [ ] ERC-4337 Relayer integration builder docs - [ ] **ERC-4337 Relayer Dapp** - [x] Feature to install ERC-4337 Relayer Snap - [ ] Deploy site using Github pages - [x] Feature to allow the user to send a deposit to the entrypoint for a smart account - [x] Show user operation activity for a smart account - [ ] Feature to build a user operation from any given smart contracts ABI - [ ] Add support for block explore - [x] Deposit to entry point - [x] Withdraw from the entry point - [ ] Chainlink CCIP integration - Cross chain token transfers with smart accounts POC - https://docs.chain.link/ccip - [ ] **ERC-4337 Relayer SDK** - [ ] envoke snap rpc method - [ ] Check if Snap installed - [ ] get snap info(version, name, is installed) - [ ] install Snap - [ ] React UI components - [ ] connect smart account button ## Collaborators Contributors: [Transeptor Labs](https://github.com/transeptorlabs) ## Resources - https://docs.metamask.io/snaps/ - https://github.com/transeptorlabs/erc-4337-relayer