Skip to main content
了解如何使用追踪分析工具调试已回滚的交易。本指南基于真实生产案例,涵盖常见的失败模式及其修复方法。

前置条件

在开始之前,你需要:
  • 失败交易的交易哈希
  • 访问一款追踪分析工具

Blocksec Explorer

查看详细的调用追踪并分析交易

Tenderly Debugger

逐步模拟并调试交易

核心调试工作流

按照以下步骤诊断大多数交易失败。
1

定位回滚位置

在 Blocksec 或 Tenderly 中打开交易并识别:
  • 顶层回滚原因(如果可用)
  • 调用树中的首次回滚(这通常是真正的根本原因)
  • 回滚之前的合约或调用(这是失败的操作)
追踪工具有时会显示多个错误。当 UI 摘要与原始追踪冲突时,请以原始追踪为准。
2

对失败进行分类

大多数回滚可归入以下类别:一旦确定了类别,修复方法就变得清晰了。
3

对比预期输入与实际输入

聚合器和路由器的失败通常源于输入不匹配:
  • 链上的 gasLimit 与来自 /quote/stepTransactiongasLimit
  • 授权数量与实际花费数量
  • 发送的 msg.value 与所需的 msg.value
  • minAmountOut 与执行时的实际输出
  • 代币地址或价格数据源 ID 错误
4

复现并测试

使用完全相同的 calldata 和状态模拟失败的调用。然后一次只更改一个变量:
  • 提高 gasLimit
  • 添加或调整 msg.value
  • 放宽滑点参数
如果更改某个变量使模拟成功,那么你就找到了根本原因。

常见失败模式

症状

追踪突然中断,或显示 gas 耗尽(OOG)错误。

如何确认

  1. 检查交易的 gasLimit
  2. 在回滚原因中查找 OOG
  3. 使用更高的 gasLimit 重新模拟(使用报价 API 中的值)

根本原因

交易使用的 gasLimit 低于报价推荐值。钱包或中继器有时会覆盖 gas 设置。

修复

  • 使用报价响应中的确切 gasLimit
  • 如果你的产品允许,可添加 10–20% 的安全缓冲
  • 确认钱包和中继器不会限制 gas 值

示例

API 返回了充足的 gasLimit,但链上交易回滚了。使用正确的 gasLimit 重新模拟即成功。

症状

回滚消息:transfer amount exceeds allowance

如何确认

  1. 在追踪中找到 transferFrom(...) 调用
  2. 确定是哪个 spender 在拉取资金
  3. 检查执行区块处的 allowance(owner, spender)

根本原因

用户要么没有授权,要么授权给了错误的 spender,要么授权额度少于所需数量。之前的某笔交易可能已经消耗了授权额度。

修复

  • 提示用户对正确的代币和 spender 进行授权
  • 权衡无限授权与精确授权之间的取舍

示例

交易因授权额度不足而回滚

症状

诸如以下错误:
  • insufficient balance for transfer
  • 原生价值转发失败

如何确认

  1. 在 Tenderly 中检查交易的 msg.value
  2. 在追踪中找到路由器转发 ETH 的位置
  3. 在该处查找余额失败

根本原因

路由需要原生代币(用于费用、桥接 gas 或协议支付),但交易发送了 value=0

修复

  • 包含 API 返回的 msg.value
  • 确认中继器和钱包不会丢弃 value 字段

示例

尽管 API 返回了非零值,但交易因缺少 msg.value 而失败。在 Tenderly 中查看

症状

回滚消息:PythErrors.StalePrice()

如何确认

在追踪中查找 getPriceNoOlderThan(..., age=N) 回滚。

根本原因

预言机数据过旧,或资金池使用了未被更新的错误数据源 ID。

修复

联系 LI.FI 支持 报告问题。

示例

由于资金池使用了错误的数据源 ID,出现了 PythErrors.StalePrice()在 Tenderly 中查看

症状

回滚消息:insufficient balancetransfer amount exceeds balance

如何确认

  1. 在追踪中找到代币转账
  2. 确定 “from” 地址
  3. 检查执行时的 balanceOf(from)

根本原因

用户的余额在报价与执行之间发生了变化。转账收费(fee-on-transfer)或变基(rebasing)代币可能导致意料之外的余额变化。

修复

  • 在发送前立即重新报价并核实余额
  • 对于转账收费代币,联系 LI.FI 支持将该代币加入拒绝列表

示例

交易因余额不足而回滚

症状

与最小输出或滑点检查相关的回滚(确切消息因 DEX 而异)。

如何确认

找到交换步骤并比较:
  • amountOutMinminReturnAmount
  • 实际计算出的 amountOut
如果 amountOut < minReturnAmount,交易会回滚。

根本原因

价格波动、MEV 提取、波动性资金池、低流动性或过时的报价。

修复

  • 重新报价并在报价后 60–90 秒内执行(最常见原因是报价过时)
  • 如果新报价仍然失败,仅出于诊断目的提高滑点容忍度(对波动性或新代币为 15–25%)
  • 对于无法避免的高滑点,使用私有或受 MEV 保护的 RPC 端点
不要将高滑点值用作生产环境默认值。这会为三明治攻击制造较大的窗口,MEV 机器人可借此从用户处提取价值。仅在一次性调试时使用这些值。

示例

症状

最终交换步骤失败,报 SafeERC20: low-level call failed

如何确认

在追踪中查找:
  1. 一个回滚的 transferFrom 调用
  2. 一个失败的嵌套外部调用(通常调向税费钱包或费用处理器)
  3. 错误以 SafeERC20: low-level call failed 形式向上冒泡

根本原因

某些代币具有自定义转账逻辑,在特定条件下会失败。例如,带有卖出税的代币可能会调用拒绝 ETH 或意外回滚的外部合约。

修复

  • 将该代币视为不兼容卖出路由
  • LI.FI 支持 报告,以加入代币拒绝列表
使用 honeypot.isGoPlus 等代币风险扫描工具,检查蜜罐标记、卖出限制或异常税费。

示例

路由器因代币的税费钱包拒绝 ETH 而未能转移代币。在 Blocksec 中查看

症状

资金池数学计算内部回滚,例如 Curve 的 get_D 在 255 次迭代后仍未收敛。

如何确认

追踪显示资金池数学函数(get_D、不变量计算)中带有 raise 语句的回滚。

根本原因

资金池已损坏,通常是由于某个被攻陷的代币导致极端失衡或无效状态。

修复

联系 LI.FI 支持 将该资金池列入黑名单。

示例

某 Curve 资金池的 get_D 函数未能收敛。Curve 团队确认该资金池已损坏。在 Tenderly 中查看

症状

回滚消息:UniswapV2: LOCKED

如何确认

在追踪中:
  1. Uniswap V2 交易对转移某个代币
  2. 该代币的转账逻辑回调进同一个交易对
  3. 交易对的重入锁被触发

根本原因

带有回调或费用交换逻辑的代币在转账期间重新进入交易对。这通常发生在配置错误的转账收费代币上。

修复

联系 LI.FI 支持 将该资金池列入黑名单。

示例

涉及 WeightedIndex 的交换回滚并报 UniswapV2: LOCKED。KyberSwap 将受影响的资金池列入了黑名单。在 Tenderly 中查看

症状

尽管用户最初拥有足够的代币,但路由中途因余额不足而回滚。

如何确认

追踪显示:
  1. 较早的一跳收到的代币少于预期
  2. 较晚的一跳试图转移最初计算的数量
  3. 余额检查失败

根本原因

转账收费(FoT)或通缩型代币在转账期间收取费用。路由假定为精确数量,但实际收到的数量少于计算值。

修复

联系 LI.FI 支持 将该代币加入拒绝列表。

示例

fBOMB 因其通缩机制打乱了路由的精确计算,报 Max20: insufficient balance 而失败。

症状

由资金池层面的重入锁引起的回滚,尤其是转账收费代币。

如何确认

追踪显示资金池处出现回滚,带有重入防护行为,类似于 “LOCKED” 但因协议而异。

根本原因

较新的 DEX 增加了重入保护,与转账收费或回调型代币相冲突。

修复

联系 LI.FI 支持 将该资金池列入黑名单。

示例

Kodiak v2 资金池增加了重入锁,导致转账收费代币回滚。在 Tenderly 中查看

症状

诸如以下回滚消息:
  • Transaction too old
  • EXPIRED
  • SwapRouter: EXPIRED

如何确认

  1. 在 calldata 中找到编码后的截止时间(通常为一个 32 字节的字)
  2. 将十六进制值转换为 Unix 时间
  3. 与交易被打包时的区块时间戳进行比较
如果 block_timestamp > deadline,路由器会拒绝该交易。示例计算:
  • 截止时间:0x6951e2e0 = 1,766,974,176
  • 区块时间戳:1,766,975,579
  • 差值:1,403 秒(迟了约 23 分钟)
查看 VM 追踪

根本原因

由于签名缓慢、内存池拥堵、gas 价格过低或中继器延迟,交易提交得太晚。

修复

  • 获取新的报价并立即提交
  • 为卡住的交易提高 gas 价格
  • 不要重用旧的 calldata
执行过晚通常意味着市场已经变动。即使没有明确的截止时间回滚,过时的报价也常因滑点而失败。请始终重新报价。

快速决策清单

调试失败交易时,请遵循以下步骤:
1

找到首次回滚

查看调用树,而不仅仅是 UI 标题。首次回滚通常就是根本原因。
2

确定类别

3

模拟交易

使用 Tenderly 或 Blocksec,以完全相同的参数复现失败。
4

测试单项更改

一次只修改一个变量(gas、value、授权、滑点),直到模拟成功。

快速参考


相关资源

错误码

API 错误码参考

常见问题 FAQ

常见的故障排除问题

状态追踪

追踪交易状态

滑点与价格影响

了解滑点设置