# Migration Guide

> How to upgrade through breaking changes of the aa-sdk and account-kit

> For the complete documentation index, see [llms.txt](/docs/llms.txt).

Below are the steps to migrate your project from older versions of the `aa-sdk` and `account-kit` to the latest version.

## Migrating to Version V4.X.X

### Packages

All of the v3 packages have been renamed or removed. The new packages are as follows:

* `@alchemy/aa-core` -> `@aa-sdk/core`
* `@alchemy/aa-ethers` -> `@aa-sdk/ethers`
* `@alchemy/aa-alchemy` -> split into `@account-kit/signer`, `@account-kit/infra`, `@account-kit/core`, `@account-kit/react`
* `@alchemy/aa-accounts` -> `@account-kit/smart-contracts`
* `@alchemy/aa-signers` -> removed

### Smart wallet authentication

The `@alchemy/aa-signers` package has been deprecated. The authentication providers in that package are still compatible with v4, but they will not receive future support and the interfaces are not guaranteed to work with future versions of the SDK.
If you want to integrate a 3rd party authentication provider, it is straightforward if the provider exposes an EIP-1193 interface. See [this guide](/docs/wallets/third-party/signers/privy).

<Warning>
  All authentication providers in the SDK are still supported!

  `@account-kit/core` and `@account-kit/react` are the only packages that are opinionated about which authentication provider you can attach to a smart wallet. However, if you use `@aa-sdk/*` or `@account-kit/infra` with `@account-kit/smart-contracts`, you can
  use the guide above to integrate with any authentication provider of your choice.
</Warning>

### Alchemy Transport

The new `Transport` type: `AlchemyTransport` has been added. This impacts how Alchemy clients, middleware, and configs are created.

For Smart Account Clients, the `create*AlchemyClient` methods have been updated to take a new `transport` property (of type `AlchemyTransport`) instead of `rpcUrl` or `apiKey` directly.

The `alchemyFeeEstimator` and `alchemyUserOperationSimulator` middleware methods now no longer take in a `ClientWithAlchemyMethods` (returned by `createAlchemyPublicRpcClient`) and instead take in an `AlchemyTransport` as well.

The `AlchemyTransport` is a type of `viem` transport that makes it easier to configure your communication with Alchemy RPC. It supports splitting traffic between Alchemy's smart wallet infra and other Node providers (if needed). The `AlchemyTransport` has been added to `@account-kit/infra` and is exported as `alchemy`.

Creating a config with `@account-kit/core` or `@account-kit/react` has been updated to accept an `AlchemyTransport` and the parameters of `createConfig` have been simplified as a result. You will now need to replace your `rpcUrl` or `apiKey` params with `transport: alchemy({...})`.

For more detailed examples, see the relevant Quickstart guides, depending on which package you are using. If you don't know where to start, check out the [React Quickstart](/docs/wallets/react/quickstart).

### Hooks: `useSendTransaction` and `useSendTransactions` removed

These methods have been removed since `useSendUserOperation` can be used to send transactions. If you were using `useSendTransaction` or `useSendTransactions`, you can replace them with
`useSendUserOperation` and pass in `waitForTxn: true` so that all `sendUserOperation` calls will wait for the transaction to be mined.

### Utils: `verifyEIP6492Signature` removed

This method has been removed. Use [`verifyMessage`](https://viem.sh/docs/actions/public/verifyMessage) from viem.

### Utils: `defineReadOnly` removed

This method is no longer used internally and has been removed. The reference impl can be found within `ethers.js`.

### Utils: `getChain` removed

This method was not efficient or maintainable because it imported all chains from viem. If you used this method, it risked increasing your bundle size massively. Now all methods require a `Chain` instead of `chainId` in some places.

### Ethers: `Chain` required param

Certain methods required a `chainId` which would be converted into a `Chain` using the above method. This has been removed for the reasons above.

### Alchemy `Chain` defs

The Alchemy `Chain` definitions have been moved from `@aa-sdk/core` to `@account-kit/infra`.

### Ethers: `getPublicErc4337Client` → `getBundlerClient`

This method on the `AccountSigner` has been renamed.

### Accounts: Default LightAccount Version Is Now v2.0.0

If you were creating LightAccounts for users without explicitly specifying the version (ie. in `createLightAccount` or `useAccount` or `useSmartAccountClient`), you should manually specify the previous default of `v1.1.0`.

### Accounts: `create*Client` parameters un-nested

Previously, the `create*Client` (ie. `createLightAccountClient`) methods used to have an `account` parameter which took in the params for the underlying account. This is resulted in different APIs for both the corresponding `create*AlchemyClient` (ie. `createLightAccountAlchemyClient`) which had these as top-level parameters.
If you were using `createLightAccountClient` or similar methods, you should now pass the account parameters as top-level parameters.

### Accounts: `getNonce` -> `getAccountNonce`

Due to a clash in the typing of viem's `Account` type, the `getNonce` method has been renamed to `getAccountNonce`.

### Viem Version

The version of viem has been updated to `2.20.0` and been added as a peer dependency. If you have viem listed as a dependency, make sure it is updated to `2.20.0`.

### Dropped CJS Support

Due to the dependency on `wagmi` in the `core` and `react` packages, those packages no longer support `cjs` builds. To keep things consistent across all packages, CJS support has been dropped in all packages in this repo. See [this](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c) guide on how to migrate from CJS to ESM.

## Migrating to Version 3.X.X

This version update brings a lot of breaking changes. As support for Modular Accounts and their interfaces grew, the previous version of the SDK was not flexible enough to handle the modularity of the new account interfaces.
To address this, version 3.x.x of the SDK switches to an approach more idiomatic to `viem`.

### Viem Version

The dependency has been updated to viem v2.x.x. This means you need to update your project to use >= v2.5.0 of viem.

### Client: `SmartAccountProvider` → `SmartAccountClient`

The biggest change is that the `SmartAccountProvider` class has been removed and replaced with a `SmartAccountClient` type that extends `viem`'s [`Client`](https://viem.sh/docs/clients/custom). To get started with the new clients, you can do the following:

### Client: removed `sign*With6492` methods

The `signMessageWith6492` and `signTypedDataWith6492` methods have been removed from the `SmartAccountClient`. Now, all clients will always use 6492 when signing messages. However, if you need to sign messages without 6492, you can still use the `client.account.signMessage` methods.

### Client: `checkGasSponsorshipEligibility` return type updated

The `checkGasSponsorshipEligibility` methods now returns an object that includes the eligibility status of a transaction as well as the `UserOperationStruct` that the eligibility is for. This now ensures that checking for sponsorship doesn't cause you to use up your
gas sponsorship limits. If your transaction is eligible, then you can sign the UO with `client.signUserOperation` and send it with `client.sendRawUserOperation`.

```ts
import { SmartAccountProvider } from "@aa-sdk/core"; // [!code --]
import { getDefaultEntryPointAddress } from "@aa-sdk/core"; // [!code --]
import { http } from "viem"; // [!code ++]
import { sepolia } from "@aa-sdk/core";

const provider = new SmartAccountProvider({ // [!code --]
const client = createSmartAccountClient({ // [!code ++]
  rpcProvider: "RPC_URL", // [!code --]
  transport: http("RPC_URL"), // [!code ++]
  chain: sepolia,
  entryPointAddress: getDefaultEntryPointAddress(sepolia), // [!code --]
});
```

### Client: Removal of `with*` middleware override functions

The `SmartAccountProvider` in previous versions had a number of `with*` functions that mapped to the corresponding middleware functions on the provider.
The concept of the middlewares is still present in this version, but their configuration has been moved to the `SmartAccountClient` creator. For example,

```ts
import { SmartAccountProvider } from "@aa-sdk/core"; // [!code --]
import { getDefaultEntryPointAddress } from "@aa-sdk/core"; // [!code --]
import { http } from "viem"; // [!code ++]
import { sepolia } from "@aa-sdk/core";

const provider = new SmartAccountProvider({ // [!code --]
const client = createSmartAccountClient({ // [!code ++]
    rpcProvider: "RPC_URL", // [!code --]
    transport: http("RPC_URL"), // [!code ++]
    chain: sepolia,
    entryPointAddress: getDefaultEntryPointAddress(sepolia), // [!code --]
}).withGasEstimator(async () => ({ // [!code --]
    gasEstimator: async (struct) => ({ // [!code ++]
        ...struct, // [!code ++]
        callGasLimit: 0n,
        preVerificationGas: 0n,
        verificationGasLimit: 0n,
    }), // [!code ++]
});
```

### Client: Signature Changes on Methods

To support the various ways of connecting to a smart account, the signatures of the methods on `SmartAccountClient` have changed. Almost all methods now have an optional param for `account` and have been converted into single argument functions that take an object with the their properties instead.

### Account: `BaseSmartContractAccount` → `SmartContractAccount`

The next big change is the removal of the class-based `BaseSmartContractAccount` that all accounts extended from. This has been replaced with a `SmartContractAccount` type that extends `viem`'s [`Account`](https://v1.viem.sh/docs/accounts/custom.html), and instantiation of an account is now an `async` action. To get started with the new accounts (using `LightAccount` as an example), you will have to make the following changes:

```ts
import {
  LightSmartContractAccount, // [!code --]
  createLightAccount, // [!code ++]
  getDefaultLightAccountFactoryAddress, // [!code --]
} from "@account-kit/smart-contracts";
import {
  LocalAccountSigner,
  type Hex,
} from "@aa-sdk/core";
import { sepolia } from "@aa-sdk/core";

const chain = sepolia;

const account = new LightSmartContractAccount({ // [!code --]
const account = await createLightAccount({ // [!code ++]
    rpcClient: client, // [!code --]
    transport: http("RPC_URL"), // [!code ++]
    signer,
    chain,
    factoryAddress: getDefaultLightAccountFactoryAddress(chain), // [!code --]
  });
```

### Account: Connecting to a Smart Account

In earlier versions, a provider could not be used with a smart account until it was connected to one using `.connect`. In version 3.x.x, you have the option of keeping the two disconnected and passing the account to the client methods directly. You also have the option to hoist the account
so that you don't have to pass the account to every method.

#### Option 1: Passing the Account to the Client Methods

```ts
import { createLightAccount } from "@account-kit/smart-contracts";
import {
  createBundlerClient,
  createSmartAccountClientFromExisting
  LocalAccountSigner,
  type Hex,
} from "@aa-sdk/core";
import { sepolia } from "@aa-sdk/core";
import { custom, http } from "viem";

const chain = sepolia;

const client = createBundlerClient({
  chain,
  transport: http("JSON_RPC_URL"),
});

// [!code focus:99]
// createSmartAccountClientFromExisting is a helper method that allows you
// to reuse a JSON RPC client to create a Smart Account client.
const smartAccountClient = createSmartAccountClientFromExisting({
  client,
});

const account = await createLightAccount({
  signer,
  chain,
  transport: custom(client),
});

const { hash } = await smartAccountClient.sendUserOperation({
    uo: {
        target: "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
        data: "0x",
        value: 10n,
    },
    account, // [!code ++]
});
```

#### Option 2: Hoisting the Account

Hoisting the account is similar to using `.connect` in previous versions. Create your client with an account passed in to it.

```ts
import { createLightAccount } from "@account-kit/smart-contracts";
import {
  createBundlerClient,
  createSmartAccountClientFromExisting
  LocalAccountSigner,
  type Hex,
} from "@aa-sdk/core";
import { sepolia } from "@aa-sdk/core";
import { http, custom } from "viem";

const chain = sepolia;

const client = createBundlerClient({
  chain,
  transport: http("JSON_RPC_URL"),
});

// [!code focus:99]
const account = await createLightAccount({
  signer,
  transport: custom(client),
  chain,
});

const smartAccountClient = createSmartAccountClientFromExisting({
  account, // [!code ++]
  client,
});

const { hash } = await smartAccountClient.sendUserOperation({
  uo: {
    target: "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
    data: "0x",
    value: 10n,
  },
  account, // [!code --]
});
```

### Account: Custom Accounts

In prior versions, using your own wallet implementations required that you extend `BaseSmartContractAccount`. In version 3.x.x, you can use the `toSmartContractAccount` method which will allow you to use any account with `SmartAccountClient`. `toSmartContractAccount` has the form of:

```ts
type toSmartContractAccount = <
  Name extends string = string,
  TTransport extends Transport = Transport,
>({
  transport,
  chain,
  source,
  entryPointAddress,
  accountAddress,
  getAccountInitCode,
  signMessage,
  signTypedData,
  encodeBatchExecute,
  encodeExecute,
  getDummySignature,
  signUserOperationHash,
  encodeUpgradeToAndCall,
}: ToSmartContractAccountParams<Name, TTransport>) => Promise<
  SmartContractAccount<Name>
>;
```

### Account: SimpleAccount and NaniAccount initialization params

`chain` and `transport` have been added to the constructor and `rpcClient` has been removed.

### Account: SimpleAccount and LightAccount initialization params

`index` is now called `salt`

### Signer: `signTypedData` signature change

The `signTypedData` method found on `SmartAccountSigner` has been updated to match the signature found on `SmartContractAccount` and viem's `Account`.

```ts
(params: SignTypedDataParams) => Promise<Hex>; // [!code --]

<
  const TTypedData extends TypedData | { [key: string]: unknown },
  TPrimaryType extends string = string,
>(
  params: TypedDataDefinition<TTypedData, TPrimaryType>,
) => Promise<Hex>;
```

### Ethers: Removed methods

The `with*` methods have been removed from the Provider and authentication classes.
The `connect` methods have been removed in favor of immutable properties on the Provider and authentication classes. See updated AccountSigner constructor below.

### Ethers: `getPublicErc4337Client` → `getBundlerClient`

The `getPublicErc4337Client` method has been renamed to `getBundlerClient` to match the naming found in `aa-core`.

### Ethers: Updated authentication adapter constructor

The `AccountSigner` now takes in a `SmartContractAccount` as a param in its constructor.

### Core: `Percent` to `Multiplier` migration

The `Percent` type and `PercentSchema` have been removed in favor of the `Multiplier` type and `MultiplierSchema`.

Going forward when using the feeOptions, you can specify the `Multiplier` type instead of a `Percent`. The `Multiplier` type is a number that represents direct multiplication of the estimation. For example, `0.1` is 10% of the estimated value and `1` is 100% of the estimated value.

```ts
createModularAccountAlchemyClient({
    ...
    opts: {
      ...
      // The maxFeePerGas and maxPriorityFeePerGas estimated values will now be multipled by 1.5
      feeOptions: {
        // This was previously { percent: 50n }
        maxFeePerGas: { multiplier: 1.5 },
        // This was previously { percent: 25n }
        maxPriorityFeePerGas: { multiplier: 1.25 },
      },
    },
  });
```