Why Upgrade?

Benefits of Upgrading

Upgrading your Nexus smart account is recommended for several important reasons:
1

Security Improvements

The latest implementation includes critical security enhancements.
2

New Features

Access to the newest MEE capabilities.
3

Performance Improvements

Enhanced gas efficiency and transaction processing.
4

Compatibility

Ensure you can leverage all the latest features of AbstractJS SDK and MEE infra.

Migration Process Overview

Migration Steps

The migration consists of these key steps:
1

Update AbstractJS Package

Install the latest SDK version
2

Connect to Existing Account

Use your existing account address
3

Upgrade Implementation

Call upgradeSmartAccount()
4

Verify Upgrade

Test the account with a transaction
5

Update Application

Adjust your application to use the latest features

Important Notes for Migration

Step 1: Update AbstractJS Package

SDK Update

First, update to the latest version of the AbstractJS SDK:
# npm
npm update @biconomy/abstractjs

# yarn
yarn upgrade @biconomy/abstractjs

# pnpm
pnpm update @biconomy/abstractjs

# bun
bun update @biconomy/abstractjs

Step 2: Connect to Your Existing Account

Account Connection

When connecting to an account created with an older SDK version, you’ll need your existing account address:
import { privateKeyToAccount } from "viem/accounts";
import { createBicoBundlerClient, toNexusAccount, getMEEVersion, MEEVersion } from "@biconomy/abstractjs";
import { baseSepolia } from "viem/chains";
import { http } from "viem";
import dotenv from "dotenv";

dotenv.config();

const privateKey = process.env.PRIVATE_KEY;
const account = privateKeyToAccount(`0x${privateKey}`);
const bundlerUrl = process.env.NEXUS_BUNDLER_URL;

// First, get your existing account address if you don't already have it stored
// This is crucial - you MUST store this address for future use
const existingAccountAddress = "YOUR_EXISTING_ACCOUNT_ADDRESS"; 

// Connect to your existing account
const nexusAccount = await toNexusAccount({
  signer: account,
  chainConfiguration: {
    chain: baseSepolia,
    transport: http(),
    version: getMEEVersion(MEEVersion.V2_1_0)
  },
  accountAddress: existingAccountAddress // Use your existing account address
});

const bundlerClient = createBicoBundlerClient({
  account: nexusAccount,
  transport: http(bundlerUrl)
});

Step 3: Upgrade the Smart Account

Account Upgrade

Call the upgradeSmartAccount() method to upgrade your account to the latest implementation.
In most cases, after upgrade, your account is going to use newer MEE K1 Validator, so you’ll have to re-initialize it.

    import {parseAbi} from "viem"
    import {NexusBootstrapAbi} from "@biconomy/abstractjs";

    // prepare nonce in the format of the old version
    const { getNonceWithKey } = nexusAccount;

    // get the validator address for the nonce, 
    // Only required if upgrading from MEE 1.x.x to 2.x.x
    const validatorForNonce = oldNexusAccount.getModule().module

    const { nonce } = await getNonceWithKey(oldNexusAccountAddress, {
        moduleAddress: validatorForNonce 
    })

    // Prepare the initdata for the upgrade
    const data = encodeAbiParameters(
      [
        { name: "bootstrap", type: "address" },
        { name: "initData", type: "bytes" }
      ],
      [
        nexusVersionConfig.bootStrapAddress,
        encodeFunctionData({
          abi: NexusBootstrapAbi,
          functionName: "initNexusWithDefaultValidator",
          args: [account.address]
        })
      ]
    )

    const initData = encodeFunctionData({
      abi: parseAbi(["function initializeAccount(bytes initData)"]),
      functionName: "initializeAccount",
      args: [data]
    })

    // Upgrade the account to the latest implementation
    const hash = await bundlerClient.upgradeSmartAccount({initData: initData, nonce: nonce});

    // Wait for the upgrade transaction to be processed
    const receipt = await bundlerClient.waitForUserOperationReceipt({ hash });
    console.log("Upgrade successful:", receipt.success);

    // Verify the account has been upgraded by checking the accountId
    const newAccountId = await bundlerClient.accountId();
    console.log("New account ID:", newAccountId);

Step 4: Verify the Upgrade

Upgrade Verification

After upgrading, verify that your account works correctly by performing a test transaction:
// Test with a simple transaction after upgrade
const testTxHash = await bundlerClient.sendUserOperation({
  calls: [{
    to: "0x0000000000000000000000000000000000000000",
    value: 0n,
    data: "0x"
  }]
});

const testReceipt = await bundlerClient.waitForUserOperationReceipt({
  hash: testTxHash
});
console.log("Test transaction successful:", testReceipt.success);

Step 5: Store Your Account Address

Address Storage

After successful migration, you MUST store your account address for future use:
// Get and store your account address
const accountAddress = await bundlerClient.account.getAddress();
console.log("IMPORTANT - Store this account address:", accountAddress);

// In your application, store this address securely 
// (database, local storage, user profile, etc.)
storeAccountAddress(userIdentifier, accountAddress);

Post-Migration: Future Account Access

Account Access After Migration

After migration, ALL future interactions with your account must use the accountAddress parameter:

CORRECT WAY

to access your account after migration
  // CORRECT WAY to access your account after migration
  const nexusAccount = await toNexusAccount({
    signer: account,
    chainConfiguration: {
      chain: baseSepolia,
      transport: http(),
      version: getMEEVersion(MEEVersion.V2_1_0)
    },
    accountAddress: "YOUR_STORED_ACCOUNT_ADDRESS" // This is essential
  });

INCORRECT WAY

this will create a new account, not access your existing one
 // INCORRECT WAY - this will create a new account, not access your existing one
 const incorrectAccount = await toNexusAccount({
   signer: account,
   chainConfiguration: {
     chain: baseSepolia,
     transport: http(),
     version: getMEEVersion(MEEVersion.V2_1_0)
   },
   // Missing accountAddress
 });

Troubleshooting

Common Issues and Solutions

If you encounter issues during the migration:
1

Check Funds

Make sure you are re-initializing or not re-initializing the validator module depending on the version you are migrating from and to. See two tabs on the Step 3.
2

Check Funds

Ensure the account has sufficient funds for gas
3

Verify Deployment

Verify the account is properly deployed on-chain
4

Check SDK Version

Check that your application is using the latest SDK version

Next Steps

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