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.
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)
// 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)
// 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)
// 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)
// 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
yarn add @lifi/sdk-provider-ethereum @lifi/sdk-provider-solana @lifi/sdk-provider-bitcoin @lifi/sdk-provider-sui @lifi/sdk-provider-tron
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.
Provider Configuration
Before (v3)
// 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)
// 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 and the Wallet Standard instead of @solana/web3.js and the legacy wallet adapter.
Before (v3)
// SDK v3
import { Solana } from '@lifi/sdk';
Solana({
getWalletAdapter: () => Promise.resolve(walletAdapter),
});
After (v4)
// 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)
// SDK v3
import { Sui } from '@lifi/sdk';
Sui({
getWallet: () => Promise.resolve(wallet),
});
After (v4)
// SDK v4
import { SuiProvider } from '@lifi/sdk-provider-sui';
SuiProvider({
getClient: () => Promise.resolve(suiClient),
getSigner: () => Promise.resolve(signer),
});
Configuration Management
Before (v3)
// 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)
// 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)
// SDK v3
step.execution?.process.forEach((process) => {
if (process.txHash) {
console.log(process.type, process.txHash);
}
});
After (v4)
// 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)
// SDK v3
executeRoute(route, {
switchChainHook: async (chainId) => { ... },
disableMessageSigning: true,
});
After (v4)
// 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)
// SDK v3
import { getTokenAllowance, setTokenAllowance } from '@lifi/sdk';
const allowance = await getTokenAllowance(token, ownerAddress, spenderAddress);
const txHash = await setTokenAllowance(approvalRequest);
After (v4)
// 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.
// 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:
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:
- Create multiple clients with different configurations
- Better testability - easier to mock and test
- Type safety - better TypeScript support
- Explicit dependencies - clear what functions depend on
Example: Multiple Clients
// 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, and feel free to file an issue if you encounter any problems.
Changelog
For a detailed view of all the changes, please see the CHANGELOG.