> ## Documentation Index
> Fetch the complete documentation index at: https://docs.li.fi/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrate from v3 to v4

> Migration guide for upgrading LI.FI SDK v3 to v4

## Overview

**LI.FI SDK v4** introduces a client-based architecture that provides better type safety, improved modularity, and clearer separation of concerns. The SDK now uses a client instance pattern instead of global configuration, making it easier to manage multiple SDK instances and improving testability.

To get started, install the latest version of LI.FI SDK.

<CodeGroup>
  ```typescript yarn theme={"system"}
  yarn add @lifi/sdk
  ```

  ```typescript pnpm theme={"system"}
  pnpm add @lifi/sdk
  ```

  ```typescript bun theme={"system"}
  bun add @lifi/sdk
  ```

  ```typescript npm theme={"system"}
  npm install @lifi/sdk
  ```
</CodeGroup>

## Configuration

The most significant change in v4 is the move from a global configuration pattern to a client-based architecture. Instead of calling `createConfig()` and using global functions, you now create a client instance and pass it to all SDK functions.

### Before (v3)

```typescript theme={"system"}
// SDK v3
import { createConfig, getQuote, ChainId } from '@lifi/sdk';

createConfig({
  integrator: 'Your dApp/company name',
});

const quote = await getQuote({
  fromAddress: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  fromChain: ChainId.ARB,
  toChain: ChainId.OPT,
  fromToken: '0x0000000000000000000000000000000000000000',
  toToken: '0x0000000000000000000000000000000000000000',
  fromAmount: '1000000000000000000',
});
```

### After (v4)

```typescript theme={"system"}
// SDK v4
import { createClient, getQuote, ChainId } from '@lifi/sdk';

const client = createClient({
  integrator: 'Your dApp/company name',
});

const quote = await getQuote(client, {
  fromAddress: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  fromChain: ChainId.ARB,
  toChain: ChainId.OPT,
  fromToken: '0x0000000000000000000000000000000000000000',
  toToken: '0x0000000000000000000000000000000000000000',
  fromAmount: '1000000000000000000',
});
```

## Function Signatures

All SDK action functions now require the client as the first parameter. This includes:

* `getRoutes(client, {...})`
* `getQuote(client, {...})`
* `getContractCallsQuote(client, {...})`
* `getChains(client, {...})`
* `getTools(client, {...})`
* `getConnections(client, {...})`
* `getTokens(client, {...})`
* `getToken(client, chain, token)`
* `getTokenBalance(client, walletAddress, token)`
* `getTokenBalances(client, walletAddress, tokens)`
* `getTokenBalancesByChain(client, walletAddress, tokensByChain)`
* `getWalletBalances(client, walletAddress)`
* `getStatus(client, {...})`
* `getStepTransaction(client, step)`
* `executeRoute(client, route, options)`
* `resumeRoute(client, route, options)`
* `getGasRecommendation(client, {...})`
* `getTransactionHistory(client, {...})`
* `getNameServiceAddress(client, name, chainType?)`
* `getRelayerQuote(client, {...})`
* `relayTransaction(client, {...})`
* `getRelayedTransactionStatus(client, {...})`
* `patchContractCalls(client, {...})`

### Example Migration

### Before (v3)

```typescript theme={"system"}
// SDK v3
import { getRoutes, executeRoute } from '@lifi/sdk';

const result = await getRoutes({
  fromChainId: 42161,
  toChainId: 10,
  fromTokenAddress: '0x...',
  toTokenAddress: '0x...',
  fromAmount: '10000000',
});

const executedRoute = await executeRoute(result.routes[0], {
  updateRouteHook(route) {
    console.log(route);
  },
});
```

### After (v4)

```typescript theme={"system"}
// SDK v4
import { createClient, getRoutes, executeRoute } from '@lifi/sdk';

const client = createClient({
  integrator: 'Your dApp/company name',
});

const result = await getRoutes(client, {
  fromChainId: 42161,
  toChainId: 10,
  fromTokenAddress: '0x...',
  toTokenAddress: '0x...',
  fromAmount: '10000000',
});

const executedRoute = await executeRoute(client, result.routes[0], {
  updateRouteHook(route) {
    console.log(route);
  },
});
```

## Provider Packages

In v4, ecosystem providers have been moved to separate packages for better modularity and tree-shaking. You need to install the provider packages separately and import providers from their respective packages.

### Install Provider Packages

<CodeGroup>
  ```typescript yarn theme={"system"}
  yarn add @lifi/sdk-provider-ethereum @lifi/sdk-provider-solana @lifi/sdk-provider-bitcoin @lifi/sdk-provider-sui @lifi/sdk-provider-tron
  ```

  ```typescript pnpm theme={"system"}
  pnpm add @lifi/sdk-provider-ethereum @lifi/sdk-provider-solana @lifi/sdk-provider-bitcoin @lifi/sdk-provider-sui @lifi/sdk-provider-tron
  ```

  ```typescript npm theme={"system"}
  npm install @lifi/sdk-provider-ethereum @lifi/sdk-provider-solana @lifi/sdk-provider-bitcoin @lifi/sdk-provider-sui @lifi/sdk-provider-tron
  ```

  ```typescript bun theme={"system"}
  bun add @lifi/sdk-provider-ethereum @lifi/sdk-provider-solana @lifi/sdk-provider-bitcoin @lifi/sdk-provider-sui @lifi/sdk-provider-tron
  ```
</CodeGroup>

<Note>
  Only install the provider packages for the ecosystems you need. For example, if you only support EVM chains, you only need `@lifi/sdk-provider-ethereum`.
</Note>

### Provider Configuration

### Before (v3)

```typescript theme={"system"}
// SDK v3
import { createConfig, EVM, Solana } from '@lifi/sdk';

createConfig({
  integrator: 'Your dApp/company name',
  providers: [
    EVM({
      getWalletClient: () => Promise.resolve(walletClient),
    }),
    Solana({
      getWalletAdapter: () => Promise.resolve(walletAdapter),
    }),
  ],
});
```

### After (v4)

```typescript theme={"system"}
// SDK v4
import { createClient } from '@lifi/sdk';
import { EthereumProvider } from '@lifi/sdk-provider-ethereum';
import { SolanaProvider } from '@lifi/sdk-provider-solana';

const client = createClient({
  integrator: 'Your dApp/company name',
});

client.setProviders([
  EthereumProvider({
    getWalletClient: () => Promise.resolve(walletClient),
  }),
  SolanaProvider({
    getWallet: () => Promise.resolve(wallet), // wallet-standard Wallet
  }),
]);
```

## Provider Names

Provider factory names have been updated to be more descriptive:

* `EVM` → `EthereumProvider` (from `@lifi/sdk-provider-ethereum`)
* `Solana` → `SolanaProvider` (from `@lifi/sdk-provider-solana`)
* `UTXO` → `BitcoinProvider` (from `@lifi/sdk-provider-bitcoin`)
* `Sui` → `SuiProvider` (from `@lifi/sdk-provider-sui`)
* **New**: `TronProvider` (from `@lifi/sdk-provider-tron`) -- adds Tron ecosystem support

## Solana Provider: `getWalletAdapter` → `getWallet`

The Solana provider now uses [`@solana/kit`](https://github.com/solana-labs/solana-web3.js) and the [Wallet Standard](https://github.com/wallet-standard/wallet-standard) instead of `@solana/web3.js` and the legacy wallet adapter.

### Before (v3)

```typescript theme={"system"}
// SDK v3
import { Solana } from '@lifi/sdk';

Solana({
  getWalletAdapter: () => Promise.resolve(walletAdapter),
});
```

### After (v4)

```typescript theme={"system"}
// SDK v4
import { SolanaProvider } from '@lifi/sdk-provider-solana';

SolanaProvider({
  getWallet: () => Promise.resolve(wallet), // wallet-standard Wallet
});
```

## Sui Provider: `getWallet` → `getClient` + `getSigner`

The Sui provider now uses `@mysten/sui` v2 and requires a `ClientWithCoreApi` and a `Signer` instead of a wallet object.

### Before (v3)

```typescript theme={"system"}
// SDK v3
import { Sui } from '@lifi/sdk';

Sui({
  getWallet: () => Promise.resolve(wallet),
});
```

### After (v4)

```typescript theme={"system"}
// SDK v4
import { SuiProvider } from '@lifi/sdk-provider-sui';

SuiProvider({
  getClient: () => Promise.resolve(suiClient),
  getSigner: () => Promise.resolve(signer),
});
```

## Configuration Management

### Before (v3)

```typescript theme={"system"}
// SDK v3
import { config } from '@lifi/sdk';

// Update configuration
config.set({
  integrator: 'Updated name',
});

// Set providers
config.setProviders([...]);

// Get chains
const chains = await config.getChains();
```

### After (v4)

```typescript theme={"system"}
// SDK v4
import { createClient } from '@lifi/sdk';

const client = createClient({
  integrator: 'Your dApp/company name',
});

// Access configuration (read-only)
console.log(client.config.integrator);

// Set providers
client.setProviders([...]);

// Get chains
const chains = await client.getChains();

// Get specific chain
const chain = await client.getChainById(1);

// Get RPC URLs
const rpcUrls = await client.getRpcUrls();
```

## Execution Model: Process → Action

The execution tracking model has been renamed for clarity. What was previously called a "process" is now called an "action."

### Type and field renames

* `Execution.process` → `Execution.actions`
* `Process` → `ExecutionAction`
* `ProcessType` → `ExecutionActionType`
* `getProcessMessage()` → `getActionMessage()` + `getSubstatusMessage()`

### New action types

The `TOKEN_ALLOWANCE` process type has been split into more granular action types:

* `CHECK_ALLOWANCE` - Checking token allowance
* `RESET_ALLOWANCE` - Resetting token allowance
* `SET_ALLOWANCE` - Setting token allowance

Additionally, the `NATIVE_PERMIT` action type has been added.

### Before (v3)

```typescript theme={"system"}
// SDK v3
step.execution?.process.forEach((process) => {
  if (process.txHash) {
    console.log(process.type, process.txHash);
  }
});
```

### After (v4)

```typescript theme={"system"}
// SDK v4
import { getActionMessage } from '@lifi/sdk';

step.execution?.actions.forEach((action) => {
  if (action.txHash) {
    console.log(action.type, action.txHash);
  }
  const message = getActionMessage(action.type, action.status);
  console.log(message);
});
```

## ExecutionOptions Changes

The `switchChainHook` and `disableMessageSigning` options have been removed from `ExecutionOptions` and moved to `EthereumProviderOptions`, which is configured when setting up the EVM provider. Note that `switchChainHook` has been renamed to `switchChain` on the provider (as shown in the example below).

### Before (v3)

```typescript theme={"system"}
// SDK v3
executeRoute(route, {
  switchChainHook: async (chainId) => { ... },
  disableMessageSigning: true,
});
```

### After (v4)

```typescript theme={"system"}
// SDK v4
import { EthereumProvider } from '@lifi/sdk-provider-ethereum';

client.setProviders([
  EthereumProvider({
    getWalletClient: () => Promise.resolve(walletClient),
    switchChain: async (chainId) => { ... },
    disableMessageSigning: true,
  }),
]);

executeRoute(client, route, {
  // switchChainHook and disableMessageSigning are no longer here
});
```

## Token Allowance Functions

Token allowance functions are now exported from the Ethereum provider package instead of the main SDK package.

### Before (v3)

```typescript theme={"system"}
// SDK v3
import { getTokenAllowance, setTokenAllowance } from '@lifi/sdk';

const allowance = await getTokenAllowance(token, ownerAddress, spenderAddress);
const txHash = await setTokenAllowance(approvalRequest);
```

### After (v4)

```typescript theme={"system"}
// SDK v4
import { createClient } from '@lifi/sdk';
import { getTokenAllowance, setTokenAllowance } from '@lifi/sdk-provider-ethereum';

const client = createClient({
  integrator: 'Your dApp/company name',
});

const allowance = await getTokenAllowance(client, token, ownerAddress, spenderAddress);
const txHash = await setTokenAllowance(client, approvalRequest);
```

## The `actions()` Helper

If you prefer calling SDK functions without passing the client as the first parameter each time, you can use the `actions()` helper. It returns an object with all SDK action functions pre-bound to the client.

```typescript theme={"system"}
// SDK v4
import { createClient, actions } from '@lifi/sdk';

const client = createClient({
  integrator: 'Your dApp/company name',
});

const api = actions(client);

// No need to pass client as the first parameter
const quote = await api.getQuote({
  fromChain: 42161,
  toChain: 10,
  fromToken: '0x...',
  toToken: '0x...',
  fromAmount: '10000000',
  fromAddress: '0x...',
});
```

## New Utilities

v4 exports common utilities from `@lifi/sdk` so you no longer need `viem` or other libraries for basic formatting:

```typescript theme={"system"}
import { formatUnits, parseUnits } from '@lifi/sdk';

// Format token amount for display
const formatted = formatUnits(1000000n, 6); // "1"

// Parse user input to token amount
const amount = parseUnits("1", 6); // 1000000n
```

## Removed Parameters

Some configuration parameters have been removed or changed:

* `chains` - No longer passed to `createClient`. Chains are fetched automatically from the API.

## Client Instance Pattern

The client instance pattern allows you to:

1. **Create multiple clients** with different configurations
2. **Better testability** - easier to mock and test
3. **Type safety** - better TypeScript support
4. **Explicit dependencies** - clear what functions depend on

### Example: Multiple Clients

```typescript theme={"system"}
// SDK v4 - Multiple clients
import { createClient } from '@lifi/sdk';

const mainnetClient = createClient({
  integrator: 'MyApp',
  apiUrl: 'https://li.quest/v1',
});

const testnetClient = createClient({
  integrator: 'MyApp',
  apiUrl: 'https://staging.li.quest/v1',
});

// Use different clients for different environments
const mainnetRoutes = await getRoutes(mainnetClient, {...});
const testnetRoutes = await getRoutes(testnetClient, {...});
```

## Migration Checklist

* Update package installation to include provider packages
* Replace `createConfig()` with `createClient()` and store the client instance
* Update all function calls to include `client` as the first parameter (or use the `actions()` helper)
* Update provider imports to use separate provider packages
* Update provider factory names (`EVM` → `EthereumProvider`, etc.)
* For Solana: replace `getWalletAdapter` with `getWallet` (returns wallet-standard `Wallet`)
* For Sui: replace `getWallet` with `getClient` + `getSigner`
* Move `switchChainHook` (renamed to `switchChain`) and `disableMessageSigning` from `ExecutionOptions` to `EthereumProviderOptions`
* Update execution monitoring code: `execution.process` → `execution.actions`
* Replace `getProcessMessage()` with `getActionMessage()` and `getSubstatusMessage()`
* Update token allowance function imports to `@lifi/sdk-provider-ethereum`
* Update token allowance function calls to include `client` parameter
* Replace `config.set()` and `config.getChains()` with client methods
* Remove any references to global `config` object
* Replace `viem`'s `formatUnits`/`parseUnits` with `@lifi/sdk` exports if desired

## Examples

Check out our complete examples in the [SDK repository](https://github.com/lifinance/sdk/tree/main/examples), and feel free to [file an issue](https://github.com/lifinance/sdk/issues) if you encounter any problems.

## Changelog

For a detailed view of all the changes, please see the [CHANGELOG](https://github.com/lifinance/sdk/blob/main/CHANGELOG.md).
