Skip to main content

链间燃料费支付

为了deliver a message,目标链上必须包含一个事务,该事务使用编码的消息和ISM元数据调用邮箱的 process函数。

为了方便起见,relayer监视已分发的消息,如果消息发送者在原始链上收到足够的付款,则代表消息发送者提交进程事务。我们称之为链间燃料费支付

因为消息可以触发任意代码执行,所以中继器必须用gasLimit测量handle call ,以便在消息分发时适当收费。

txCost=gasPricegasLimitexchangeRate=originGasTokenPricedestinationGasTokenPriceoriginFee=exchangeRatetxCosttxCost = gasPrice * gasLimit \\[5pt] exchangeRate = \frac{originGasTokenPrice}{destinationGasTokenPrice} \\[5pt] originFee = exchangeRate * txCost

Destination Gas Config

For each remote domain, you can set the domain gas config.

struct DomainGasConfig {
IGasOracle gasOracle;
uint96 gasOverhead;
}

gasOracle

The gasOracle is a contract containing the exchange rates between supported origin and destination chains.

gasOverhead

The gasOverhead is the operational cost of processing a message on the destination chain. When returning a quote for the cost of dispatching a message, the IGP contract will add this gasOverhead to the gasLimit.

Post Dispatch

在发送后钩子期间,如果付款不足以支付中继器的“预期”成本,则 InterchainGasPaymaster合同将回滚。中继器将尊重dispatch 时间的报价。

Gas Limit

当没有指定时,用于计量handle 调用的 gasLimit使用静态默认值50_000

tip

我们建议开发人员在单元测试中对他们的handle implementations 进行基准测试,以确定要使用的合理gasLimit

如果你希望 handle 函数消耗超过这个默认值,你应该覆盖default gasLimit in metadata

退款

如果消息发送方支付的金额超过钩子报价,合同将退还差额。如果没有指定,退款地址将默认为消息发送方。这允许发送方跳过显式的quoteDispatch 调用。

warning

退款可能存在reentrancy。应特别注意确保安全,防止再入漏洞。

只有在付款金额大于报价的情况下才会退款。如果发送所需的燃料费比已支付的燃料费少,则不会退款。如果退款不成功,payForGas调用将回滚。要指定不同的退款地址,请覆盖default refundAddress in metadata

元数据

这个钩子需要StandardHookMetadata的打包编码的元数据。关于如何传递元数据覆盖,请参阅邮箱Mailboxdispatch overloads

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

示例

bytes memory metadata = abi.encodePacked(
StandardHookMetadata({
variant: 1, // only variant supported by this hook
msgValue: 0, // unused by this hook
gasLimit: 100000, // override default gas limit
refundAddress: msg.sender // override default refund address
})
);

Gas Oracles

链间燃料费支付需求是使用支持的始发链和目的地链之间的整体燃料价格和汇率来计算的。

info

汇率和天然气价格由中继器决定。 可能会收取差价,以计入漂没和运营成本。

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

require(
address(_gasOracle) != address(0),
string.concat(
"Configured IGP doesn't support domain ",
Strings.toString(_destinationDomain)
)
);

return _gasOracle.getExchangeRateAndGasPrice(_destinationDomain);
}

参数

  • destinationDomain: 消息的目的域

返回

  • tokenExchangeRate: 起源链和目的地链的gas代币之间的汇率
  • gasPrice: 目的地链的燃料价格

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调用的燃料制

返回

  • fee: postDispatch 成功所需的付款

重试

如果handle调用消耗的燃料费超过报价,中继器将不会提交进程事务。在这种情况下,可以使用payForGas功能支付额外的gas。

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

参数

  • messageId: 从dispatch调用返回的消息标识符
  • destinationDomain: 消息的目的域
  • gasAmount: 额外的燃料费用
  • refundAddress: 退还超额款项的地址