npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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 库(如 wagmiviem)无缝集成。
  • 多功能性:支持跨链桥接、智能合约调用、代币交换等多种操作。

本 SDK 支持 Ethereum、Polygon、Arbitrum 等主流链,适用于 2025 年快速增长的 L3 网络(如 Degen Chain)。

2. 安装与初始化

2.1 安装

确保你的项目使用 React 16.8 或以上版本,并已安装 Node.js 和 npm。运行以下命令安装 SDK:

npm install gatex-sdk-hooks

2.2 依赖

Gatex-SDK-Hooks 需要以下依赖:

核心依赖

  • viem:用于处理区块链数据(如金额转换)。
  • wagmi:用于钱包连接和交易签名。
  • reactreact-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 初始化要点

  1. Provider 嵌套顺序:Solana Provider → QueryClient Provider → Wagmi Provider → RainbowKit Provider
  2. 固定配置:避免在每次渲染时重新创建配置对象
  3. 链列表缓存:将链列表保存到本地存储,避免重复请求
  4. 错误处理:为链列表获取添加适当的错误处理

3. 可用的 Hooks

以下是 Gatex-SDK-Hooks 提供的核心 Hooks,每个 Hook 都返回标准化的状态对象(dataloadingerror)和操作函数。

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-toastifysonner)显示用户友好的错误提示。

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

  1. 为什么 fetchData 返回空数据?
  • 确保已正确配置 API 密钥和桥接参数。
  • 检查网络连接或 API 服务器状态。
  1. 转账失败提示"余额不足"?
  • 验证用户钱包是否有足够的代币和 gas 费用。
  • 使用 useCrossChainFee 检查费用要求。
  1. 跨链交易需要多久?
  • 通常 1-5 分钟,取决于源链和目标链的确认速度。
  1. 如何调试交易失败?
  • 检查 error 对象的详细信息。
  • 使用区块链浏览器(如 Etherscan)跟踪 source_tx_hash
  1. 智能合约调用失败怎么办?

    • 检查合约地址是否正确。
    • 验证 ABI 是否与合约匹配。
    • 确保函数参数类型和数量正确。
  2. 代币交换失败的原因?

    • 检查代币是否已授权。
    • 验证滑点设置是否合理。
    • 确保有足够的代币余额。

调试建议

  • 日志记录:在 fetchDatatransfer 中添加 console.log 打印输入和输出。
  • 测试网络:在测试网(如 Sepolia)上验证功能,降低成本。
  • 状态跟踪:使用 loading 状态显示加载动画,避免重复操作。
  • 错误边界:使用 React Error Boundary 捕获组件错误。

8. 最佳实践

  1. 桥接配置:调用 transfer 前,必须通过 configureBridge 设置桥接参数,否则交易会失败。

  2. 钱包连接:确保用户已连接钱包(如 MetaMask)并有足够的代币和 gas 费用。

  3. 金额处理:使用 parseUnitsformatUnits 处理代币小数位,避免精度问题。

  4. 交易状态:跨链交易可能因网络延迟而较慢,建议显示进度条或状态更新。

  5. 安全检查:验证输入的地址和金额,防止用户误操作。

  6. 用户体验:提供清晰的加载状态和错误提示,优化用户交互。

  7. 代币图标:使用 getTokenIcon 辅助函数处理代币图标显示,支持多种图标源。

  8. 历史记录:保存用户选择的代币历史,提升用户体验。

9. 许可证

MIT License