Deploy a Safe account with Dynamic
Let’s deploy a Safe account on top of any wallet through Dynamic! First we’ll make sure signup/login are enabled, then we’ll fetch the walletClient once logged in before deploying the Safe account.
Enable signup/login
Once you’ve signed up for Dynamic, integrating it is as easy as either npx create-dynamic-app
, or simply following the Quickstart guide.
When that’s done you should have an app which is wrapped with the DynamicContextProvider.
Before we work on Main, let’s declare a function that can help us deploy the Safe account, taking a walletClient and wallet address as arguments:
We’re using a few dependancies below, you might want to first install them:
Let’s walk through what we just wrote step by step:
Transport URL
This is the RPC URL for the Pimlico API which we will use in multiple places, so better to extract it. It depends on your Pimlico API key so make sure you have that set under NEXT_PUBLIC_PIMLICO_API_KEY
in your .env
file.
pimlicoBundlerClient
The Bundler is the node that can help us batch our user operations and submit them as a single transaction to the blockchain. The client we are creating here is an interface to that Bundler, and it comes with a load of helpful methods related to those userops, such as Gas estimations. Specifically, we are going to need getUserOperationGasPrice
later.
You can see that as well as the transport (i.e. how it should communicate which in this case is via HTTP using the Transport URL we defined earlier), it needs something called the entrypoint address. This is imported as a static variable via ENTRYPOINT_ADDRESS_V07
from the permissionless
package. This is an address of a smart contract (deployed on every chain) that acts as a gateway for user operations. This article helps describe what the V07 version is compared to previous.
You can learn more about the Bundler Client here.
pimlicoPaymasterClient
This Paymaster is where we handle the sponsoring of user operations. It’s optional, but we are going to use it in our middleware later.
This client also needs the transport method and entrypoint address as we described in the previous step.
You can learn more about the Paymaster Client here.
Viem Clients & Chain
We are going to need to make some read actions and write actions onchain, and Viem provides a Public Client (for read actions) and Wallet Client (for write actions). We are going to need both of these, so we are going to extract them from the wallet object we get passed in as an argument.
Dynamic makes it super easy to return these clients from the wallet object. We can use the getPublicClient
and getWalletClient
methods on the wallet connector respectively.
You can learn more about interacting with Wallets (covers all kinds of actions) here.
walletClientToSmartAccountSigner
Something needs to sign the user operations we are going to send to the Bundler. This function takes the Wallet Client and returns a signer that can be used to sign those operations.
In normal transactions, the walletClient is enough to sign with, and you can use methods like signTransaction
or signMessage
directly on the walletClient. But for Smart Accounts, we need a specific type of signer that can handle the extra complexity of Smart Accounts.
You can learn more about this specific Signer type here.
signerToSafeSmartAccount
While we now have something that can sign for user operations, we don’t have a Smart Account yet to actually use it with. That’s the purpose of signerToSafeSmartAccount
. It takes the Public Client, the signer we just created, and some other options, and returns a Safe Account.
You can learn more about this method here.
createSmartAccountClient
With our signer and Safe account now in hand, the last step is to create an interface where we can start to take actions on the Safe Account. This is what createSmartAccountClient
does.
You can see we are defining some extra middleware here, such as the gas price and the sponsorUserOperation. These are optional but can be helpful in certain situations.
In our case we’re going to use the paymaster we created earlier to sponsor the user operations, and the bundler to get the gas prices.
You can learn more about the signerToSafeSmartAccount method here.
In Main.js
, we can now fetch the walletClient once logged in and then create that Safe account using the function we just created. To learn how to handle loading states, visit the Loading States guide.
That’s it! You now have the ability to create a Safe account on top of any wallet used with Dynamic, including embedded wallets! To learn how to interact with the Safe account, check out our Hackathon starter kit which handles ERC20 token transfers and cross chain ERC20 token transfers.
Was this page helpful?