gatex-sdk-hooks
v1.0.64
Published
React hooks for API data fetching and blockchain interaction
Downloads
20
Readme
Gatex-SDK-Hooks 使用文档
1. 简介
Gatex-SDK-Hooks 是一个专为 React 开发者设计的跨链操作库,旨在简化区块链跨链交互的开发流程。它基于 React Hooks 提供直观的接口,支持查询区块链网络信息、代币详情、计算跨链交易费用、执行跨链转账、调用智能合约函数以及代币交换等功能。无论是构建去中心化金融(DeFi)应用、NFT 市场还是跨链桥接工具,Gatex-SDK-Hooks 都能帮助开发者快速实现功能。
核心优势
- 简单易用:通过 Hooks 封装复杂逻辑,开发者无需深入了解跨链协议细节。
- 高灵活性:支持多种区块链网络和代币,适配不同跨链场景。
- 实时反馈:提供加载状态和错误信息,优化用户体验。
- 可扩展性:与主流 Web3 库(如
wagmi、viem)无缝集成。 - 多功能性:支持跨链桥接、智能合约调用、代币交换等多种操作。
本 SDK 支持 Ethereum、Polygon、Arbitrum 等主流链,适用于 2025 年快速增长的 L3 网络(如 Degen Chain)。
2. 安装与初始化
2.1 安装
确保你的项目使用 React 16.8 或以上版本,并已安装 Node.js 和 npm。运行以下命令安装 SDK:
npm install gatex-sdk-hooks2.2 依赖
Gatex-SDK-Hooks 需要以下依赖:
核心依赖
viem:用于处理区块链数据(如金额转换)。wagmi:用于钱包连接和交易签名。react和react-dom:React 核心库。@tanstack/react-query:用于数据查询和缓存。
EVM 链支持
@rainbow-me/rainbowkit:用于 EVM 钱包连接 UI。
Solana 链支持(可选)
@solana/wallet-adapter-react:Solana 钱包适配器核心。@solana/wallet-adapter-react-ui:Solana 钱包连接 UI。@solana/wallet-adapter-wallets:Solana 钱包适配器。@solana/web3.js:Solana Web3 库。
2.3 初始化
在应用入口(如 App.jsx)中配置 Web3 提供者并初始化 SDK:
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import { RainbowKitProvider } from "@rainbow-me/rainbowkit";
import { WagmiProvider } from "wagmi";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import "@rainbow-me/rainbowkit/styles.css";
// Solana 钱包相关导入
import {
WalletModalProvider as SolanaWalletModalProvider
} from '@solana/wallet-adapter-react-ui';
import {
WalletProvider as SolanaWalletProvider,
ConnectionProvider as SolanaConnectionProvider,
} from '@solana/wallet-adapter-react';
import { WalletAdapterNetwork as SolanaWalletAdapterNetwork } from '@solana/wallet-adapter-base';
import { PhantomWalletAdapter, SolflareWalletAdapter } from '@solana/wallet-adapter-wallets';
import { clusterApiUrl } from '@solana/web3.js';
// 创建 QueryClient 实例
const queryClient = new QueryClient();
// 路由配置
const router = createBrowserRouter([
{
path: "/",
element: <Directory />,
},
// 其他路由...
]);
// 固定配置信息
const fixedConfig = {
supportedChains: defaultChains, // 从配置文件导入
wagmiConfig: initialConfig // 从配置文件导入
};
function App() {
// 使用固定配置,避免重新创建
const [config] = useState(fixedConfig);
// Solana 配置
const network = SolanaWalletAdapterNetwork.Mainnet;
const endpoint = clusterApiUrl(network);
const wallets = [
new PhantomWalletAdapter(),
new SolflareWalletAdapter(),
];
return (
<SolanaConnectionProvider endpoint={endpoint}>
<SolanaWalletProvider wallets={wallets} autoConnect>
<SolanaWalletModalProvider>
<QueryClientProvider client={queryClient}>
<WagmiProvider config={config.wagmiConfig}>
<RainbowKitProvider chains={config.supportedChains}>
<RouterProvider router={router} />
</RainbowKitProvider>
</WagmiProvider>
</QueryClientProvider>
</SolanaWalletModalProvider>
</SolanaWalletProvider>
</SolanaConnectionProvider>
);
}
export default App;2.4 最小化配置示例
如果你只需要基本的 EVM 链支持:
import { WagmiConfig, createConfig, http } from 'wagmi';
import { mainnet, polygon } from 'wagmi/chains';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
const wagmiConfig = createConfig({
chains: [mainnet, polygon],
transports: {
[mainnet.id]: http(),
[polygon.id]: http(),
},
});
function App() {
return (
<QueryClientProvider client={queryClient}>
<WagmiConfig config={wagmiConfig}>
{/* 你的应用内容 */}
</WagmiConfig>
</QueryClientProvider>
);
}2.6 初始化要点
- Provider 嵌套顺序:Solana Provider → QueryClient Provider → Wagmi Provider → RainbowKit Provider
- 固定配置:避免在每次渲染时重新创建配置对象
- 链列表缓存:将链列表保存到本地存储,避免重复请求
- 错误处理:为链列表获取添加适当的错误处理
3. 可用的 Hooks
以下是 Gatex-SDK-Hooks 提供的核心 Hooks,每个 Hook 都返回标准化的状态对象(data、loading、error)和操作函数。
3.1 useChainList
获取支持的区块链网络列表,例如 Ethereum、Polygon 等。
返回值
data: Chain[]- 链信息数组,包含 ID、名称、链选择器ID 和桥接合约地址。loading: boolean- 是否正在加载。error: Error | null- 错误信息。fetchData: () => Promise<void>- 手动触发数据获取。
使用场景
- 显示链选择下拉菜单。
- 初始化跨链交易配置。
示例
import { useChainList } from 'gatex-sdk-hooks';
import { useEffect } from 'react';
function ChainSelector() {
const { data: chainList, loading, error, fetchData } = useChainList();
useEffect(() => {
fetchData(); // 组件挂载时获取链列表
}, []);
if (loading) return <div>Loading chains...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<select>
{chainList?.map((chain) => (
<option key={chain.id} value={chain.id}>
{chain.chainName}
</option>
))}
</select>
);
}3.2 useTokenList
获取指定链上的代币列表,支持搜索和推荐代币功能。
返回值
data: Token[]- 代币信息数组,包含地址、名称、符号和小数位数。loading: boolean- 是否正在加载。error: Error | null- 错误信息。fetchData: (params: TokenListParams) => Promise<Token[]>- 获取代币列表的函数。
参数 (TokenListParams)
chainId?: string- 链 ID(可选,不传则获取所有链的代币)。keyword?: string- 搜索关键词(可选)。recommend?: number- 推荐代币标识(0 表示获取推荐代币)。
使用场景
- 构建代币选择器。
- 显示用户余额或代币图标。
- 搜索特定代币。
示例
import { useTokenList } from 'gatex-sdk-hooks';
import { useEffect, useState } from 'react';
function TokenSelector({ chainId }) {
const [searchQuery, setSearchQuery] = useState('');
const { data: tokenList, loading, error, fetchData } = useTokenList();
// 获取推荐代币
const fetchRecommendedTokens = async () => {
const result = await fetchData({
chainId: chainId,
recommend: 0
});
console.log('Recommended tokens:', result);
};
// 搜索代币
const searchTokens = async (keyword) => {
const result = await fetchData({
chainId: chainId,
keyword: keyword
});
console.log('Search results:', result);
};
useEffect(() => {
fetchRecommendedTokens();
}, [chainId]);
return (
<div>
<input
placeholder="Search tokens..."
onChange={(e) => searchTokens(e.target.value)}
/>
{tokenList?.map((token) => (
<div key={token.address}>
{token.symbol} - {token.name}
</div>
))}
</div>
);
}3.3 useTokenBalance
获取指定代币的余额信息。
返回值
balance: string- 代币余额。symbol: string- 代币符号。isLoading: boolean- 是否正在加载。refetch: () => void- 重新获取余额。
参数
tokenAddress: string- 代币合约地址。options: BalanceOptions- 余额查询选项。
参数 (BalanceOptions)
walletAddress: string- 钱包地址。evmChainId?: string- EVM 链 ID。solanaEndpoint?: string- Solana RPC 端点。
示例
import { useTokenBalance } from 'gatex-sdk-hooks';
function TokenBalance({ tokenAddress, walletAddress, chainId }) {
const {
balance,
symbol,
isLoading,
refetch
} = useTokenBalance(tokenAddress, {
walletAddress,
evmChainId: chainId
});
return (
<div>
<p>Balance: {isLoading ? 'Loading...' : balance} {symbol}</p>
<button onClick={refetch}>Refresh</button>
</div>
);
}3.4 useCrossChainFee
计算跨链交易的费用。
返回值
data: FeeData- 费用数据,包含路由结果和最小接收金额。loading: boolean- 是否正在加载。error: Error | null- 错误信息。fetchData: (params: FeeParams) => Promise<FeeData>- 计算费用的函数。
参数 (FeeParams)
sourceChain: string- 源链 ID。destChain: string- 目标链 ID。sourceToken: string- 源代币地址。destToken: string- 目标代币地址。amount: string- 转账金额(Wei 或代币单位)。to: string- 接收地址。
使用场景
- 显示跨链转账的预期费用和接收金额。
- 验证交易是否可行。
示例
import { useCrossChainFee } from 'gatex-sdk-hooks';
import { parseUnits, formatUnits } from 'viem';
function FeeCalculator({ sourceChainId, destChainId, sourceToken, destToken, amount, decimals, recipient }) {
const { data: feeData, loading, error, fetchData } = useCrossChainFee();
const calculateFee = async () => {
try {
const result = await fetchData({
sourceChain: sourceChainId,
destChain: destChainId,
sourceToken,
destToken,
amount: String(parseUnits(amount, decimals)),
to: recipient,
});
if (result.routerResult) {
const destAmount = formatUnits(result.routerResult.destMinAmount, decimals);
console.log(`Expected receive amount: ${destAmount}`);
}
} catch (err) {
console.error('Fee calculation failed:', err);
}
};
return (
<div>
<button onClick={calculateFee} disabled={loading}>
{loading ? 'Calculating...' : 'Calculate Fee'}
</button>
{feeData && <div>Min Receive: {formatUnits(feeData.routerResult.destMinAmount, decimals)}</div>}
{error && <div>Error: {error.message}</div>}
</div>
);
}3.5 useCrossChainTransfer
执行跨链转账交易。
返回值
transfer: (params: TransferParams) => Promise<void>- 执行转账的函数。data: TransferData | null- 转账结果数据。loading: boolean- 是否正在执行。error: Error | null- 错误信息。
参数 (TransferParams)
sourceChain: string- 源链 ID。destChain: string- 目标链 ID。sourceToken: string- 源代币地址。destToken: string- 目标代币地址。amount: bigint- 转账金额(Wei 或代币单位)。to: string- 接收地址。routerResult: object- 从useCrossChainFee获取的路由结果。
使用场景
- 实现跨链转账按钮。
- 跟踪交易状态。
示例
import { useCrossChainTransfer } from 'gatex-sdk-hooks';
import { parseUnits } from 'viem';
function TransferButton({ sourceChainId, destChainId, sourceToken, destToken, amount, decimals, recipient, routerResult }) {
const { transfer, data, loading, error } = useCrossChainTransfer();
const handleTransfer = async () => {
try {
await transfer({
sourceChain: sourceChainId,
destChain: destChainId,
sourceToken,
destToken,
amount: parseUnits(amount, decimals),
to: recipient,
...routerResult,
});
} catch (err) {
console.error('Transfer failed:', err);
}
};
return (
<div>
<button onClick={handleTransfer} disabled={loading}>
{loading ? 'Transferring...' : 'Start Transfer'}
</button>
{data && <div>Tx Hash: {data.source_tx_hash}</div>}
{error && <div>Error: {error.message}</div>}
</div>
);
}3.6 useEVMFunction
调用智能合约函数,支持读写操作。
返回值
execute: (params: ExecuteParams) => Promise<void>- 执行合约函数的函数。estimateGas: (params: EstimateParams) => Promise<GasEstimate>- 估算 Gas 的函数。data: ExecuteData | null- 执行结果数据。loading: boolean- 是否正在执行。error: Error | null- 错误信息。
参数 (ExecuteParams)
contractAddress: string- 合约地址。functionName: string- 函数名称。args: any[]- 函数参数。chainId: string- 链 ID。abi: any[]- 合约 ABI。value?: bigint- 发送的 ETH 数量(仅用于 payable 函数)。
参数 (EstimateParams)
contractAddress: string- 合约地址。functionName: string- 函数名称。abi: any[]- 合约 ABI。args: any[]- 函数参数。value?: bigint- 发送的 ETH 数量。
使用场景
- 调用智能合约函数。
- 估算交易 Gas 费用。
- 执行复杂的合约交互。
示例
import { useEVMFunction } from 'gatex-sdk-hooks';
import { parseUnits } from 'viem';
function ContractInteraction({ contractAddress, abi, chainId }) {
const {
execute,
estimateGas,
data,
loading,
error
} = useEVMFunction();
const handleExecute = async () => {
try {
await execute({
contractAddress,
functionName: 'transfer',
args: ['0x123...', parseUnits('100', 18)],
chainId,
abi
});
} catch (err) {
console.error('Function execution failed:', err);
}
};
const handleEstimateGas = async () => {
try {
const estimate = await estimateGas({
contractAddress,
functionName: 'transfer',
abi,
args: ['0x123...', parseUnits('100', 18)]
});
console.log('Gas estimate:', estimate);
} catch (err) {
console.error('Gas estimation failed:', err);
}
};
return (
<div>
<button onClick={handleEstimateGas}>Estimate Gas</button>
<button onClick={handleExecute} disabled={loading}>
{loading ? 'Executing...' : 'Execute Function'}
</button>
{data && <div>Success! Hash: {data.hash}</div>}
{error && <div>Error: {error.message}</div>}
</div>
);
}3.7 useContractAbi
获取智能合约的 ABI。
返回值
loading: boolean- 是否正在加载。error: Error | null- 错误信息。fetchData: (params: AbiParams) => Promise<string>- 获取 ABI 的函数。
参数 (AbiParams)
chainId: string- 链 ID。address: string- 合约地址。
使用场景
- 动态获取合约 ABI。
- 支持合约交互。
示例
import { useContractAbi } from 'gatex-sdk-hooks';
function AbiLoader({ contractAddress, chainId }) {
const { loading, error, fetchData } = useContractAbi();
const loadAbi = async () => {
try {
const abi = await fetchData({ chainId, address: contractAddress });
console.log('Contract ABI:', JSON.parse(abi));
} catch (err) {
console.error('Failed to load ABI:', err);
}
};
return (
<div>
<button onClick={loadAbi} disabled={loading}>
{loading ? 'Loading ABI...' : 'Load ABI'}
</button>
{error && <div>Error: {error.message}</div>}
</div>
);
}3.8 useSwap
执行代币交换操作。
返回值
swap: (params: SwapParams) => Promise<void>- 执行交换的函数。getQuote: (params: QuoteParams) => Promise<SwapQuote>- 获取交换报价的函数。status: string- 交换状态('idle', 'approving', 'swapping', 'success', 'error')。error: Error | null- 错误信息。reset: () => void- 重置状态。
参数 (SwapParams)
sourceToken: string- 源代币地址。destToken: string- 目标代币地址。amountIn: string- 输入金额。
参数 (QuoteParams)
sourceToken: string- 源代币地址。destToken: string- 目标代币地址。amountIn: string- 输入金额。
使用场景
- 实现代币交换功能。
- 获取交换报价。
- 跟踪交换状态。
示例
import { useSwap } from 'gatex-sdk-hooks';
function TokenSwap({ sourceToken, destToken }) {
const [amountIn, setAmountIn] = useState('');
const [quote, setQuote] = useState(null);
const {
swap,
getQuote,
status,
error,
reset
} = useSwap();
const handleGetQuote = async () => {
try {
const result = await getQuote({
sourceToken,
destToken,
amountIn
});
setQuote(result);
} catch (err) {
console.error('Failed to get quote:', err);
}
};
const handleSwap = async () => {
try {
await swap({
sourceToken,
destToken,
amountIn
});
} catch (err) {
console.error('Swap failed:', err);
}
};
return (
<div>
<input
value={amountIn}
onChange={(e) => setAmountIn(e.target.value)}
placeholder="Enter amount"
/>
<button onClick={handleGetQuote}>Get Quote</button>
{quote && (
<div>
<p>Expected output: {quote.amountOutFormatted}</p>
<button onClick={handleSwap} disabled={status !== 'idle'}>
{status === 'approving' ? 'Approving...' :
status === 'swapping' ? 'Swapping...' : 'Swap'}
</button>
</div>
)}
{error && <div>Error: {error.message}</div>}
</div>
);
}3.9 useCrossChainInfo
查询跨链交易信息,用于交易历史或浏览器。
返回值
data: Transaction[]- 交易数据数组。loading: boolean- 是否正在加载。error: Error | null- 错误信息。fetchData: (params: InfoParams) => Promise<Transaction[]>- 获取交易数据的函数。
参数 (InfoParams)
addressOrTxHash: string- 钱包地址或交易哈希。pageNo: number- 页码。pageSize: number- 每页数量。sortName: string- 排序字段(如id)。sortOrder: 'asc' | 'desc'- 排序顺序。
使用场景
- 构建交易历史页面。
- 显示单笔交易详情。
示例
import { useCrossChainInfo } from 'gatex-sdk-hooks';
function TransactionHistory({ address }) {
const { data, loading, error, fetchData } = useCrossChainInfo();
const fetchTransactions = () => {
fetchData({
addressOrTxHash: address,
pageNo: 1,
pageSize: 10,
sortName: 'id',
sortOrder: 'desc',
});
};
return (
<div>
<button onClick={fetchTransactions}>Load Transactions</button>
{loading && <div>Loading...</div>}
{error && <div>Error: {error.message}</div>}
{data?.map((tx) => (
<div key={tx.message_id}>
{tx.source_chain_name} → {tx.dest_chain_name}: {tx.send_amount} {tx.source_token_symbol}
</div>
))}
</div>
);
}3.10 configureBridge
配置桥接合约地址和链选择器,通常在应用初始化时调用。
参数
chainSelectors: Record<string, string>- 链 ID 到链选择器 ID 的映射。contractAddresses: Record<string, string>- 链 ID 到桥接合约地址的映射。
使用场景
- 初始化跨链桥接参数。
- 确保交易使用正确的桥接合约。
示例
import { configureBridge } from 'gatex-sdk-hooks';
function AppInitializer({ chainList }) {
useEffect(() => {
configureBridge({
chainSelectors: chainList.reduce((acc, chain) => {
acc[chain.id] = chain.ccipChainId;
return acc;
}, {}),
contractAddresses: chainList.reduce((acc, chain) => {
acc[chain.id] = chain.bridge;
return acc;
}, {}),
});
}, [chainList]);
return null;
}4. 完整使用流程示例
以下是一个完整的跨链转账应用,展示如何整合所有 Hooks,并包含 UI 交互。
import { useState, useEffect } from 'react';
import {
useChainList,
useTokenList,
useCrossChainFee,
useCrossChainTransfer,
useTokenBalance,
configureBridge
} from 'gatex-sdk-hooks';
import { parseUnits, formatUnits } from 'viem';
function CrossChainApp() {
// 状态管理
const [sourceChainId, setSourceChainId] = useState('');
const [destChainId, setDestChainId] = useState('');
const [sourceToken, setSourceToken] = useState('');
const [destToken, setDestToken] = useState('');
const [amount, setAmount] = useState('');
const [recipient, setRecipient] = useState('');
const [destAmount, setDestAmount] = useState('');
// Hooks 初始化
const { data: chainList, fetchData: fetchChainList } = useChainList();
const { data: tokenList, fetchData: fetchTokenList } = useTokenList();
const { data: feeData, fetchData: fetchFee, loading: feeLoading } = useCrossChainFee();
const { transfer, loading: transferLoading, error: transferError } = useCrossChainTransfer();
const { balance: sourceBalance, symbol: sourceSymbol } = useTokenBalance(sourceToken, {
walletAddress: '0x...',
evmChainId: sourceChainId
});
// 获取链和代币列表
useEffect(() => {
fetchChainList();
fetchTokenList();
}, []);
// 配置桥接
useEffect(() => {
if (chainList) {
configureBridge({
chainSelectors: chainList.reduce((acc, chain) => {
acc[chain.id] = chain.ccipChainId;
return acc;
}, {}),
contractAddresses: chainList.reduce((acc, chain) => {
acc[chain.id] = chain.bridge;
return acc;
}, {}),
});
}
}, [chainList]);
// 计算费用
const calculateFee = async () => {
try {
const decimals = tokenList?.find((t) => t.address === sourceToken)?.decimals || 18;
const result = await fetchFee({
sourceChain: sourceChainId,
destChain: destChainId,
sourceToken,
destToken,
amount: String(parseUnits(amount, decimals)),
to: recipient,
});
if (result.routerResult) {
const receiveAmount = formatUnits(result.routerResult.destMinAmount, decimals);
setDestAmount(receiveAmount);
}
} catch (err) {
console.error('Fee calculation failed:', err);
}
};
// 执行转账
const handleTransfer = async () => {
try {
const decimals = tokenList?.find((t) => t.address === sourceToken)?.decimals || 18;
await transfer({
sourceChain: sourceChainId,
destChain: destChainId,
sourceToken,
destToken,
amount: parseUnits(amount, decimals),
to: recipient,
...feeData?.routerResult,
});
alert('Transfer successful!');
} catch (err) {
console.error('Transfer failed:', err);
alert('Transfer failed: ' + err.message);
}
};
return (
<div style={{ padding: '20px', maxWidth: '600px', margin: 'auto' }}>
<h2>Cross-Chain Transfer</h2>
{/* 源链选择 */}
<div>
<label>Source Chain</label>
<select value={sourceChainId} onChange={(e) => setSourceChainId(e.target.value)}>
<option value="">Select Chain</option>
{chainList?.map((chain) => (
<option key={chain.id} value={chain.id}>{chain.chainName}</option>
))}
</select>
</div>
{/* 目标链选择 */}
<div>
<label>Destination Chain</label>
<select value={destChainId} onChange={(e) => setDestChainId(e.target.value)}>
<option value="">Select Chain</option>
{chainList?.map((chain) => (
<option key={chain.id} value={chain.id}>{chain.chainName}</option>
))}
</select>
</div>
{/* 源代币选择 */}
<div>
<label>Source Token</label>
<select value={sourceToken} onChange={(e) => setSourceToken(e.target.value)}>
<option value="">Select Token</option>
{tokenList?.filter((t) => t.chain_id === sourceChainId).map((token) => (
<option key={token.address} value={token.address}>{token.name}</option>
))}
</select>
{sourceBalance && <span>Balance: {sourceBalance} {sourceSymbol}</span>}
</div>
{/* 目标代币选择 */}
<div>
<label>Destination Token</label>
<select value={destToken} onChange={(e) => setDestToken(e.target.value)}>
<option value="">Select Token</option>
{tokenList?.filter((t) => t.chain_id === destChainId).map((token) => (
<option key={token.address} value={token.address}>{token.name}</option>
))}
</select>
</div>
{/* 金额输入 */}
<div>
<label>Amount</label>
<input
type="text"
value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="Enter amount"
/>
</div>
{/* 接收地址 */}
<div>
<label>Recipient Address</label>
<input
type="text"
value={recipient}
onChange={(e) => setRecipient(e.target.value)}
placeholder="Enter recipient address"
/>
</div>
{/* 计算费用按钮 */}
<button onClick={calculateFee} disabled={feeLoading || !amount || !recipient}>
{feeLoading ? 'Calculating...' : 'Calculate Fee'}
</button>
{/* 预期接收金额 */}
{destAmount && <div>Expected Receive: {destAmount}</div>}
{/* 转账按钮 */}
<button onClick={handleTransfer} disabled={transferLoading || !feeData}>
{transferLoading ? 'Transferring...' : 'Transfer'}
</button>
{/* 错误信息 */}
{transferError && <div style={{ color: 'red' }}>Error: {transferError.message}</div>}
</div>
);
}5. 数据结构说明
5.1 链列表数据结构
描述支持的区块链网络。
interface Chain {
id: string; // 链 ID,例如 '1'(Ethereum)
chainName: string; // 链名称,例如 'Ethereum Mainnet'
ccipChainId: string; // CCIP 链 ID,例如 '5009297550715157269'
bridge: string; // 桥接合约地址,例如 '0x1234...5678'
cctpBridge?: string; // CCTP 桥接合约地址(可选)
domain?: string; // CCTP 域(可选)
rpcUrl?: string; // 链 RPC 地址(可选)
}示例
{
"id": "1",
"chainName": "Ethereum Mainnet",
"ccipChainId": "5009297550715157269",
"bridge": "0x1234567890abcdef1234567890abcdef12345678",
"cctpBridge": "0x9876543210fedcba9876543210fedcba98765432",
"domain": "0"
}5.2 代币列表数据结构
描述链上的代币信息。
interface Token {
address: string; // 代币合约地址,例如 '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
chain_id: string; // 所在链 ID,例如 '1'
name: string; // 代币名称,例如 'USD Coin'
symbol: string; // 代币符号,例如 'USDC'
decimals: number; // 小数位数,例如 6
img_src?: string; // 代币图标 URL(可选)
image_url?: string; // 代币图标 URL(备用字段)
}示例
{
"address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"chain_id": "1",
"name": "USD Coin",
"symbol": "USDC",
"decimals": 6,
"img_src": "https://example.com/usdc.png"
}5.3 交换报价数据结构
描述代币交换的报价信息。
interface SwapQuote {
amountOutFormatted: string; // 格式化后的输出金额
minAmountOutFormatted: string; // 格式化后的最小输出金额
totalCostFormatted: string; // 格式化后的总成本
gasEstimate: bigint; // Gas 估算
gasPrice: bigint; // Gas 价格
priceImpact?: string; // 价格影响(可选)
route?: string[]; // 交换路径(可选)
}示例
{
"amountOutFormatted": "99.5",
"minAmountOutFormatted": "99.0",
"totalCostFormatted": "100.0",
"gasEstimate": "210000",
"gasPrice": "20000000000",
"priceImpact": "0.1%",
"route": ["USDC", "ETH"]
}5.4 Gas 估算数据结构
描述智能合约调用的 Gas 估算信息。
interface GasEstimate {
gasLimit: string; // Gas 限制
gasCostETH: string; // 估算的 ETH 成本
gasPrice: string; // Gas 价格
}示例
{
"gasLimit": "210000",
"gasCostETH": "0.0042",
"gasPrice": "20000000000"
}5.5 跨链交易数据结构
描述跨链交易的详细信息。
interface Transaction {
message_id: string; // 交易 ID,例如 '0xabc123'
source_tx_hash: string; // 源链交易哈希,例如 '0xdef456'
dest_tx_hash?: string; // 目标链交易哈希(可选)
source_chain_name: string; // 源链名称,例如 'Ethereum'
dest_chain_name: string; // 目标链名称,例如 'Polygon'
from_address: string; // 发送地址,例如 '0x123...'
to_address: string; // 接收地址,例如 '0x456...'
status: string; // 交易状态,例如 'pending'、'completed'
send_amount: string; // 发送金额,例如 '1000000'(Wei/代币单位)
receive_amount?: string; // 接收金额(可选)
source_token_symbol: string; // 源代币符号,例如 'USDC'
dest_token_symbol?: string; // 目标代币符号(可选)
source_token_decimals: number; // 源代币小数位,例如 6
dest_token_decimals?: number; // 目标代币小数位(可选)
ccip_fee: string; // CCIP 费用,例如 '1000000000000000'
bridge_fee: string; // 桥接费用,例如 '500000000000000'
fee_decimals: number; // 费用代币小数位,例如 18
fee_symbol: string; // 费用代币符号,例如 'ETH'
start_time: string; // 开始时间,例如 '2025-04-01T12:00:00Z'
end_time?: string; // 完成时间(可选)
}示例
{
"message_id": "0xabc123",
"source_tx_hash": "0xdef456",
"dest_tx_hash": "0xghi789",
"source_chain_name": "Ethereum",
"dest_chain_name": "Polygon",
"from_address": "0x1234567890abcdef1234567890abcdef12345678",
"to_address": "0x4567890abcdef1234567890abcdef1234567890",
"status": "completed",
"send_amount": "1000000",
"receive_amount": "995000",
"source_token_symbol": "USDC",
"dest_token_symbol": "USDC",
"source_token_decimals": 6,
"dest_token_decimals": 6,
"ccip_fee": "1000000000000000",
"bridge_fee": "500000000000000",
"fee_decimals": 18,
"fee_symbol": "ETH",
"start_time": "2025-04-01T12:00:00Z",
"end_time": "2025-04-01T12:05:00Z"
}6. 错误处理
每个 Hook 返回的 error 对象包含错误详情,建议使用 UI 库(如 react-toastify 或 sonner)显示用户友好的错误提示。
import { toast } from 'sonner';
function ErrorHandler({ error }) {
useEffect(() => {
if (error) {
toast.error('Operation failed', {
description: error.message || error.msg || 'Please try again later',
});
}
}, [error]);
return null;
}常见错误
- 网络错误:API 请求失败,检查网络连接或 API 状态。
- 余额不足:用户钱包代币不足,提示用户充值。
- 参数错误:输入的链 ID、代币地址或金额格式错误,验证输入。
- 合约错误:智能合约调用失败,检查合约地址和 ABI。
- Gas 不足:Gas 费用不足,提示用户增加 Gas 限制。
7. 常见问题与调试
FAQ
- 为什么
fetchData返回空数据?
- 确保已正确配置 API 密钥和桥接参数。
- 检查网络连接或 API 服务器状态。
- 转账失败提示"余额不足"?
- 验证用户钱包是否有足够的代币和 gas 费用。
- 使用
useCrossChainFee检查费用要求。
- 跨链交易需要多久?
- 通常 1-5 分钟,取决于源链和目标链的确认速度。
- 如何调试交易失败?
- 检查
error对象的详细信息。 - 使用区块链浏览器(如 Etherscan)跟踪
source_tx_hash。
智能合约调用失败怎么办?
- 检查合约地址是否正确。
- 验证 ABI 是否与合约匹配。
- 确保函数参数类型和数量正确。
代币交换失败的原因?
- 检查代币是否已授权。
- 验证滑点设置是否合理。
- 确保有足够的代币余额。
调试建议
- 日志记录:在
fetchData和transfer中添加console.log打印输入和输出。 - 测试网络:在测试网(如 Sepolia)上验证功能,降低成本。
- 状态跟踪:使用
loading状态显示加载动画,避免重复操作。 - 错误边界:使用 React Error Boundary 捕获组件错误。
8. 最佳实践
桥接配置:调用
transfer前,必须通过configureBridge设置桥接参数,否则交易会失败。钱包连接:确保用户已连接钱包(如 MetaMask)并有足够的代币和 gas 费用。
金额处理:使用
parseUnits和formatUnits处理代币小数位,避免精度问题。交易状态:跨链交易可能因网络延迟而较慢,建议显示进度条或状态更新。
安全检查:验证输入的地址和金额,防止用户误操作。
用户体验:提供清晰的加载状态和错误提示,优化用户交互。
代币图标:使用
getTokenIcon辅助函数处理代币图标显示,支持多种图标源。历史记录:保存用户选择的代币历史,提升用户体验。
9. 许可证
MIT License
