Skip to content
SwapKit is a powerful suite of tools for building blockchain applications.

Migrate to v4

This guide provides a comprehensive overview of all breaking changes and migration steps from SwapKit v3 to v4.

v4 fundamentally changes how packages are organized:

v3 Structure: Individual packages for each component

Terminal window
@swapkit/plugin-chainflip
@swapkit/plugin-evm
@swapkit/toolbox-cosmos
@swapkit/wallet-keystore
@swapkit/api

v4 Structure: Consolidated monolithic packages with submodule exports

Terminal window
@swapkit/plugins/* # All plugins in one package
@swapkit/toolboxes/* # All toolboxes in one package
@swapkit/wallets/* # All wallets in one package
@swapkit/helpers # Utilities and API (previously @swapkit/api)
@swapkit/sdk # Complete bundle with everything

All imports must be updated:

// Plugins
import { ChainflipPlugin } from "@swapkit/plugin-chainflip";
import { EVMPlugin } from "@swapkit/plugin-evm";
import { ChainflipPlugin } from "@swapkit/plugins/chainflip";
import { EVMPlugin } from "@swapkit/plugins/evm";
// Toolboxes
import { getToolboxByChain } from "@swapkit/toolbox-cosmos";
import { EVMToolbox } from "@swapkit/toolbox-evm";
import { getCosmosToolbox } from "@swapkit/toolboxes/cosmos";
import { getEvmToolbox } from "@swapkit/toolboxes/evm";
// Wallets
import { keystoreWallet } from "@swapkit/wallet-keystore";
import { keystoreWallet } from "@swapkit/wallets/keystore";
// API (moved to helpers)
import { SwapKitApi } from "@swapkit/api";
import { SwapKitApi } from "@swapkit/helpers/api";

The SwapKit client initialization has changed:

// v3
import { SwapKit } from "@swapkit/core";
const client = SwapKit({
apis: { /* custom APIs */ },
rpcUrls: { /* RPC URLs */ },
config: { stagenet: false },
plugins: { ...ThorchainPlugin },
wallets: { ...keystoreWallet }
});
// v4
import { SwapKit } from "@swapkit/core";
const client = SwapKit({
config: {
rpcUrls: { /* RPC URLs */ },
apiKeys: { /* API keys */ }
},
plugins: { ...ThorchainPlugin },
wallets: { ...keystoreWallet }
});

v4 introduces a centralized configuration system:

// v3 - Direct configuration
const client = SwapKit({
apis: { [Chain.Ethereum]: customEthApi },
rpcUrls: { [Chain.Ethereum]: "https://eth-rpc.com" }
});
// v4 - SKConfig system
import { SKConfig } from "@swapkit/helpers";
SKConfig.set({
rpcUrls: { [Chain.Ethereum]: "https://eth-rpc.com" },
apiKeys: {
blockchair: "YOUR_KEY",
swapKit: "YOUR_KEY"
}
});

Plugins now use the createPlugin helper:

// v3
export function plugin({ getWallet, config }: SwapKitPluginParams<ConnectConfig>) {
return {
swap,
supportedSwapkitProviders: [ProviderName.THORCHAIN]
};
}
// v4
import { createPlugin } from "@swapkit/helpers";
export const MyPlugin = createPlugin({
name: "myPlugin",
properties: { supportedSwapkitProviders: [ProviderName.THORCHAIN] },
methods: ({ getWallet }) => ({ swap })
});

Wallets now use the createWallet helper:

// v3
export const keystoreWallet: SwapKitWallet<[chains: CryptoChain[], phrase: string]> =
({ addChain, apis, rpcUrls }) => {
return async (chains, phrase) => { /* ... */ };
};
// v4
import { createWallet } from "@swapkit/helpers";
export const keystoreWallet = createWallet({
name: "keystore",
hooks: ({ config }) => ({
async connectWallet(chains: Chain[], phrase: string) { /* ... */ }
})
});

Toolboxes no longer accept RPC URLs directly:

// v3
const toolbox = getToolboxByChain(chain, {
api: customApi,
rpcUrl: "https://rpc.url",
signer
});
// v4 - RPC URLs from SKConfig only
const toolbox = getEvmToolbox(chain, { signer });
// RPC URL automatically retrieved from SKConfig

Several type imports have changed:

// Wallet types
import type { EVMWallets } from "@swapkit/toolbox-evm";
import type { EVMToolboxes } from "@swapkit/toolboxes/evm";
// API types
import type { QuoteRequest } from "@swapkit/api";
import type { QuoteRequest } from "@swapkit/helpers/api";
// Plugin params simplified
SwapKitPluginParams<ConnectConfig>
SwapKitPluginParams
  • ChainApis type: Use SKConfig system instead
  • Direct API parameter: Configure via SKConfig
  • walletAddressValidator helper: Removed from core exports
  • Individual package installations: Must use consolidated packages
Terminal window
# Remove v3 packages
bun remove @swapkit/plugin-* @swapkit/toolbox-* @swapkit/wallet-*
# Install v4 packages
bun add @swapkit/sdk
# or individual packages
bun add @swapkit/core @swapkit/plugins @swapkit/toolboxes @swapkit/wallets

Replace all v3 imports with v4 equivalents:

import { THORChainPlugin } from "@swapkit/plugin-thorchain";
import { EVMToolbox } from "@swapkit/toolbox-evm";
import { ledgerWallet } from "@swapkit/wallet-ledger";
import { ThorchainPlugin } from "@swapkit/plugins/thorchain";
import { getEvmToolbox } from "@swapkit/toolboxes/evm";
import { ledgerWallet } from "@swapkit/wallets/ledger";
import { SwapKitCore } from "@swapkit/core";
import { createSwapKit } from "@swapkit/sdk";
const client = new SwapKitCore({
const client = createSwapKit({
// config
});

The wallet connection pattern remains similar but uses the new import paths:

// @noErrorValidation
import { createSwapKit, Chain } from "@swapkit/sdk";
const client = createSwapKit({
// your config
});
// Connect EVM wallet
await client.connectEVMWallet([Chain.Ethereum]);
// Connect keystore wallet
const chains = [Chain.Bitcoin, Chain.Ethereum, Chain.Cosmos];
const phrase = "your mnemonic phrase here";
await client.connectKeystore(chains, phrase);

1. Runtime Configuration Updates (Major Improvement)

Section titled “1. Runtime Configuration Updates (Major Improvement)”

The biggest improvement in v4 is the ability to update configuration at runtime without recreating the SwapKit client.

// v3 - Had to recreate entire client for config changes
const client1 = SwapKit({
rpcUrls: { [Chain.Ethereum]: "https://public-rpc.com" },
apis: { [Chain.Bitcoin]: customBtcApi }
});
// To change RPC URL, needed to create new client
const client2 = SwapKit({
rpcUrls: { [Chain.Ethereum]: "https://premium-rpc.com" },
apis: { [Chain.Bitcoin]: customBtcApi }
});
import { createSwapKit, SKConfig, Chain } from '@swapkit/sdk';
// Create client once
const swapKit = createSwapKit({
config: {
rpcUrls: { [Chain.Ethereum]: "https://public-rpc.com" },
apiKeys: { blockchair: "basic-key" }
}
});
// Update configuration at runtime - client continues working with new config
SKConfig.setRpcUrl(Chain.Ethereum, "https://premium-rpc.com");
SKConfig.setApiKey("blockchair", "premium-api-key");
// Switch to testnet mode
SKConfig.setEnv("isStagenet", true);
// All subsequent operations automatically use new configuration!
const balance = await swapKit.getBalance(Chain.Ethereum); // Uses premium RPC

Update specific parts of configuration without affecting others:

// Update API keys individually
SKConfig.setApiKey("swapKit", "your-swapkit-api-key");
SKConfig.setApiKey("walletConnectProjectId", "your-wc-project-id");
SKConfig.setApiKey("blockchair", "your-blockchair-key");
// Update RPC URLs for specific chains
SKConfig.setRpcUrl(Chain.Ethereum, "https://ethereum-rpc.com");
SKConfig.setRpcUrl(Chain.Arbitrum, "https://arbitrum-rpc.com");
SKConfig.setRpcUrl(Chain.Avalanche, "https://avalanche-rpc.com");
// Update environment settings
SKConfig.setEnv("isDev", false);
SKConfig.setEnv("isStagenet", true);
// Update integration configurations
SKConfig.setIntegrationConfig("radix", {
dAppDefinitionAddress: "account_rdx...",
applicationName: "My DeFi App",
applicationVersion: "1.0.0",
network: { networkId: 1, networkName: "mainnet" }
});

Update multiple configurations at once:

// Update multiple settings simultaneously
SKConfig.set({
rpcUrls: {
[Chain.Ethereum]: "https://ethereum-rpc.com",
[Chain.Arbitrum]: "https://arbitrum-rpc.com",
[Chain.Avalanche]: "https://avalanche-rpc.com"
},
apiKeys: {
blockchair: "premium-blockchair-key",
swapKit: "premium-swapkit-key",
walletConnectProjectId: "your-project-id"
},
envs: {
isStagenet: false,
isDev: false
}
});

Switch between mainnet and testnet without recreating client:

// Start on mainnet
const swapKit = createSwapKit();
// Switch to testnet for testing
SKConfig.setEnv("isStagenet", true);
SKConfig.setRpcUrl(Chain.THORChain, "https://stagenet-thornode.ninerealms.com");
// All operations now use testnet
await swapKit.connectKeystore([Chain.THORChain], phrase);
const balance = await swapKit.getBalance(Chain.THORChain); // Testnet balance
// Switch back to mainnet
SKConfig.setEnv("isStagenet", false);
SKConfig.setRpcUrl(Chain.THORChain, "https://thornode.ninerealms.com");

5. How Toolboxes Automatically Use Updated Config

Section titled “5. How Toolboxes Automatically Use Updated Config”

All toolboxes in v4 dynamically retrieve configuration from SKConfig:

// When you call this...
const ethToolbox = await getEvmToolbox(Chain.Ethereum);
// Internally, it gets the RPC URL from SKConfig
const rpcUrl = SKConfig.get("rpcUrls")[Chain.Ethereum];
const provider = new JsonRpcProvider(rpcUrl);
// So when you update the RPC URL...
SKConfig.setRpcUrl(Chain.Ethereum, "https://new-rpc.com");
// The next toolbox instance automatically uses the new URL
const newEthToolbox = await getEvmToolbox(Chain.Ethereum); // Uses new RPC!
  • createPlugin: Streamlined plugin creation with consistent interface
  • createWallet: Simplified wallet adapter development
  • Improved Solana Support: Jupiter API integration for real-time token metadata
  • Dynamic Cosmos Fees: Automatic fee estimation when not provided
  • Ripple Support: Full XRP toolbox implementation
  • OneKey Wallet: New wallet integration

Updates preserve existing configuration:

// Set initial API key
SKConfig.setApiKey("swapKit", "key1");
// Add another API key - preserves existing ones
SKConfig.setApiKey("blockchair", "key2");
// Both keys are now available
const apiKeys = SKConfig.get("apiKeys");
console.log(apiKeys.swapKit); // "key1"
console.log(apiKeys.blockchair); // "key2"
// @errors: 2305
// Error: Module '@swapkit/api' has no exported member 'SwapKitApi'
// Solution: Update import
import { SwapKitApi } from "@swapkit/sdk";
// @noErrorValidation
// Error: Argument of type '{ signer }' is not assignable...
// Solution: Configure via SKConfig
import { SKConfig, Chain, getEvmToolbox } from "@swapkit/sdk";
SKConfig.set({ rpcUrls: { [Chain.Ethereum]: "https://..." } });
const signer = /* your signer instance */;
const toolbox = getEvmToolbox(Chain.Ethereum, { signer });
// @noErrorValidation
// Error: Type '{ swap }' is not assignable...
// Solution: Use createPlugin helper
import { createPlugin } from "@swapkit/sdk";
const swap = async (params) => { /* implementation */ };
export const MyPlugin = createPlugin({
name: "myPlugin",
methods: ({ getWallet }) => ({ swap })
});
  • Update all package dependencies
  • Replace all import paths
  • Update client initialization code
  • Configure SKConfig for RPC URLs and API keys
  • Update custom plugins to use createPlugin
  • Update custom wallets to use createWallet
  • Remove direct API/RPC parameters from toolboxes
  • Test all functionality thoroughly