跳至主要内容

代币兑换

兑换流程允许用户将一种代币兑换为另一种 -- 可以在同一条链上,也可以跨链(桥接兑换)。ONE SDK(@one_deploy/sdk v1.1.0)提供了功能完整的 Web widget 和全平台 API 方法。

Widget 用法(Web)

OneSwapWidget

主兑换 widget,处理代币对选择、金额输入、路由展示、滑点配置和交易执行。

import { OneSwapWidget } from '@one_deploy/sdk';

function SwapPage() {
return (
<OneSwapWidget
defaultFromToken={{ symbol: 'ETH', chainId: 1 }}
defaultToToken={{ symbol: 'USDC', chainId: 1 }}
defaultAmount="1.0"
walletAddress="0xYourUserWalletAddress"
slippageTolerance={0.5}
allowedChains={[1, 137, 42161]}
onSuccess={(result) => {
console.log('Swap complete:', result.txHash);
}}
onError={(error) => {
console.error('Swap failed:', error.message);
}}
onClose={() => {
console.log('Widget closed');
}}
theme="light"
/>
);
}

OneSwapWidgetProps

interface OneSwapWidgetProps {
/** 默认源代币 */
defaultFromToken?: SwapToken;
/** 默认目标代币 */
defaultToToken?: SwapToken;
/** 预填充的兑换数量(以源代币为单位) */
defaultAmount?: string;
/** 已连接的钱包地址 */
walletAddress: string;
/** 滑点容忍度百分比(例如 0.5 = 0.5%) */
slippageTolerance?: number;
/** 限制兑换在这些链 ID 上进行 */
allowedChains?: number[];
/** 限制可选择的代币 */
allowedTokens?: SwapToken[];
/** 启用跨链兑换(默认: true) */
enableCrossChain?: boolean;
/** 兑换完成时调用 */
onSuccess?: (result: SwapResult) => void;
/** 兑换失败时调用 */
onError?: (error: { code: string; message: string }) => void;
/** 用户关闭 widget 时调用 */
onClose?: () => void;
/** Widget 颜色主题 */
theme?: 'light' | 'dark' | 'auto';
/** 覆盖 CSS 类名 */
className?: string;
}

预设 Widget

import { OneSameChainSwap, OneCrossChainSwap } from '@one_deploy/sdk';

function SwapPresets() {
return (
<>
{/* Same-chain swap only -- cross-chain toggle is hidden */}
<OneSameChainSwap
walletAddress="0xAbc..."
defaultFromToken={{ symbol: 'ETH', chainId: 1 }}
defaultToToken={{ symbol: 'USDC', chainId: 1 }}
onSuccess={(result) => console.log('Same-chain swap done', result)}
/>

{/* Cross-chain swap -- source and dest chains differ */}
<OneCrossChainSwap
walletAddress="0xAbc..."
defaultFromToken={{ symbol: 'ETH', chainId: 1 }}
defaultToToken={{ symbol: 'USDC', chainId: 137 }}
onSuccess={(result) => console.log('Cross-chain swap done', result)}
/>
</>
);
}

API 方法(全平台)

getSwapQuote

获取兑换报价,包括最优路由、预估输出和手续费明细。

import { OneEngineClient } from '@one_deploy/sdk';

const engine = new OneEngineClient({
apiKey: 'YOUR_API_KEY',
projectId: 'YOUR_PROJECT_ID',
});

// Same-chain swap: ETH -> USDC on Ethereum
const quote: SwapQuote = await engine.getSwapQuote({
fromToken: 'ETH',
fromChainId: 1,
toToken: 'USDC',
toChainId: 1,
amount: '1.0',
slippage: 0.5,
senderAddress: '0xAbc...',
});

console.log(quote);
// {
// quoteId: 'sq_abc123',
// fromToken: { symbol: 'ETH', chainId: 1, address: '0x...', decimals: 18 },
// toToken: { symbol: 'USDC', chainId: 1, address: '0xA0b...', decimals: 6 },
// fromAmount: '1.0',
// toAmount: '2634.52',
// route: { steps: [...], estimatedGas: '150000', priceImpact: 0.03 },
// fee: { amount: '0.003', token: 'ETH' },
// expiresAt: '2026-02-02T12:05:00Z',
// }
// Cross-chain swap: ETH (Ethereum) -> USDC (Polygon)
const crossChainQuote: SwapQuote = await engine.getSwapQuote({
fromToken: 'ETH',
fromChainId: 1,
toToken: 'USDC',
toChainId: 137,
amount: '0.5',
slippage: 1.0,
senderAddress: '0xAbc...',
});

console.log('Cross-chain route steps:', crossChainQuote.route.steps.length);
// Typically: swap ETH->USDC on Ethereum, bridge USDC to Polygon

executeSwap

使用之前获取的报价执行兑换。

const result: SwapResult = await engine.executeSwap({
quoteId: quote.quoteId,
senderAddress: '0xAbc...',
receiverAddress: '0xAbc...', // usually same as sender
});

console.log(result);
// {
// swapId: 'sw_xyz789',
// status: 'processing',
// txHash: '0x1234...',
// fromAmount: '1.0',
// toAmount: '2634.52',
// route: { ... },
// }

getSwapStatus

检查兑换的当前状态,对于耗时较长的跨链兑换尤其有用。

const status: SwapResult = await engine.getSwapStatus('sw_xyz789');

console.log(status.status); // 'processing' | 'completed' | 'failed'
console.log(status.txHash); // source chain tx hash
console.log(status.destinationTxHash); // dest chain tx hash (cross-chain only)

getSupportedSwapTokens

列出所有可用于兑换的代币,可选择按链过滤。

// All tokens across all chains
const allTokens: SwapToken[] = await engine.getSupportedSwapTokens();

// Tokens on Polygon only
const polygonTokens: SwapToken[] = await engine.getSupportedSwapTokens(137);

getSupportedSwapChains

列出所有支持兑换的链。

const chains = await engine.getSupportedSwapChains();
// [
// { chainId: 1, name: 'Ethereum', type: 'evm' },
// { chainId: 137, name: 'Polygon', type: 'evm' },
// { chainId: 42161, name: 'Arbitrum', type: 'evm' },
// ...
// ]

类型

interface SwapToken {
/** 代币符号 */
symbol: string;
/** 代币所在的链 ID */
chainId: number;
/** 合约地址(原生代币如 ETH 未定义) */
address?: string;
/** 代币精度 */
decimals?: number;
/** 显示名称 */
name?: string;
/** 代币 logo URL */
logoUrl?: string;
}

interface SwapQuoteRequest {
/** 源代币符号 */
fromToken: string;
/** 源链 ID */
fromChainId: number;
/** 目标代币符号 */
toToken: string;
/** 目标链 ID */
toChainId: number;
/** 兑换的源代币数量(人类可读) */
amount: string;
/** 滑点容忍度百分比(例如 0.5) */
slippage?: number;
/** 发起兑换的地址 */
senderAddress: string;
}

interface SwapQuote {
/** 服务器生成的报价标识符 */
quoteId: string;
/** 源代币详情 */
fromToken: SwapToken;
/** 目标代币详情 */
toToken: SwapToken;
/** 输入数量(人类可读) */
fromAmount: string;
/** 预估输出数量(人类可读) */
toAmount: string;
/** 兑换的最优路由 */
route: SwapRoute;
/** 手续费明细 */
fee: {
amount: string;
token: string;
};
/** ISO 8601 过期时间 */
expiresAt: string;
}

interface SwapRoute {
/** 兑换路由中的有序步骤 */
steps: SwapStep[];
/** 预估 gas(单位 wei) */
estimatedGas: string;
/** 价格影响百分比(例如 0.03 = 0.03%) */
priceImpact: number;
/** 预估执行时间(秒) */
estimatedTime?: number;
}

interface SwapStep {
/** 步骤类型 */
type: 'swap' | 'bridge' | 'approve';
/** 此步骤使用的协议或 DEX */
protocol: string;
/** 此步骤的源代币 */
fromToken: SwapToken;
/** 此步骤的目标代币 */
toToken: SwapToken;
/** 此步骤的输入数量 */
fromAmount: string;
/** 此步骤的预期输出 */
toAmount: string;
/** 此步骤执行所在的链 ID */
chainId: number;
}

interface SwapExecuteRequest {
/** 来自 getSwapQuote 的报价 ID */
quoteId: string;
/** 执行兑换的地址 */
senderAddress: string;
/** 接收输出代币的地址(默认为发送者) */
receiverAddress?: string;
}

interface SwapResult {
/** 唯一兑换标识符 */
swapId: string;
/** 当前状态 */
status: 'pending' | 'processing' | 'completed' | 'failed';
/** 源链交易哈希 */
txHash?: string;
/** 目标链交易哈希(仅跨链兑换) */
destinationTxHash?: string;
/** 实际输入数量 */
fromAmount: string;
/** 实际(或预估)输出数量 */
toAmount: string;
/** 执行的路由 */
route: SwapRoute;
/** 源代币 */
fromToken: SwapToken;
/** 目标代币 */
toToken: SwapToken;
/** ISO 8601 创建时间戳 */
createdAt: string;
/** ISO 8601 最后更新时间戳 */
updatedAt: string;
}

完整示例:同链兑换

import { OneEngineClient } from '@one_deploy/sdk';

const engine = new OneEngineClient({
apiKey: process.env.ONE_API_KEY!,
projectId: process.env.ONE_PROJECT_ID!,
});

async function swapETHtoUSDC(wallet: string) {
// 1. Get a quote
const quote = await engine.getSwapQuote({
fromToken: 'ETH',
fromChainId: 1,
toToken: 'USDC',
toChainId: 1,
amount: '0.5',
slippage: 0.5,
senderAddress: wallet,
});

console.log(`Swap 0.5 ETH -> ~${quote.toAmount} USDC`);
console.log(`Route: ${quote.route.steps.map((s) => s.protocol).join(' -> ')}`);
console.log(`Price impact: ${quote.route.priceImpact}%`);

// 2. Execute the swap
const result = await engine.executeSwap({
quoteId: quote.quoteId,
senderAddress: wallet,
});

// 3. Wait for completion
let status = await engine.getSwapStatus(result.swapId);
while (status.status === 'pending' || status.status === 'processing') {
await new Promise((r) => setTimeout(r, 3000));
status = await engine.getSwapStatus(result.swapId);
}

console.log(`Swap ${status.status}: received ${status.toAmount} USDC`);
console.log(`Tx: ${status.txHash}`);
}

完整示例:跨链兑换

async function crossChainSwap(wallet: string) {
// ETH on Ethereum -> USDC on Polygon
const quote = await engine.getSwapQuote({
fromToken: 'ETH',
fromChainId: 1,
toToken: 'USDC',
toChainId: 137,
amount: '1.0',
slippage: 1.0,
senderAddress: wallet,
});

console.log(`Cross-chain: 1 ETH (Ethereum) -> ~${quote.toAmount} USDC (Polygon)`);
console.log(`Steps: ${quote.route.steps.length}`);

quote.route.steps.forEach((step, i) => {
console.log(
` Step ${i + 1}: ${step.type} via ${step.protocol} -- ` +
`${step.fromAmount} ${step.fromToken.symbol} -> ${step.toAmount} ${step.toToken.symbol}`
);
});

console.log(`Estimated time: ${quote.route.estimatedTime}s`);

// Execute
const result = await engine.executeSwap({
quoteId: quote.quoteId,
senderAddress: wallet,
receiverAddress: wallet,
});

// Poll -- cross-chain swaps may take longer
let status = await engine.getSwapStatus(result.swapId);
while (status.status === 'pending' || status.status === 'processing') {
await new Promise((r) => setTimeout(r, 10000));
status = await engine.getSwapStatus(result.swapId);
console.log(`Status: ${status.status}`);
}

console.log(`Done: ${status.toAmount} USDC on Polygon`);
console.log(`Source tx: ${status.txHash}`);
console.log(`Destination tx: ${status.destinationTxHash}`);
}

参见