跳转到主要内容
本指南将带您完成通过 LI.FI REST API 直接集成 Composer。这种方法让您完全控制请求/响应流程,非常适合后端服务、自定义前端或任何您想自己管理交易的环境。
已经在使用 LI.FI SDK 或 Widget? Composer 自动工作。请参见 SDK 指南Widget 指南

概览

集成流程:
  1. 请求报价GET /v1/quotePOST /v1/advanced/routes
  2. 设置代币授权 — 授权 LI.FI 合约使用您的代币
  3. 发送交易 — 提交报价响应中的 transactionRequest
  4. 跟踪状态 — 为跨链转账轮询 GET /v1/status

请求 Composer 报价

使用 GET /quote(推荐)

获取 Composer 交易的最简单方法。返回包含交易数据的单个最佳路由。
curl -X GET 'https://li.quest/v1/quote?\
fromChain=8453&\
toChain=8453&\
fromToken=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913&\
toToken=0x7BfA7C4f149E7415b73bdeDfe609237e29CBF34A&\
fromAddress=0xYOUR_WALLET_ADDRESS&\
toAddress=0xYOUR_WALLET_ADDRESS&\
fromAmount=1000000'

使用 POST /advanced/routes

返回多个路由选项。当您想向用户展示选择或需要更多路由选择控制时很有用。
const getRoutes = async (params: {
  fromChainId: number;
  toChainId: number;
  fromTokenAddress: string;
  toTokenAddress: string;
  fromAmount: string;
  fromAddress: string;
}) => {
  const result = await axios.post('https://li.quest/v1/advanced/routes', {
    ...params,
    toAddress: params.fromAddress,
    options: {
      order: 'RECOMMENDED',
    },
  });
  return result.data;
};

const routes = await getRoutes({
  fromChainId: 8453,
  toChainId: 8453,
  fromTokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
  toTokenAddress: '0x7BfA7C4f149E7415b73bdeDfe609237e29CBF34A',
  fromAmount: '1000000',
  fromAddress: '0xYOUR_WALLET_ADDRESS',
});

设置代币授权

在执行交易之前,您需要授权 LI.FI 合约使用您的代币。授权地址在报价响应中提供。
import { ethers } from 'ethers';

const ERC20_ABI = [
  'function approve(address spender, uint256 amount) returns (bool)',
  'function allowance(address owner, address spender) view returns (uint256)',
];

const checkAndSetAllowance = async (
  signer: ethers.Signer,
  tokenAddress: string,
  approvalAddress: string,
  amount: string
) => {
  const erc20 = new ethers.Contract(tokenAddress, ERC20_ABI, signer);
  const signerAddress = await signer.getAddress();
  const allowance = await erc20.allowance(signerAddress, approvalAddress);

  if (allowance.lt(amount)) {
    const tx = await erc20.approve(approvalAddress, amount);
    await tx.wait();
    console.log('授权已设置。');
  } else {
    console.log('授权已足够。');
  }
};

// 使用报价响应中的数据
await checkAndSetAllowance(
  signer,
  quote.action.fromToken.address,
  quote.estimate.approvalAddress,
  quote.action.fromAmount
);
对于原生代币(如 ETH),跳过此步骤。原生代币不需要授权。

执行交易

使用报价响应中的 transactionRequest 对象发送交易。
// 对于 GET /quote 响应
const tx = await signer.sendTransaction(quote.transactionRequest);
console.log('交易已发送:', tx.hash);

// 对于 POST /advanced/routes 响应,需要先获取交易数据
const selectedRoute = routes.routes[0]; // 选择最佳路由
const tx = await signer.sendTransaction(selectedRoute.transactionRequest);
console.log('交易已发送:', tx.hash);

const receipt = await tx.wait();
console.log('交易已确认:', receipt.transactionHash);

跟跨链交易状态

对于跨链 Composer 流程,轮询状态端点以跟踪进度。
const getStatus = async (txHash: string, fromChain: number, toChain: number) => {
  const result = await axios.get('https://li.quest/v1/status', {
    params: { txHash, fromChain, toChain },
  });
  return result.data;
};

// 对于跨链转账,轮询直到完成
if (quote.action.fromChainId !== quote.action.toChainId) {
  let status;
  do {
    status = await getStatus(tx.hash, quote.action.fromChainId, quote.action.toChainId);
    console.log('状态:', status.status, status.substatus);

    if (status.status !== 'DONE' && status.status !== 'FAILED') {
      await new Promise((resolve) => setTimeout(resolve, 5000)); // 等待 5 秒
    }
  } while (status.status !== 'DONE' && status.status !== 'FAILED');

  console.log('最终状态:', status.status);
}
状态含义
NOT_FOUND交易不存在或尚未挖矿
INVALID哈希与请求的工具无关
PENDING交易进行中
DONE成功完成
FAILED交易失败

错误处理

Composer 使用标准的 LI.FI API 错误格式。常见错误包括:
错误原因解决方案
NO_POSSIBLE_ROUTE没有找到路径检查 toToken 是否是支持的金库代币地址
INSUFFICIENT_LIQUIDITY流动性不足尝试较小的金额或稍后重试
TRANSACTION_FAILED模拟失败检查协议状态(如金库是否已满)
try {
  const quote = await getQuote(params);
  // ... 处理报价
} catch (error) {
  if (error.response?.data?.code === 'NO_POSSIBLE_ROUTE') {
    console.error('没有找到路径。请检查 toToken 地址。');
  } else if (error.response?.data?.code === 'INSUFFICIENT_LIQUIDITY') {
    console.error('流动性不足。请尝试较小金额。');
  } else {
    console.error('未知错误:', error.message);
  }
}

完整示例

这是一个完整的同链 Composer 集成示例:
import { ethers } from 'ethers';
import axios from 'axios';

const API_URL = 'https://li.quest/v1';

// 配置
const PRIVATE_KEY = 'YOUR_PRIVATE_KEY';
const RPC_URL = 'https://mainnet.base.org';
const signer = new ethers.Wallet(PRIVATE_KEY, new ethers.JsonRpcProvider(RPC_URL));

// 获取报价
async function getComposerQuote(fromAddress: string) {
  const response = await axios.get(`${API_URL}/quote`, {
    params: {
      fromChain: 8453,
      toChain: 8453,
      fromToken: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
      toToken: '0x7BfA7C4f149E7415b73bdeDfe609237e29CBF34A',
      fromAmount: '1000000',
      fromAddress,
      toAddress: fromAddress,
    },
  });
  return response.data;
}

// 设置授权
async function ensureAllowance(tokenAddress: string, approvalAddress: string, amount: string) {
  const ERC20_ABI = ['function approve(address, uint256)', 'function allowance(address, address) view returns (uint256)'];
  const erc20 = new ethers.Contract(tokenAddress, ERC20_ABI, signer);
  const address = await signer.getAddress();
  const allowance = await erc20.allowance(address, approvalAddress);
  
  if (allowance < BigInt(amount)) {
    const tx = await erc20.approve(approvalAddress, amount);
    await tx.wait();
    console.log('授权已设置');
  }
}

// 主函数
async function main() {
  const address = await signer.getAddress();
  
  try {
    // 1. 获取报价
    const quote = await getComposerQuote(address);
    console.log('收到报价,工具:', quote.tool);
    
    // 2. 设置授权
    await ensureAllowance(
      quote.action.fromToken.address,
      quote.estimate.approvalAddress,
      quote.action.fromAmount
    );
    
    // 3. 执行交易
    const tx = await signer.sendTransaction(quote.transactionRequest);
    console.log('交易已发送:', tx.hash);
    
    const receipt = await tx.wait();
    console.log('交易已确认:', receipt.transactionHash);
    
  } catch (error) {
    console.error('错误:', error.response?.data || error.message);
  }
}

main();

下一步