How to Give an AI Agent Native Cross-Chain Swaps with the Chainflip SDK

How to Give an AI Agent Native Cross-Chain Swaps with the Chainflip SDK

How to Give an AI Agent Native Cross-Chain Swaps with the Chainflip SDK

How to Give an AI Agent Native Cross-Chain Swaps with the Chainflip SDK

Chainflip processed $727M in swap volume in October 2026, up 17% on October 2025 (Chainflip Scan). The public SDK behind those flows is open to any developer, so you can wrap it as tools that let an AI agent swap native BTC, ETH, SOL and stablecoins across chains while the user approves every step. This is a pattern you can build today with the public SDK, not an official Chainflip MCP server or agent skill.

What you need

  • A Node.js project with @chainflip/sdk installed (the swap module is imported from @chainflip/sdk/swap)

  • A Broker API endpoint configured in the SDK, since opening a deposit channel calls the Broker API

  • An agent framework or MCP host that supports tool calling with JSON Schema inputs

  • A wallet flow where the user sends the deposit themselves

  • Testnet funds on Perseverance for your first runs

Step 1: Initialise the SDK and expose a list_assets tool

The Chainflip SDK docs (as published in November 2026) already cover the full agent lifecycle: getChains and getAssets, getQuoteV2, requestDepositAddressV2 and getStatusV2. Start by wrapping the first two so the agent can discover what is swappable before it quotes anything.

import { SwapSDK } from '@chainflip/sdk/swap';

const sdk = new SwapSDK({ network: 'mainnet' });

export async function listAssets(chain) {
  return sdk.getAssets(chain);
}
import { SwapSDK } from '@chainflip/sdk/swap';

const sdk = new SwapSDK({ network: 'mainnet' });

export async function listAssets(chain) {
  return sdk.getAssets(chain);
}

What you will see: an array of AssetData objects. The functions reference gives the signature as getAssets(chain?: Chain, type?: AssetState), with chain identifiers including Bitcoin, Ethereum, Solana, Arbitrum, Assethub and Tron. getChains returns only chains that support deposit channel or vault swaps.

Common mistake: copying the docs examples verbatim, which initialise the SDK with network: 'perseverance' (testnet). Set the network explicitly for each environment, and pass Assethub rather than Polkadot, which the docs say was removed in version 1.11.

Swap BTC to USDC on Chainflip

Step 2: Wrap getQuoteV2 as a get_quote tool

Accept source asset, destination asset and amount from the model, then call the SDK. Amounts are in base units, so convert in code rather than asking the model to do it.

const { quotes } = await sdk.getQuoteV2({
  srcChain: 'Bitcoin', srcAsset: 'BTC',
  destChain: 'Ethereum', destAsset: 'USDC',
  amount: '10000000', // 0.1 BTC in satoshis
});
const { quotes } = await sdk.getQuoteV2({
  srcChain: 'Bitcoin', srcAsset: 'BTC',
  destChain: 'Ethereum', destAsset: 'USDC',
  amount: '10000000', // 0.1 BTC in satoshis
});

What you will see: one or more quotes with an estimated output, fees, and recommended values such as recommendedLivePriceSlippageTolerancePercent and recommendedRetryDurationMinutes. Return a trimmed summary to the model and keep the full quote object server-side under an id.

Common mistake: assuming a route is available because it was yesterday. If an asset is missing from getAssets or getQuoteV2 returns an error, the tool should tell the user the route is unavailable instead of quietly trying something else.

Step 3: Open a deposit channel only after the user confirms

This is the one tool that commits to a swap, so the host must show the quote and wait for an explicit yes. Validate the destination address for the destination chain and the refund address for the source chain before the call.

const channel = await sdk.requestDepositAddressV2({
  quote,
  destAddress: validatedEthAddress,
  fillOrKillParams: {
    refundAddress: validatedBtcAddress,
    maxOraclePriceSlippage: quote.recommendedLivePriceSlippageTolerancePercent,
    // retry duration and minimum price: derive from the quote, see SDK reference
  },
});
const channel = await sdk.requestDepositAddressV2({
  quote,
  destAddress: validatedEthAddress,
  fillOrKillParams: {
    refundAddress: validatedBtcAddress,
    maxOraclePriceSlippage: quote.recommendedLivePriceSlippageTolerancePercent,
    // retry duration and minimum price: derive from the quote, see SDK reference
  },
});

The SDK reference describes fillOrKillParams as the parameters that set a minimum accepted price, and release notes say maxOraclePriceSlippage is required when live price protection applies to both assets. Under the hood the SDK calls the Broker API's broker_request_swap_deposit_address, where docs portal PR #89 marks refund_parameters as required. Those parameters carry retry_duration, refund_address and min_price, and the docs flag a min_price of 0x0 as an example value only, so never default to it.

What you will see: a deposit address, a depositChannelId such as 6739624-Ethereum-2562, and an estimatedDepositChannelExpiryTime. Channels expire after 24 hours, so show the user that deadline. Funds sent to the address settle through Chainflip's decentralized custody model, secured by validators with no centralized custodian.

Common mistake: letting the model invent or reuse a refund address. Refund and destination addresses should come from the user's connected wallet and pass format checks in code.

Step 4: Poll swap status with getStatusV2

Call getStatusV2({ id: depositChannelId }) on an interval and return the state field plus the fields that state adds. The response is a union on state, covering WAITING, RECEIVING, SWAPPING, SENDING, SENT, COMPLETED and further states listed in the getStatusV2 docs (November 2026).

What you will see: the state advancing as the deposit is witnessed, swapped and sent. Map each state directly to your tool's output schema so the agent can narrate progress.

Common mistake: reporting COMPLETED as success. COMPLETED means the lifecycle is over. A fill-or-kill swap that misses its minimum price also ends there, with funds sent to the refund address, so inspect the refund fields before telling the user what happened.

Step 5: Publish the four tools as MCP-style definitions

Each wrapper becomes a tool with a name, a description, a JSON Schema input and a predictable output. Because the definition is plain schema plus a handler, the same four tools work in any MCP host or agent framework that supports tool calling.

{
  name: 'open_deposit_channel',
  description: 'Opens a Chainflip deposit channel for a quoted swap. Only call after the user explicitly confirms the quote.',
  inputSchema: {
    type: 'object',
    required: ['quoteId', 'destAddress', 'refundAddress'],
    properties: {
      quoteId: { type: 'string' },
      destAddress: { type: 'string' },
      refundAddress: { type: 'string' }
    }
  }
}
{
  name: 'open_deposit_channel',
  description: 'Opens a Chainflip deposit channel for a quoted swap. Only call after the user explicitly confirms the quote.',
  inputSchema: {
    type: 'object',
    required: ['quoteId', 'destAddress', 'refundAddress'],
    properties: {
      quoteId: { type: 'string' },
      destAddress: { type: 'string' },
      refundAddress: { type: 'string' }
    }
  }
}

What you will see: the host listing list_assets, get_quote, open_deposit_channel and get_swap_status as callable tools. Mark open_deposit_channel as requiring confirmation if your host supports it, and enforce that check in your handler too.

Common mistake: merging quote and channel creation into a single do_swap tool. That removes the confirmation step and lets the agent commit to a crypto swap the user never reviewed.

Troubleshooting

  • Asset not found: check the chain identifier and network, and use Assethub for DOT.

  • Deposit channel request rejected: confirm refundAddress is set and that maxOraclePriceSlippage is present where live price protection applies.

  • Status stuck on WAITING: the deposit has not been witnessed yet, or the channel expired. Compare the current time with estimatedDepositChannelExpiryTime.

  • User received a refund: the minimum price was not met within the retry window. Fetch a fresh quote before trying again.

Ship the pattern on testnet first

Four tools, one confirmation gate and strict address checks are enough to give an agent native cross-chain swaps without handing it control of funds. For the bigger picture on why this matters, read what changes when assistants can execute cross-chain trades and why native settlement beats solver networks.

Build against Perseverance, then switch the network to mainnet once the confirmation flow holds up. Your users can also buy native BTC or sell BTC for stablecoins directly on Chainflip while you test.

Resources

  • Swap - Start swapping native assets

  • Lending - Borrow against native Bitcoin

  • Blog - Product updates and announcements

  • Chainflip Scan - Track swaps and network activity

  • Website - Explore Chainflip

Earn with Chainflip:

Find us:

FAQ

Does Chainflip offer an official MCP server for AI agents?

No. This guide describes a pattern built on the public SDK from @chainflip/sdk/swap and the Broker API, and you define and host the tools yourself.

Can an AI agent complete a swap without the user?

It should not. Design the agent to list assets, quote and track status freely, but require explicit user confirmation before opening a deposit channel and have the user send the deposit from their own wallet.

How long does a Chainflip deposit channel stay open?

Deposit channels expire after 24 hours. The response from requestDepositAddressV2 includes estimatedDepositChannelExpiryTime, which the agent should show to the user.

Does a COMPLETED status mean the swap succeeded?

Not on its own. COMPLETED means the swap lifecycle is over, and a swap that missed its minimum price can end there with funds sent to the refund address, so check the refund fields before reporting the result.

Chainflip processed $727M in swap volume in October 2026, up 17% on October 2025 (Chainflip Scan). The public SDK behind those flows is open to any developer, so you can wrap it as tools that let an AI agent swap native BTC, ETH, SOL and stablecoins across chains while the user approves every step. This is a pattern you can build today with the public SDK, not an official Chainflip MCP server or agent skill.

What you need

  • A Node.js project with @chainflip/sdk installed (the swap module is imported from @chainflip/sdk/swap)

  • A Broker API endpoint configured in the SDK, since opening a deposit channel calls the Broker API

  • An agent framework or MCP host that supports tool calling with JSON Schema inputs

  • A wallet flow where the user sends the deposit themselves

  • Testnet funds on Perseverance for your first runs

Step 1: Initialise the SDK and expose a list_assets tool

The Chainflip SDK docs (as published in November 2026) already cover the full agent lifecycle: getChains and getAssets, getQuoteV2, requestDepositAddressV2 and getStatusV2. Start by wrapping the first two so the agent can discover what is swappable before it quotes anything.

import { SwapSDK } from '@chainflip/sdk/swap';

const sdk = new SwapSDK({ network: 'mainnet' });

export async function listAssets(chain) {
  return sdk.getAssets(chain);
}

What you will see: an array of AssetData objects. The functions reference gives the signature as getAssets(chain?: Chain, type?: AssetState), with chain identifiers including Bitcoin, Ethereum, Solana, Arbitrum, Assethub and Tron. getChains returns only chains that support deposit channel or vault swaps.

Common mistake: copying the docs examples verbatim, which initialise the SDK with network: 'perseverance' (testnet). Set the network explicitly for each environment, and pass Assethub rather than Polkadot, which the docs say was removed in version 1.11.

Swap BTC to USDC on Chainflip

Step 2: Wrap getQuoteV2 as a get_quote tool

Accept source asset, destination asset and amount from the model, then call the SDK. Amounts are in base units, so convert in code rather than asking the model to do it.

const { quotes } = await sdk.getQuoteV2({
  srcChain: 'Bitcoin', srcAsset: 'BTC',
  destChain: 'Ethereum', destAsset: 'USDC',
  amount: '10000000', // 0.1 BTC in satoshis
});

What you will see: one or more quotes with an estimated output, fees, and recommended values such as recommendedLivePriceSlippageTolerancePercent and recommendedRetryDurationMinutes. Return a trimmed summary to the model and keep the full quote object server-side under an id.

Common mistake: assuming a route is available because it was yesterday. If an asset is missing from getAssets or getQuoteV2 returns an error, the tool should tell the user the route is unavailable instead of quietly trying something else.

Step 3: Open a deposit channel only after the user confirms

This is the one tool that commits to a swap, so the host must show the quote and wait for an explicit yes. Validate the destination address for the destination chain and the refund address for the source chain before the call.

const channel = await sdk.requestDepositAddressV2({
  quote,
  destAddress: validatedEthAddress,
  fillOrKillParams: {
    refundAddress: validatedBtcAddress,
    maxOraclePriceSlippage: quote.recommendedLivePriceSlippageTolerancePercent,
    // retry duration and minimum price: derive from the quote, see SDK reference
  },
});

The SDK reference describes fillOrKillParams as the parameters that set a minimum accepted price, and release notes say maxOraclePriceSlippage is required when live price protection applies to both assets. Under the hood the SDK calls the Broker API's broker_request_swap_deposit_address, where docs portal PR #89 marks refund_parameters as required. Those parameters carry retry_duration, refund_address and min_price, and the docs flag a min_price of 0x0 as an example value only, so never default to it.

What you will see: a deposit address, a depositChannelId such as 6739624-Ethereum-2562, and an estimatedDepositChannelExpiryTime. Channels expire after 24 hours, so show the user that deadline. Funds sent to the address settle through Chainflip's decentralized custody model, secured by validators with no centralized custodian.

Common mistake: letting the model invent or reuse a refund address. Refund and destination addresses should come from the user's connected wallet and pass format checks in code.

Step 4: Poll swap status with getStatusV2

Call getStatusV2({ id: depositChannelId }) on an interval and return the state field plus the fields that state adds. The response is a union on state, covering WAITING, RECEIVING, SWAPPING, SENDING, SENT, COMPLETED and further states listed in the getStatusV2 docs (November 2026).

What you will see: the state advancing as the deposit is witnessed, swapped and sent. Map each state directly to your tool's output schema so the agent can narrate progress.

Common mistake: reporting COMPLETED as success. COMPLETED means the lifecycle is over. A fill-or-kill swap that misses its minimum price also ends there, with funds sent to the refund address, so inspect the refund fields before telling the user what happened.

Step 5: Publish the four tools as MCP-style definitions

Each wrapper becomes a tool with a name, a description, a JSON Schema input and a predictable output. Because the definition is plain schema plus a handler, the same four tools work in any MCP host or agent framework that supports tool calling.

{
  name: 'open_deposit_channel',
  description: 'Opens a Chainflip deposit channel for a quoted swap. Only call after the user explicitly confirms the quote.',
  inputSchema: {
    type: 'object',
    required: ['quoteId', 'destAddress', 'refundAddress'],
    properties: {
      quoteId: { type: 'string' },
      destAddress: { type: 'string' },
      refundAddress: { type: 'string' }
    }
  }
}

What you will see: the host listing list_assets, get_quote, open_deposit_channel and get_swap_status as callable tools. Mark open_deposit_channel as requiring confirmation if your host supports it, and enforce that check in your handler too.

Common mistake: merging quote and channel creation into a single do_swap tool. That removes the confirmation step and lets the agent commit to a crypto swap the user never reviewed.

Troubleshooting

  • Asset not found: check the chain identifier and network, and use Assethub for DOT.

  • Deposit channel request rejected: confirm refundAddress is set and that maxOraclePriceSlippage is present where live price protection applies.

  • Status stuck on WAITING: the deposit has not been witnessed yet, or the channel expired. Compare the current time with estimatedDepositChannelExpiryTime.

  • User received a refund: the minimum price was not met within the retry window. Fetch a fresh quote before trying again.

Ship the pattern on testnet first

Four tools, one confirmation gate and strict address checks are enough to give an agent native cross-chain swaps without handing it control of funds. For the bigger picture on why this matters, read what changes when assistants can execute cross-chain trades and why native settlement beats solver networks.

Build against Perseverance, then switch the network to mainnet once the confirmation flow holds up. Your users can also buy native BTC or sell BTC for stablecoins directly on Chainflip while you test.

Resources

  • Swap - Start swapping native assets

  • Lending - Borrow against native Bitcoin

  • Blog - Product updates and announcements

  • Chainflip Scan - Track swaps and network activity

  • Website - Explore Chainflip

Earn with Chainflip:

Find us:

FAQ

Does Chainflip offer an official MCP server for AI agents?

No. This guide describes a pattern built on the public SDK from @chainflip/sdk/swap and the Broker API, and you define and host the tools yourself.

Can an AI agent complete a swap without the user?

It should not. Design the agent to list assets, quote and track status freely, but require explicit user confirmation before opening a deposit channel and have the user send the deposit from their own wallet.

How long does a Chainflip deposit channel stay open?

Deposit channels expire after 24 hours. The response from requestDepositAddressV2 includes estimatedDepositChannelExpiryTime, which the agent should show to the user.

Does a COMPLETED status mean the swap succeeded?

Not on its own. COMPLETED means the swap lifecycle is over, and a swap that missed its minimum price can end there with funds sent to the refund address, so check the refund fields before reporting the result.

Get Chainflip updates

Product news, protocol updates, and launches.