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.
Plugin Structure
Section titled “Plugin Structure”A SwapKit plugin consists of the following components:
- A plugin factory created with
createPlugin
- Plugin methods that interact with external services or smart contracts
- Integration with the SwapKit client
Basic Plugin Example
Section titled “Basic Plugin Example”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: {}, }; }, }),});
Creating an EVM-based Swap Plugin
Section titled “Creating an EVM-based Swap Plugin”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), }; } }, }),});
Using Your Plugin with SwapKit
Section titled “Using Your Plugin with SwapKit”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] }); }}
Best Practices
Section titled “Best Practices”When creating a SwapKit plugin, follow these best practices:
- Error Handling: Use SwapKitError for consistent error reporting
- Type Safety: Leverage TypeScript to provide proper type definitions
- Documentation: Document your plugin methods and parameters
- Testing: Create comprehensive tests for all functionality
- Validation: Validate inputs to prevent runtime errors
- 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.