AmineElmerzouki
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Publish Note

      Everyone on the web can find and read all notes of this public team.
      Once published, notes can be searched and viewed by anyone online.
      See published notes
      Please check the box to agree to the Community Guidelines.
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Publish Note

Everyone on the web can find and read all notes of this public team.
Once published, notes can be searched and viewed by anyone online.
See published notes
Please check the box to agree to the Community Guidelines.
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
![image](https://hackmd.io/_uploads/ry7p3mWSp.png) # Harnessing ERC-4337: A Step-by-Step Guide to Implementing Ethereum's Account Revolution ## Introduction Welcome to the second part of our exploration into Ethereum's groundbreaking ERC-4337 protocol. Having explored the theoretical underpinnings in our previous guide, "ERC-4337: Revolutionizing Ethereum's Account Management " (add the first article link here)", we now turn our attention to the actionable side of this innovation. In this guide, we'll walk you through the intricate process of creating and launching an ERC-4337-compliant smart contract, with a focus on using the Stackup platform. This article provide you with the practical know-how to effectively leverage ERC-4337's capabilities, paving the way for enhanced account management on the Ethereum network. ## The Essential Components of ERC-4337 1. **UserOperations**: Consider these as your Ethereum account's checklist, encompassing tasks like money transfers, smart contract interactions, or a mix of actions. Unlike the current Ethereum system where you execute each task separately, ERC-4337's UserOperations lets you group various actions into one operation. You sign this combined operation, and the Ethereum network handles it. UserOperations maintain a structure akin to present Ethereum transactions but incorporate additional logic specific to ERC-4337. 2. **Bundlers**: After you've prepared your UserOperation, Bundlers are the ones who insert it into the Ethereum network. They act as intermediaries, gathering multiple UserOperations, bundling them, and then submitting them to the network. These can be validators or MEV searchers. 3. **EntryPoint**: This smart contract functions as the Ethereum network's gatekeeper. When Bundlers submit UserOperations, the EntryPoint unpacks and executes them. If it finds an operation that doesn't work, it can reverse the actions of that operation, maintaining transaction integrity and reliability. 4. **Contract Account**: Think of this as your automated helper in the Ethereum network. Different from standard accounts that require manual action initiation, Contract Accounts can autonomously execute actions as per the instructions they receive, like those from a UserOperation. They can interact with other contracts, manage assets, and make decisions based on their programmed logic, thus automating and simplifying complex Ethereum transactions. 5. **Paymaster**: An optional component that can cover transaction fees on behalf of your transaction. It pledges to repay the Bundler for gas costs. The conditions for this reimbursement are outlined in the smart contract. 6. **Aggregators**: These optional smart contracts work with the Contract Account to collectively validate signatures from multiple UserOperations. In essence, ERC-4337 introduces new elements into Ethereum's architecture, each playing a crucial role in the transaction process. ## Requirements: - Yarn software installed on your system - Access to Stackup API Key: https://app.stackup.sh/ - Stackup repository setup https://github.com/stackup-wallet/erc-4337-examples ![image](https://hackmd.io/_uploads/H1WeTmZHT.png) - VScode Or Any code editor. - An operational terminal window for executing commands ## SimpleAccount.sol: A Basic ERC-4337 Contract Illustration Ethereum's core team has developed a straightforward and minimal example of an ERC-4337 compliant contract, named SimpleAccount.sol. https://github.com/eth-infinitism/account-abstraction/blob/develop/contracts/samples/SimpleAccount.sol We will spend some time examining the code provided below. While it's not necessary to replicate this code in a file, reviewing it will help us grasp its functionalities better. ``` solidity // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; /* solhint-disable avoid-low-level-calls */ /* solhint-disable no-inline-assembly */ /* solhint-disable reason-string */ import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; import "../core/BaseAccount.sol"; import "./callback/TokenCallbackHandler.sol"; /** * minimal account. * this is sample minimal account. * has execute, eth handling methods * has a single signer that can send requests through the entryPoint. */ contract SimpleAccount is BaseAccount, TokenCallbackHandler, UUPSUpgradeable, Initializable { using ECDSA for bytes32; address public owner; IEntryPoint private immutable _entryPoint; event SimpleAccountInitialized(IEntryPoint indexed entryPoint, address indexed owner); modifier onlyOwner() { _onlyOwner(); _; } /// @inheritdoc BaseAccount function entryPoint() public view virtual override returns (IEntryPoint) { return _entryPoint; } // solhint-disable-next-line no-empty-blocks receive() external payable {} constructor(IEntryPoint anEntryPoint) { _entryPoint = anEntryPoint; _disableInitializers(); } function _onlyOwner() internal view { //directly from EOA owner, or through the account itself (which gets redirected through execute()) require(msg.sender == owner || msg.sender == address(this), "only owner"); } /** * execute a transaction (called directly from owner, or by entryPoint) */ function execute(address dest, uint256 value, bytes calldata func) external { _requireFromEntryPointOrOwner(); _call(dest, value, func); } /** * execute a sequence of transactions * @dev to reduce gas consumption for trivial case (no value), use a zero-length array to mean zero value */ function executeBatch(address[] calldata dest, uint256[] calldata value, bytes[] calldata func) external { _requireFromEntryPointOrOwner(); require(dest.length == func.length && (value.length == 0 || value.length == func.length), "wrong array lengths"); if (value.length == 0) { for (uint256 i = 0; i < dest.length; i++) { _call(dest[i], 0, func[i]); } } else { for (uint256 i = 0; i < dest.length; i++) { _call(dest[i], value[i], func[i]); } } } /** * @dev The _entryPoint member is immutable, to reduce gas consumption. To upgrade EntryPoint, * a new implementation of SimpleAccount must be deployed with the new EntryPoint address, then upgrading * the implementation by calling `upgradeTo()` */ function initialize(address anOwner) public virtual initializer { _initialize(anOwner); } function _initialize(address anOwner) internal virtual { owner = anOwner; emit SimpleAccountInitialized(_entryPoint, owner); } // Require the function call went through EntryPoint or owner function _requireFromEntryPointOrOwner() internal view { require(msg.sender == address(entryPoint()) || msg.sender == owner, "account: not Owner or EntryPoint"); } /// implement template method of BaseAccount function _validateSignature(UserOperation calldata userOp, bytes32 userOpHash) internal override virtual returns (uint256 validationData) { bytes32 hash = userOpHash.toEthSignedMessageHash(); if (owner != hash.recover(userOp.signature)) return SIG_VALIDATION_FAILED; return 0; } function _call(address target, uint256 value, bytes memory data) internal { (bool success, bytes memory result) = target.call{value : value}(data); if (!success) { assembly { revert(add(result, 32), mload(result)) } } } /** * check current account deposit in the entryPoint */ function getDeposit() public view returns (uint256) { return entryPoint().balanceOf(address(this)); } /** * deposit more funds for this account in the entryPoint */ function addDeposit() public payable { entryPoint().depositTo{value : msg.value}(address(this)); } /** * withdraw value from the account's deposit * @param withdrawAddress target to send to * @param amount to withdraw */ function withdrawDepositTo(address payable withdrawAddress, uint256 amount) public onlyOwner { entryPoint().withdrawTo(withdrawAddress, amount); } function _authorizeUpgrade(address newImplementation) internal view override { (newImplementation); _onlyOwner(); } } ``` ### Reviewing the Code: Insights into the SimpleAccount Contract The `SimpleAccount` contract presented is configured to be managed by an external owner address. It's tailored for interaction with an `EntryPoint` contract, adhering to the ERC-4337 guidelines. This setup enables the owner to initiate transactions without personally incurring gas fees. The contract employs OpenZeppelin's libraries for enhanced features, such as cryptographic signature validation (`ECDSA`) and support for upgradeable contract models (`UUPSUpgradeable` and `Initializable`). Additionally, it incorporates `BaseAccount` and a callback handler. `BaseAccount` is pivotal, maintaining the nonce of the smart contract, verifying UserOperation payload, facilitating interactions with `EntryPoint`, managing execution payments (via `payPrefund()`), and providing a framework for tailored implementations of functions like `_validateSignature()`, `_validateNonce()`, and `_payPrefund()`. A key state variable, `owner`, retains the account's owner address. `_entryPoint` is an immutable linkage to an external contract, designated as the `EntryPoint`. Two principal functions, `execute` and `executeBatch`, are integral to this contract. They permit the owner or the relay system's `EntryPoint` to dispatch individual or grouped transactions. These functions include safeguards, verifying that the initiator is either the `EntryPoint` or the owner, prior to executing any processes. Upgradeability is a notable feature of this contract, allowing for the transition to a new owner. However, any modifications to the `EntryPoint` (like changes to `_entryPoint`) necessitate deploying a new smart contract account. For practical application, we'll utilize Stackup's SDK, which simplifies deploying an ERC-4337 compatible contract. This enables us to efficiently execute operations such as approving ERC-20 tokens and managing ETH and token transfers. ## Creating ERC-4337 Smart Contracts Using Stackup In this segment, we focus on constructing an ERC-4337 compliant contract using Stackup (https://docs.stackup.sh/) This particular contract serves as an excellent foundational template for developers venturing into Account Abstraction with Stackup. ### Setting Up for Developers 1. Begin by opening your terminal window and executing the following commands: Setting up a local copy of an example ERC-4337 project from Stackup. Here's a breakdown of each command: `git clone https://github.com/stackup-wallet/erc-4337-examples.git`: - This command uses Git to clone repository . The repository contains example code for ERC-4337 projects developed by Stackup. `cd erc-4337-examples`: - After cloning the repository, this command changes the current directory in your terminal to the newly created 'erc-4337-examples' directory. This directory contains the cloned project files. `yarn install`: - This command uses Yarn, a package manager for JavaScript, to install all the dependencies required for the ERC-4337 project. These dependencies are specified in a file named 'package.json' in the project directory. Running `yarn install` ensures that you have all the necessary packages and their correct versions to run and work on the project. 2. Moving forward, we'll proceed with setting up our ERC-4337 contract. This is achieved by utilizing the initialization command provided by Yarn: `yarn run init` - This command is a crucial step in the setup process. It initializes the project configuration for your ERC-4337 contract. Essentially, when you run `yarn run init`, it executes a predefined script in the project's `package.json` file. This script is tailored to set up various aspects of the ERC-4337 environment, such as default parameters, network settings, and other necessary configurations that are required for the contract to function correctly within the Ethereum framework. It ensures that your development environment is correctly aligned with the requirements of the ERC-4337 standard, facilitating a smoother development process as you start building and customizing your smart contract. Upon running the initialization command, a `config.json` file is generated. This file contains important configuration values for your ERC-4337 contract, such as: - `rpcUrl`: This field specifies the Remote Procedure Call (RPC) URL, which is essential for supporting the methods invoked by the ERC-4337 contract. To populate this field correctly, you will require an API Key from Stackup. - `signingKey`: This key is vital for creating signatures for UserOperations. It plays a dual role by also being used by the contract account for the validation of transactions. - `paymaster.rpcUrl`: This URL is specifically for the Paymaster component of the ERC-4337 contract. It is crucial for the Paymaster to interact with the network and perform its functions. - `paymaster.context`: This is a flexible field that varies depending on the specific Paymaster you are working with. It's designed to hold any necessary contextual information required for the Paymaster's operation within the contract. Each of these fields plays a specific role in configuring the ERC-4337 contract, ensuring it operates correctly within the Ethereum network and interacts effectively with other components like UserOperations and Paymasters. ### Generate an API Key for Stackup 3. Once the `config.json` file is in place, it's time to input specific details like the RPC URL. Start by visiting [https://app.stackup.sh/sign-in](https://app.stackup.sh/sign-in) and sign up for an account. After registration, you will be asked to choose a blockchain network. For this tutorial, opt for the Ethereum Sepolia chain. Click 'Next' to proceed. Following that, access your newly created bundler instance and select the 'API Key' option to obtain your key. Copy this API Key and return to your `config.json` file, where you'll insert this key into the relevant rpcUrl fields. The completed `config.json` file should resemble the following structure: ``` json { "rpcUrl": "https://api.stackup.sh/v1/node/b58f0311040b1c851c6019012deb3da19687cc4049986b86830ed4a2306fad16", "signingKey": "0xc3e722960afadbacf08e3862b96b8ec599b24d9f749df001aacbb25d197717bc", "paymaster": { "rpcUrl": "https://api.stackup.sh/v1/paymaster/8f92183c7b11d46e086c9b3f93e909195dcc6790ae81b4254408431e85b84d74", "context": {} } } ``` ### Create Our Smart Contract Address 4. Now that our configuration is established, it's time to generate a smart contract account, as specified in our configuration file. To do this, execute the following command in your terminal: `yarn run simpleAccount address` - This command will produce an address, which is the identifier for the smart contract account you're about to create. It's important to note that at this stage, the smart contract account has not been deployed to the Ethereum network. However, generating this address is a crucial step, as it allows us to know the address of our smart contract account in advance. This preliminary step is essential for organizing and preparing for the subsequent deployment process of the smart contract. After running the command, your terminal should display an output similar to the following: ``` $ ts-node scripts/simpleAccount/index.ts address SimpleAccount address: 0x37662167966c7d2566b28ed8d4bea9d1d09d3ffd Done in 1.75s. ``` This output indicates that the command to generate the address for your SimpleAccount has been successfully executed. The address displayed (`0x37662167966c7d2566b28ed8d4bea9d1d09d3ffd`) is a randomly generated Ethereum address, which serves as a placeholder for the actual address that will be assigned to your smart contract account. The completion time of the process is also indicated, demonstrating the efficiency and quickness of the operation. - In the upcoming section, we will focus on adding funds to the SimpleAccount address that was just created. It's important to remember, however, that the contract itself has not yet been deployed. ### Add Funds to the Smart Contract Account Using a Faucet Let's proceed to add funds to the address of our smart contract account (for instance, SimpleAccount) that we generated previously. To do this, you might utilize the QuickNode Multi-Chain Faucet.(https://faucet.quicknode.com/drip) This allows you to obtain some testnet ETH, which you can initially send to your personal wallet. From there, you can transfer it to the SimpleAccount address. It's important to be aware that the Faucet necessitates having a mainnet balance in the address that is to be funded. Alternatively, if you already possess test ETH in a different wallet, you can directly transfer it to your smart contract (SimpleAccount) address, bypassing the need to use the Faucet initially. ![image](https://hackmd.io/_uploads/ryU3O7Wra.png) ### Start a Transaction from SimpleAccount to a Different Address Now that our smart contract account, such as SimpleAccount, is sufficiently funded, it's time to perform a transfer from this account. We suggest ensuring that you have a minimum of 0.01 ETH available for testing an ETH transfer, keeping in mind the additional gas fees. To initiate this, input the following command into your terminal. Make sure to substitute the placeholder terms like `{address}` and `{eth}` with the actual values you intend to use. ```bash yarn run simpleAccount transfer --to {address} --amount {eth} ``` The command provided is used to initiate a transfer of Ethereum (ETH) from your smart contract account (in this case, SimpleAccount) to another Ethereum address. Here's a breakdown of its components: - `yarn run simpleAccount transfer`: This part of the command tells Yarn to execute the `transfer` function within the `simpleAccount` script. The `simpleAccount` script is part of your project and is designed to interact with the SimpleAccount smart contract. - `--to {address}`: This flag specifies the recipient's Ethereum address for the transfer. You need to replace `{address}` with the actual Ethereum address of the recipient to whom you want to send ETH. - `--amount {eth}`: Here, `{eth}` should be replaced with the amount of Ethereum you wish to transfer. This value is in ETH (Ethereum's native cryptocurrency). For instance, if you want to transfer 0.02 ETH, you would replace `{eth}` with `0.02`. It's important to ensure that the SimpleAccount has enough ETH to cover both the amount you intend to transfer and the gas fees associated with the transaction. This command will initiate a transaction on the Ethereum network, transferring the specified amount of ETH from your SimpleAccount to the provided recipient address. The process involves: - Accepting the destination address (`t`) and the amount of ether (`amt`) as inputs in the primary function. - Performing a verification for any middleware, which is particularly relevant if a paymaster is involved. - Initializing a SimpleAccount contract utilizing the settings specified in the `config.json` file. - Parsing and processing the provided address and amount values. - Signing the transaction and invoking the `execute` function with the aforementioned values. - Generating and returning both the UserOperation hash and the transaction hash as outputs. - ### The Transaction Process of a Smart Contract Account In a general overview, when a transfer is initiated from a smart contract account, a complex process unfolds in the background. It begins with the creation of a UserOperation object, which outlines the desired transaction. This object is then sent to a group of Bundlers, entities responsible for managing these operations. The Bundlers, after receiving the UserOperation, create a transaction that interacts with a specific contract, commonly known as the EntryPoint contract. This contract plays a critical role in the execution of bundled UserOperations. It's at this EntryPoint where the transaction is processed, executing the transfer as per the instructions in the UserOperation. This process involves various transfers, contract calls, and the management of gas fees, all orchestrated to facilitate the smooth execution of the transfer from the smart contract account to the specified destination. ## Conclusion You've successfully set up a smart contract account utilizing ERC-4337 and Stackup, and have also accomplished a fund transfer from this account to a different address. While this procedure might appear straightforward and achievable with or without ERC-4337, it's important to recognize the broader scope of opportunities that ERC-4337 brings to the table. This includes the ability to have transactions with sponsored gas fees and the capacity to handle batched transactions, opening up a new realm of functionalities and efficiencies in your smart contract interactions.

Import from clipboard

Paste your webpage below. It will be converted to Markdown.

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template is not available.
Upgrade
All
  • All
  • Team
No template found.

Create custom template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

How to use Slide mode

API Docs

Edit in VSCode

Install browser extension

Get in Touch

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

No updates to save
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully