This guide will walk you through how to use Biconomy’s smart accounts with Dynamic. You can find more info on how Biconomy works here: https://docs.biconomy.io/account
Install Dynamic and Biconomy
In your app’s repository, install @dynamic-labs/sdk-react-core, @dynamic-labs/ethereum and @biconomy/{account, bundler, common, core-types, paymaster}:
yarn add @dynamic-labs/sdk-react-core @biconomy/account @biconomy/bundler @biconomy/common @biconomy/core-types @biconomy/paymaster
@dynamic-labs/ethereum will help you to enable all EVM compatible chains
including layer 2’s i.e. Base as well as Dynamic Embedded Wallets. Learn more
about WalletConnectors
here. Add the DynamicContextProvider
All you need to get started is the DynamicContextProvider - you will want to wrap your app with this component at the highest possible level, like so:
import { DynamicContextProvider } from "@dynamic-labs/sdk-react-core";
import { EthereumWalletConnectors } from "@dynamic-labs/ethereum";
import { EthersExtension } from "@dynamic-labs/ethers-v6";
<DynamicContextProvider
  settings={{
    // Find your environment id at https://app.dynamic.xyz/dashboard/developer
    environmentId: "REPLACE-WITH-YOUR-ENVIRONMENT-ID",
    walletConnectors: [EthereumWalletConnectors],
    walletConnectorExtensions: [EthersExtension],
  }}
>
  {/* Your app's components */}
</DynamicContextProvider>;
We are using Ethers here instead of the default Viem, as Biconomy requires an
Ethers signer object. Learn more about switching between Viem and Ethers
here. To enable embedded wallets for your users, toggle it on along with
email/social auth in the
dashboard. Access the wallet
Inside any component which is wrapped by DynamicContextProvider, you can access any of the provided hooks. While you can access the full context via usedynamiccontext, we are most interested in the users currently connected wallets which we can easily access via useUserWallets.
A user can have branded wallets connected as well as Dynamic embedded wallets,
so here we will filter for a users embedded wallet, assuming they had one
created when they signed up.
import { useUserWallets } from "@dynamic-labs/sdk-react-core";
const userWallets = useUserWallets();
const embeddedWallet = userWallets.find(
  (wallet) => wallet.connector?.isEmbeddedWallet === true
);
Initialize a bundler and paymaster
You will need to initialize instances of a Biconomy bundler and paymaster for the user, like so:
import { IBundler, Bundler } from "@biconomy/bundler";
import { IPaymaster, BiconomyPaymaster } from "@biconomy/paymaster";
import { ChainId } from "@biconomy/core-types";
import { DEFAULT_ENTRYPOINT_ADDRESS } from "@biconomy/account";
...
// Initialize your bundler
const bundler: IBundler = new Bundler({
bundlerUrl: 'your-bundler-url-from-the-biconomy-dashboard',
chainId: ChainId.POLYGON_MUMBAI, // Replace this with your desired network
entryPointAddress: DEFAULT_ENTRYPOINT_ADDRESS, // This is a Biconomy constant
});
// Initialize your paymaster
const paymaster: IPaymaster = new BiconomyPaymaster({
paymasterUrl: 'your-paymaster-url-from-the-biconomy-dashboard',
});
Initialize a ECDSAOwnershipValidationModule
Now you’re ready to allow the user to authorize actions from their Biconomy smart account by signing messages with their Dynamic wallet. This is done by initializing a ECDSAOwnershipValidationModule for the user’s smart account and passing in a signer from the user’s wallet.
import {
  ECDSAOwnershipValidationModule,
  DEFAULT_ECDSA_OWNERSHIP_MODULE,
} from "@biconomy/modules";
...
// Get a provider and signer for the user's embedded wallet
const provider = await embeddedWallet.connector?.getPublicClient();
// Note that we are using the ethers signer here rather than Viem
const signer = await embeddedWallet.connector?.ethers?.getSigner();
// Initialize Biconomy's validation module with the ethers signer
const validationModule = await ECDSAOwnershipValidationModule.create({
signer: signer,
moduleAddress: DEFAULT_ECDSA_OWNERSHIP_MODULE // This is a Biconomy constant
});
Create the smart account
Lastly, using the user’s paymaster, bundler, and validation module instances from above, initialize the user’s smart account using Biconomy’s BiconomySmartAccountV2.create method:
import {
  BiconomySmartAccountV2,
  DEFAULT_ENTRYPOINT_ADDRESS,
} from "@biconomy/account";
...
const smartAccount = await BiconomySmartAccountV2.create({
provider: provider, // This can be any ethers JsonRpcProvider connected to your app's network
chainId: ChainId.POLYGON_MUMBAI, // Replace this with your target network
bundler: bundler, // Use the `bundler` we initialized above
paymaster: paymaster, // Use the `paymaster` we initialized above
entryPointAddress: DEFAULT_ENTRYPOINT_ADDRESS, // This is a Biconomy constant
defaultValidationModule: validationModule, // Use the `validationModule` we initialized above
activeValidationModule: validationModule // Use the `validationModule` we initialized above
});
End to end flow
You can find a complete example of the integration here: https://github.com/dynamic-labs/dynamic-biconomy-example