How to build an app with Safe and ERC-7579
The smart account ecosystem needed to be more cohesive. Each provider built its modules, which were often incompatible with other smart account implementations. Developers had to build new modules compatible with their smart accounts or miss out on essential application features.
ERC-7579 (opens in a new tab) aims to ensure interoperability across implementations. It defines the account interface so developers can implement modules for all smart accounts that follow this standard. The Safe7579 Adapter makes your Safe compatible with any ERC-7579 modules. As a developer building with Safe, you can access a rich ecosystem of modules to add features to your application.
In this tutorial, you will build an app that can:
- Enable a 7579 module on a newly deployed Safe (the OwnableExecutor (opens in a new tab) module by Rhinestone)
- Send a transaction via the 7579 module (Send a dummy transaction as the new owner via
executeOnOwnedAccount
) - Interact with the 7579 directly to add a new owner to the module
The full code for this tutorial is in the Safe7579 module tutorial repository (opens in a new tab).
Prerequisites
Prerequisite knowledge: You will need some basic experience with React (opens in a new tab), Next.js (opens in a new tab), ERC-4337 (opens in a new tab) and ERC-7579 (opens in a new tab).
Before progressing with the tutorial, please make sure you have the following:
- Downloaded and installed Node.js (opens in a new tab) and pnpm (opens in a new tab).
- Created an API key from Pimlico (opens in a new tab).
- Metamask installed in your browser and connected to the Sepolia network.
- Two test accounts in Metamask, the second with some Sepolia Eth for gas.
1. Setup a Next.js application
Initialize a new Next.js app using pnpm with the following command:
When prompted by the CLI:
- Select
yes
to TypeScript, ESLint, and App router. - Select
no
to all other questions (Tailwind,src
directory, and import aliases).
Install dependencies
For this project, you will use Pimlico's Permissionless.js (opens in a new tab) to set up a Safe and interact with it and viem (opens in a new tab) for some helper functions.
Currently, permissionless.js
can only be used to deploy single-signer Safe accounts. Multi-signature ERC-7579 Safes will be coming soon.
Run the following command to add all these dependencies to the project:
2. Setup project
First, set up the project and add some UI and styles so you can focus on the 7579-related code for the rest of the tutorial.
Add CSS
Replace the content of app/globals.css
with the following:
Add a scaffold React component
Now, replace the content of app/page.tsx
with the following code. It includes all necessary imports, the React component and the UI, and empty functions you will fill with code in the following steps. From now on, you will only work on this file.
Add your Pimlico API key to the pimlicoUrl
variable. You can find your API key in the Pimlico dashboard.
You can now run the development server with pnpm dev
and open the app in your browser at http://localhost:3000
. You should see a card that asks you to connect two wallets. Connect two wallets to proceed with the tutorial.
3. Initialize the clients
In the first step, you create the clients that allow you to interact with the smart account. As permissionless.js is just a tiny wrapper around viem, you will use many of viem's functions in this tutorial.
To add this code, overwrite the init
function with this one:
You must refresh your page after adding this code, as the initial site load will trigger the init
function and set up the Safe account and the Smart account client. You can check the console to see if the setup was successful.
4. Install the 7579 module
Now, add the function to install the OwnableExecutor
module as an executor
to your smart account.
Overwrite the installModule
function with this one.
When you open the UI now and click the “Install Module” button, the console should log the module installation process. You can use jiffyscan.xyz (opens in a new tab) to inspect the user operation hash. From there, you can copy the transaction hash and inspect the transaction with Etherscan (opens in a new tab), Tenderly (opens in a new tab), or other block explorers.
5. Send a transaction via the 7579 module
In the following function, you will use the OwnableExecutor
module. The module allows owners to execute transactions from the smart account without collecting signatures. For this example, you will send a dummy transaction that sends zero eth to owner1.
In detail:
- Owner2 calls module
- The module calls
executeAsModule
on the smart account - The smart account executes the transaction (and sends zero eth to owner1)
Replace the executeOnOwnedAccount
function with this code:
When you open the UI and click the “Execute on owned account” button, your console should log the transaction. You can inspect the transaction with Tenderly to follow the call stack from the module over the Safe 7579 adapter to your Safe and the transaction's final receiver.
You also learned the required data format to send a 7579 transaction from a module to a Safe. It is precisely the data you packed for the transaction in executeOnOwnedAccountData
. Every other 7579 module uses the same data type to send transactions to a Safe. However, with most other modules, you don’t have to pack the data yourself; you call a function on the module, and the module sends the dedicated transaction to the smart account.
6. Interact with the 7579 module directly
Some modules can be configured directly. The OwnableExecutor
module allows you to add additional owners and remove existing owners. This example outlines how you interact with the module directly to add a new owner.
The call flow is:
- Sign a user operation with your smart account client and send it to the bundler.
- The bundler bundles the user operation into a regular transaction and sends it to the meme pool.
- The transaction executes a call from your smart account to the module with the defined data.
- The module recognizes your smart account as an authorized sender. It stores the new owner of your smart account in its storage.
Replace addOwner
with this function:
When you open the UI and click the “Add Owner” button, your console should log the user operation that adds a new owner. Make sure to inspect the final transaction (you can get the transaction hash from jiffyscan.xyz) to understand the call stack from the smart account to the module.
7. Uninstall the 7579 module
The last step is to uninstall the module. If the module is no longer needed, you can remove it from the smart account.
Replace the uninstallModule
function with this code:
In the last step of the UI, you can now click the “Uninstall Module” button to remove the module from the smart account. Notice that depending on the type of the 7579 module, the method required different deInitData
.
Also, you have to pass the correct previous entry address to the uninstallModule
function. If you have only one module installed, the previous entry is the sentinel address (opens in a new tab) 0x1
.
That’s it! You have successfully built an app that can interact with a Safe Smart Account using the ERC-7579 standard. You can now deploy and test your app with your Safes and modules.
Do more with Safe and ERC-7579
You learned how to deploy an ERC-7579-compatible Safe Smart Account and use an ERC-7579-compatible module, the OwnableExecutor from Rhinestone. We hope you enjoyed this tutorial and that the combination of Safe and 7579 will allow you to tap into new functionalities for your decentralized apps.
As a next step, you can add more functionalities to your app using other ERC-7579-compatible modules (opens in a new tab).
You can also find more inspiration on this list of ERC-7579 modules (opens in a new tab). You can also read more about this ERC in our overview (opens in a new tab) or the official documentation (opens in a new tab).
Did you encounter any difficulties? Let us know by opening an issue (opens in a new tab) or asking a question on Stack Exchange (opens in a new tab) with the safe-core
tag.