跳到主要内容

跨链 Gas 费用后置处理

在后置处理钩子中,如果支付的费用不足以覆盖中继器的预期成本,InterchainGasPaymaster 合约将会回滚。在 dispatch 时计算的 gas 报价必须与中继器的预期成本相符。

Gas 限制

gasLimit 是根据在目标链上调用给定消息的 handle 的成本来设置的。这可能会根据消息内容和处理程序的逻辑而有所不同。

用于计量 handle 调用的默认 gasLimit 是静态的 50_000 gas。这对于简单操作来说已经足够,但对于更复杂的 handle 函数可能不够。

如果你的 handle 函数执行复杂操作或需要更多 gas,你必须在元数据中覆盖默认的 gasLimit 以避免交易回滚。在单元测试中对你的 handle 实现进行基准测试,以确定合理的 gasLimit

元数据

此 hook 需要 打包编码 格式的 StandardHookMetadata。查看 Mailbox dispatch 重载了解如何传递元数据覆盖。

struct StandardHookMetadata {
uint16 variant;
uint256 msgValue;
uint256 gasLimit;
address refundAddress;
}

StandardHookMetadata 结构定义了元数据编码所需的字段:

  • variant: 指定元数据格式版本
  • msgValue: 随消息发送的原生代币数量
  • gasLimit: 目标链上 handle 函数的 gas 限制。确保这与你的模拟结果相匹配
  • refundAddress: 退还未使用 gas 费用的地址

要编码此元数据,请使用 StandardHookMetadata.formatMetadata 库函数。Solidity 不支持使用 abi.encodePacked 直接编码结构体。

使用示例

// 示例: 使用 StandardHookMetadata 编码元数据
bytes memory metadata = StandardHookMetadata.formatMetadata(
0, // ETH 消息值
200000, // 自定义 gas 限制
address(this), // 退款地址
bytes("") // 可选的自定义元数据
);

确定和覆盖 Gas 限制

  1. 模拟和基准测试 Gas 使用量:
  • 使用 Tenderly 或 Foundry 等工具模拟消息接收者的 handle 函数。确保 from 地址设置为你链上的 Mailbox 合约。
  • 如果 gas 使用量超过 50,000,计算适当的 gasLimit 并更新你的元数据。
  • 使用 Hyperlane Explorer 中的操作按钮 从消息详情模拟交易。
  1. 更新你的元数据:
  • 根据模拟结果计算所需的 gasLimit
  • 在元数据中传入更新后的 gasLimit,确保中继器能够传递你的消息。

目标 Gas 配置

对于每个远程域,InterchainGasPaymaster 设置域 gas 配置。

struct DomainGasConfig {
IGasOracle gasOracle;
uint96 gasOverhead;
}

Gas 开销

gas 开销是目标 gas 配置的一部分。这对应于在目标链上处理消息的运营成本。

信息
  • 你应该确保 gasOverhead 足以覆盖目标链上的 ISM 范围。
  • 由于你可以为不同的消息类型配置不同的 ISM,每个 ISM 的 verify 函数可能有不同的 gas 开销。

Gas 预言机

跨链 Gas 费用要求是使用预言机提供的 gas 价格和原目标链之间的汇率计算的。

IGP 合约可以配置 gas 预言机,负责跟踪远程代币 gas 价格和汇率。开发者应该使用 Mailbox 合约上的 quoteDispatch 函数来计算 gas 费用。quoteDispatch 考虑了系统级开销,确保整个 dispatch 过程的费用计算准确。

信息
  • 汇率和 gas 价格由中继器决定。可能会收取价差以应对价格波动和运营成本。

最终,中继器将能够自动更新其 gas 预言机,以确保其 IGP 始终为远程 gas 报出公平价格。

getExchangeRateAndGasPrice

function getExchangeRateAndGasPrice(
uint32 _destinationDomain
)
public
view
override
returns (uint128 tokenExchangeRate, uint128 gasPrice)
{
IGasOracle _gasOracle = destinationGasConfigs[_destinationDomain]
.gasOracle;

if (address(_gasOracle) == address(0)) {
revert(
string.concat(
"Configured IGP doesn't support domain ",
Strings.toString(_destinationDomain)
)
);
}
return _gasOracle.getExchangeRateAndGasPrice(_destinationDomain);
}

参数

  • destinationDomain: 消息的目标域

返回值

  • tokenExchangeRate: 原链和目标链 gas 代币之间的汇率
  • gasPrice: 目标链的 gas 价格

quoteGasPayment

quoteGasPayment 函数计算中继器预期成本的费用。

function quoteGasPayment(
uint32 _destinationDomain,
uint256 _gasLimit
) public view virtual override returns (uint256) {
// Get the gas data for the destination domain.
(
uint128 _tokenExchangeRate,
uint128 _gasPrice
) = getExchangeRateAndGasPrice(_destinationDomain);

// The total cost quoted in destination chain's native token.
uint256 _destinationGasCost = _gasLimit * uint256(_gasPrice);

// Convert to the local native token.
return
(_destinationGasCost * _tokenExchangeRate) /
TOKEN_EXCHANGE_RATE_SCALE;
}

参数

  • destinationDomain: 消息的目标域
  • gasLimit: 用于计量 handle 调用的 gas 限制

返回值

  • fee: postDispatch 成功所需的支付金额

重试

如果 handle 调用消耗的 gas 超过报价,中继器将不会提交处理交易。这个问题通常是由于初始 dispatch 时 gas 支付不足导致的。

在这种情况下,可以使用 payForGas 函数支付额外的 gas。

function payForGas(
bytes32 _messageId,
uint32 _destinationDomain,
uint256 _gasAmount,
address _refundAddress
) external payable;

参数

  • messageId: 从 dispatch 调用返回的消息标识符
  • destinationDomain: 消息的目标域
  • gasAmount: 要支付的额外 gas 数量
  • refundAddress: 退还多余支付的地址

使用 Hyperlane Explorer 进行调试

Hyperlane Explorer 是一个强大的工具,可用于调试跨链消息问题,包括 gas 支付和中继器行为。

主要功能

  • 消息状态: 查看消息的当前状态(例如,"重试: GasPaymentRequirementNotMet")。
  • Gas 支付详情: 检查已支付的 gas 数量(原始 IGP gas 数量)和中继器要求的数量。
  • 模拟调用数据: 使用"查看调用数据详情"选项在 Tenderly 等工具上模拟交易。

故障排除

本节介绍开发者在处理跨链 Gas 支付时遇到的常见问题及其可能的解决方案。

GasPaymentRequirementNotMet 警告

  • 原因:dispatch 期间提供的 gas 支付不满足中继器计算的要求时发生。

  • 解决方案:

    • 使用 quoteDispatch 计算使 dispatch 调用成功所需的总费用。
    • 验证元数据中的 msg.value 是否覆盖了中继器报价的费用。
    • 在 Hyperlane Explorer 中检查消息状态。查找: Retry(GasPaymentRequirementNotMet)

回退路由和超额支付警告

  • 原因: msg.value 超过所需的 gas 支付,触发回退路由钩子。

  • 解决方案:

    • 验证你的报价逻辑(quoteDispatch)是否与中继器的预期费用匹配。
    • 避免在未先对 handle 函数进行基准测试的情况下过度估计 gasLimit 值。
    • 模拟交易以确认适当的支付。

意外的高额 Gas 报价

  • 原因: 设置了非常高的 gasLimit,导致过高的 gas 报价。

  • 解决方案:

    • 仔细检查元数据中指定的 gasLimit
    • 验证你的报价逻辑(quoteDispatch)是否与中继器的预期费用匹配。
    • 调整 gasLimit 以匹配你的 handle 函数的估计 gas 消耗。