Creating a DEX swap
Swap tokens on-chain through a DEX from any wallet — permissionless, with no account, KYC, or activity. Quote the swap, approve if needed, then sign and broadcast the returned transaction yourself.
Last updated
curl -X POST "https://backend.pay.kiichain.io/market/v1/dex/quote" \
-H "Content-Type: application/json" \
-d '{
"asset_in": {
"denom": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"chain_id": "1",
"amount": "25000000"
},
"asset_out": {
"denom": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"chain_id": "1"
},
"sender_address": "0x1A2b3C4d5E6f7A8b9C0d1E2f3A4b5C6d7E8f9A0b"
}'{
"does_swap": true,
"estimated_amount_out": "24980000",
"txs_required": 1,
"usd_amount_in": "25.00",
"usd_amount_out": "24.98",
"swap_price_impact_percent": "0.08",
"provider": "lifi",
"evm_tx": "0x02f8b20180…",
"approval_token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"approval_address": "0xLiFiRouterSpender…",
"approval_amount": "25000000"
}import { parseTransaction } from "viem";
const { evm_tx } = quote; // from step 1
const tx = parseTransaction(evm_tx); // { to, value, data, chainId, ... }
const hash = await walletClient.sendTransaction({
to: tx.to,
value: tx.value,
data: tx.data,
chainId: tx.chainId,
});
console.log("swap broadcast:", hash);const receipt = await publicClient.waitForTransactionReceipt({ hash });
console.log(receipt.status); // "success" or "reverted"import { parseTransaction } from "viem";
// assumes viem `walletClient` (with your account) and `publicClient` are configured
const BASE_URL = "https://backend.pay.kiichain.io";
const SENDER = walletClient.account.address;
// 1 · Quote: 25 USDC → USDT on Ethereum.
const quote = await fetch(`${BASE_URL}/market/v1/dex/quote`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
asset_in: {
denom: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
chain_id: "1",
amount: "25000000",
},
asset_out: {
denom: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
chain_id: "1",
},
sender_address: SENDER,
}),
}).then((r) => r.json());
if (!quote.does_swap) throw new Error("no route available");
// 2 · Approve the router if the quote asks for it.
if (quote.approval_token && quote.approval_address) {
const approveHash = await walletClient.writeContract({
address: quote.approval_token,
abi: [
{
name: "approve",
type: "function",
stateMutability: "nonpayable",
inputs: [
{ name: "spender", type: "address" },
{ name: "amount", type: "uint256" },
],
outputs: [{ type: "bool" }],
},
],
functionName: "approve",
args: [quote.approval_address, BigInt(quote.approval_amount)],
});
await publicClient.waitForTransactionReceipt({ hash: approveHash });
}
// 3 · Sign & broadcast the swap transaction.
const tx = parseTransaction(quote.evm_tx);
const hash = await walletClient.sendTransaction({
to: tx.to,
value: tx.value,
data: tx.data,
chainId: tx.chainId,
});
// 4 · Confirm on-chain.
const receipt = await publicClient.waitForTransactionReceipt({ hash });
console.log(
receipt.status === "success" ? "Swap complete 🎉" : "Swap reverted",
);