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

Creating a SwapKit Plugin

SwapKit plugins extend the functionality of the core library to support various DeFi protocols and services. This guide explains how to create a custom plugin for SwapKit.

A SwapKit plugin consists of the following components:

  1. A plugin factory created with createPlugin
  2. Plugin methods that interact with external services or smart contracts
  3. Integration with the SwapKit client

Here’s a simple example of creating a plugin:

import {
AssetValue,
Chain,
SwapKitError,
createPlugin,
type EVMChain,
} from "@swapkit/sdk";
type SwapParams = {
route: {
sellAsset: string;
buyAsset: string;
sellAmount: string;
};
};
type QuoteParams = {
sellAsset: string;
buyAsset: string;
sellAmount: string;
};
export const ExamplePlugin = createPlugin({
name: "example",
properties: {
supportedSwapkitProviders: ["your-provider-name"],
},
methods: ({ getWallet }) => ({
swap: async function exampleSwap({ route }: SwapParams) {
const { sellAsset, buyAsset, sellAmount } = route;
if (!(sellAsset && buyAsset)) {
throw new SwapKitError("core_swap_asset_not_recognized");
}
const assetValue = await AssetValue.from({
asyncTokenLookup: true,
asset: sellAsset,
value: sellAmount,
});
const wallet = getWallet(assetValue.chain as EVMChain);
if (!wallet) {
throw new SwapKitError("core_wallet_connection_not_found");
}
if ("transfer" in wallet) {
const txHash = await wallet.transfer({
assetValue,
from: wallet.address,
recipient: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
});
return txHash;
}
throw new Error("Wallet does not support transfer");
},
getQuote: async function getExampleQuote(params: QuoteParams) {
return {
success: true,
data: {},
};
},
}),
});

Here’s a more realistic example of an EVM-based plugin that integrates with an exchange:

import {
ApproveMode,
AssetValue,
Chain,
EVMChain,
ProviderName,
SwapKitError,
createPlugin,
type QuoteResponseRoute
} from "@swapkit/sdk";
const approve = ({ approveMode, getWallet }) =>
async function({ assetValue }) {
const evmChain = assetValue.chain as EVMChain;
const wallet = getWallet(evmChain);
if (!wallet) {
throw new SwapKitError("core_wallet_connection_not_found");
}
const routerAddress = "0x1234567890123456789012345678901234567890";
if (approveMode === ApproveMode.CheckOnly) {
return wallet.isApproved({
amount: assetValue.getBaseValue("bigint"),
assetAddress: assetValue.address,
from: wallet.address,
spenderAddress: routerAddress,
});
}
return wallet.approve({
amount: assetValue.getBaseValue("bigint"),
assetAddress: assetValue.address,
from: wallet.address,
spenderAddress: routerAddress,
});
};
export const ExchangePlugin = createPlugin({
name: "exchange",
properties: {
supportedSwapkitProviders: [ProviderName.CUSTOM_EXCHANGE],
},
methods: ({ getWallet }) => ({
approveAssetValue: approve({ approveMode: ApproveMode.Approve, getWallet }),
isAssetValueApproved: approve({ approveMode: ApproveMode.CheckOnly, getWallet }),
swap: async function exchangeSwap({ route }) {
const { tx, sellAsset } = route;
if (!tx) {
throw new SwapKitError("core_swap_invalid_params");
}
const assetValue = await AssetValue.from({
asset: sellAsset,
asyncTokenLookup: true
});
const evmChain = assetValue.chain as EVMChain;
const wallet = getWallet(evmChain);
if (!wallet) {
throw new SwapKitError("core_wallet_connection_not_found");
}
const { from, to, data, value } = tx;
return wallet.sendTransaction({
from,
to,
data,
value: BigInt(value || 0)
});
},
getQuote: async function getExchangeQuote({
sellAsset,
buyAsset,
sellAmount,
slippage = 1,
}) {
try {
const response = await fetch("https:
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
sellAsset,
buyAsset,
sellAmount,
slippage,
}),
});
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
const quoteData = await response.json();
return {
success: true,
data: {
routes: [
{
sellAsset,
buyAsset,
sellAmount,
buyAmount: quoteData.buyAmount,
tx: {
from: quoteData.from,
to: quoteData.to,
data: quoteData.data,
value: quoteData.value,
},
providers: [ProviderName.CUSTOM_EXCHANGE],
} as QuoteResponseRoute,
],
},
};
} catch (error) {
return {
success: false,
error: String(error),
};
}
},
}),
});

Once you’ve created your plugin, you can use it with the SwapKit client:

import { createSwapKit, Chain, keystoreWallet } from "@swapkit/sdk";
import { ExamplePlugin } from "./example-plugin";
const swapKit = createSwapKit({
plugins: { examplePlugin: ExamplePlugin },
wallets: { ...keystoreWallet },
});
async function connectAndUsePlugin() {
await swapKit.connectKeystore(
[Chain.Bitcoin, Chain.Ethereum],
"your secret phrase here"
);
const quoteResponse = await swapKit.examplePlugin.getQuote({
sellAsset: "ETH.ETH",
buyAsset: "ETH.USDC-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
sellAmount: "0.1",
});
if (quoteResponse.success) {
const txHash = await swapKit.swap({ route: quoteResponse.data.routes[0] });
}
}

When creating a SwapKit plugin, follow these best practices:

  1. Error Handling: Use SwapKitError for consistent error reporting
  2. Type Safety: Leverage TypeScript to provide proper type definitions
  3. Documentation: Document your plugin methods and parameters
  4. Testing: Create comprehensive tests for all functionality
  5. Validation: Validate inputs to prevent runtime errors
  6. Security: Be careful with sensitive data and external API calls

By following this guide, you should be able to create, test, and integrate custom plugins with SwapKit.