Skip to main content
This guide explains how to migrate your BiconomySmartAccountV2 smart accounts to the newer Nexus smart accounts. The migration process preserves your account’s address, balance, and history while upgrading to Nexus’s enhanced architecture.

Why Migrate?

Benefits of Migration

Migrating from V2 to Nexus smart accounts provides several benefits:
1

Enhanced Security

Improved security model with modular validators
2

Better Performance

More gas-efficient transaction processing
3

Expanded Features

Access to the newest account abstraction capabilities
4

Future Compatibility

Ensure your smart account remains compatible with the latest AbstractJS SDK

Migration Process Overview

Migration Steps

The migration follows these steps:
1

Connect to V2 Account

Connect to your existing V2 smart account
2

Deploy V2 Account

If not already deployed. Ensure the account is deployed on-chain
3

Migrate to Nexus

Update implementation and initialize the Nexus account
4

Verify Migration

Test the migrated account with a supertransaction
5

Update Your Application

Use the latest SDK to interact with the migrated account

Prerequisites

Before starting the migration, ensure you have the following:

Required Setup

1

Update SDK

Update to the latest version of the AbstractJS SDK:
npm install @biconomy/abstractjs
2

Prepare Credentials

Make sure you have your EOA’s private key and the V2 account address

Step 1: Connect to Your V2 Account

V2 Account Connection

First, set up the necessary connections to your V2 smart account:
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { baseSepolia } from "viem/chains";
import { 
  createSmartAccountClient as createV2Client,
  BiconomySmartAccountV2,
  PaymasterMode
} from "@biconomy/account";
import { getMEEVersion, MEEVersion } from "@biconomy/abstractjs";
import dotenv from "dotenv";

dotenv.config();

// Use the version that suits your needs from the list
// See MEE Versioning
const version = MEEVersion.V2_1_0;
const versionConfig = getMEEVersion(version)

// Define configuration variables
const config = {
  // Chain and network information
  chain: baseSepolia,
  
  // EOA credentials
  eoaPrivateKey: process.env.EOA_PRIVATE_KEY, // Replace with your private key
  eoaAddress: process.env.EOA_ADDRESS, // Replace with your EOA address
  
  // Biconomy infrastructure URLs
  v2BundlerUrl: process.env.V2_BUNDLER_URL, // Replace with your V2 bundler URL
  nexusBundlerUrl: process.env.NEXUS_BUNDLER_URL, // Replace with your Nexus bundler URL
  
  // API keys
  paymasterApiKey: process.env.PAYMASTER_API_KEY, // Replace with your Paymaster API key
  
  // Nexus contract addresses
  nexusImplementationAddress: versionConfig.implementationAddress,
  nexusBootstrapAddress: versionConfig.bootStrapAddress,
};

// Connect to your EOA
const eoaAccount = privateKeyToAccount(config.eoaPrivateKey as `0x${string}`);
const client = createWalletClient({
  account: eoaAccount,
  chain: config.chain,
  transport: http(),
});

// Connect to your V2 smart account
const V2Account = await createV2Client({
  signer: client,
  biconomyPaymasterApiKey: config.paymasterApiKey,
  bundlerUrl: config.v2BundlerUrl!,
});

// Get V2 account address
const V2AccountAddress = await V2Account.getAccountAddress();
console.log("V2 Account Address:", V2AccountAddress);

Step 2: Check Deployment Status

Account Deployment Check

Check if your V2 account is already deployed, and deploy it if necessary:
// Check if account is deployed
const isDeployed = await V2Account.isAccountDeployed();

if (!isDeployed) {
  console.log("Account not deployed, deploying now...");
  
  // Deploy the V2 account
  const deploymentResponse = await V2Account.sendTransaction([
    {
      to: V2AccountAddress,
      value: 0n,
      data: "0x",
    },
  ]);

  const { transactionHash } = await deploymentResponse.waitForTxHash();
  console.log("V2 account deployment transaction hash:", transactionHash);
} else {
  console.log("Account already deployed, proceeding with migration");
}

Step 3: Migrate to Nexus

Nexus Migration

Now perform the migration by updating the implementation to Nexus and initializing the Nexus account:
import { 
  encodeFunctionData,
  encodeAbiParameters
} from "viem";

async function migrateToNexus(V2Account: BiconomySmartAccountV2) {
  const V2AccountAddress = await V2Account.getAccountAddress();
  
  // Step 1: Update implementation to Nexus
  console.log("Preparing update implementation to Nexus...");
  const updateImplementationCalldata = encodeFunctionData({
    abi: [
      {
        name: "updateImplementation",
        type: "function",
        stateMutability: "nonpayable",
        inputs: [{ type: "address", name: "newImplementation" }],
        outputs: []
      }
    ],
    functionName: "updateImplementation",
    args: [config.nexusImplementationAddress],
  });
  
  const updateImplementationTransaction = {
    to: V2AccountAddress,
    data: updateImplementationCalldata,
  };
  
  // Step 2: Initialize Nexus Account
  console.log("Preparing initialize Nexus account...");
  const ownerAddress = config.eoaAddress;
  
  // Prepare initialization data for the validator
    const initData = encodeFunctionData({
      abi: [
        { 
          name: "initNexusWithDefaultValidator", type: "function",
           stateMutability: "nonpayable", 
           inputs: [
            { type: "bytes", name: "data" }
          ], 
          outputs: [] 
        }
      ],
      functionName: "initNexusWithDefaultValidator",
      args: [ownerAddress as `0x${string}`]
    });
  
  // Encode bootstrap data
  const initDataWithBootstrap = encodeAbiParameters(
    [
      { name: "bootstrap", type: "address" },
      { name: "initData", type: "bytes" },
    ],
    [config.nexusBootstrapAddress, initData]
  );
  
  // Create initializeAccount calldata
  const initializeNexusCalldata = encodeFunctionData({
    abi: [
      {
        name: "initializeAccount",
        type: "function",
        stateMutability: "nonpayable",
        inputs: [{ type: "bytes", name: "data" }],
        outputs: []
      }
    ],
    functionName: "initializeAccount",
    args: [initDataWithBootstrap],
  });
  
  const initializeNexusTransaction = {
    to: V2AccountAddress,
    data: initializeNexusCalldata,
  };
  
  // Send both transactions in a batch
  console.log("Sending migration transaction...");
  const migrateToNexusResponse = await V2Account.sendTransaction(
    [updateImplementationTransaction, initializeNexusTransaction],
    {
      paymasterServiceData: { mode: PaymasterMode.SPONSORED },
    }
  );
  
  const { transactionHash } = await migrateToNexusResponse.waitForTxHash();
  console.log("Migration transaction hash:", transactionHash);
  console.log("Migration completed successfully");
  
  return V2AccountAddress; // Return the address for the next step
}

Step 4: Test Your Migrated Account

Migration Verification

After migration, verify that your account works correctly by creating a test supertransaction:
  import {
    createMeeClient,
    getMEEVersion,
    MEEVersion,
    toMultichainNexusAccount,
  } from "@biconomy/abstractjs";
  import { Address, Hex, http } from "viem";
  import { privateKeyToAccount } from "viem/accounts";
  import { base } from "viem/chains";

  const privateKey: Hex = "0xyour_private_key";
  const storedSmartAccountAddress: Address = "0xyour_sca_address";
  const eoaAccount = privateKeyToAccount(privateKey);

  // Initialize mcNexus with new version config
  const mcNexus = await toMultichainNexusAccount({
    signer: eoaAccount,
    chainConfigurations: [
      {
        chain: base,
        transport: http(),
        version: getMEEVersion(MEEVersion.V2_1_0),
        // This is essential
        accountAddress: storedSmartAccountAddress,
      },
    ],
  });

  // Create MEE client
  const meeClient = await createMeeClient({
    account: mcNexus,
  });

  const USDC_BASE: Address = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"; // fee token

  const amount = 1n;
  const instructions = await mcNexus.buildComposable({
    type: "transfer",
    data: {
      tokenAddress: USDC_BASE,
      chainId: base.id,
      amount,
      recipient: eoaAccount.address,
    },
  });

  // Get quotes
  const quote = await meeClient.getFusionQuote({
    instructions,
    trigger: {
      tokenAddress: USDC_BASE,
      chainId: base.id,
      amount,
    },
    feeToken: {
      address: USDC_BASE,
      chainId: base.id,
    },
  });

  // Executes the supertransaction
  const { hash: supertxHash } = await meeClient.executeFusionQuote({
    fusionQuote: quote,
  });

  // Wait for the supertransaction
  const receipt = await meeClient.waitForSupertransactionReceipt({
    hash: supertxHash,
  });

Step 5: Update Your Application

Application Update

Update your application to use the latest AbstractJs SDK with MEE stack for all future interactions:
// IMPORTANT: Always use the same address as your V2 account
const migratedAccountAddress = "YOUR_V2_ACCOUNT_ADDRESS";

// Initialize mcNexus with new version config
// Use this pattern for all future SDK interactions
// Use the same version you used to get implementation address to upgrade to
const mcNexus = await toMultichainNexusAccount({
  signer: eoaAccount,
  chainConfigurations: [
    {
      chain: base,
      transport: http(),
      version: getMEEVersion(MEEVersion.V2_1_0),
      // This is essential
      accountAddress: migratedAccountAddress,
    },
  ],
});

// Create MEE client
const meeClient = await createMeeClient({
  account: mcNexus,
});

Troubleshooting

Common Issues and Solutions

If you encounter issues during migration:
1

Check Funds

Ensure your EOA has sufficient funds for gas
2

Verify Deployment

Verify the V2 account is properly deployed
3

Check Configuration

Check that all environment variables are set correctly

Next Steps

After successfully migrating your V2 account to Nexus:

Post-Migration Actions

1

Store Account Address

STORE YOUR ACCOUNT ADDRESS in your application’s persistent storage
2

Update Application Code

Update your application code to use the accountAddress parameter in all future interactions
3

Test Thoroughly

Test thoroughly with real transactions to ensure everything works as expected
By following this migration guide and properly storing your account address, you’ve successfully upgraded your V2 account to a Nexus account while preserving its address, balance, and history.