Skip to content

Commit 4dc7f7d

Browse files
committed
fix: process gas estimation for trusted relayer isms
1 parent 6bbc7b5 commit 4dc7f7d

1 file changed

Lines changed: 36 additions & 17 deletions

File tree

  • rust/main/chains/hyperlane-ethereum/src/contracts

rust/main/chains/hyperlane-ethereum/src/contracts/mailbox.rs

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use futures_util::future::join_all;
1717
use hyperlane_core::Metadata;
1818
use tokio::join;
1919
use tokio::sync::Mutex;
20-
use tracing::instrument;
20+
use tracing::{instrument, warn};
2121

2222
use hyperlane_core::{
2323
rpc_clients::call_and_retry_indefinitely, BatchItem, BatchResult, ChainCommunicationError,
@@ -341,7 +341,16 @@ where
341341
tx_gas_estimate: Option<U256>,
342342
with_gas_estimate_buffer: bool,
343343
) -> ChainResult<ContractCall<M, ()>> {
344-
let tx = self.contract_call(message, metadata, tx_gas_estimate)?;
344+
let mut tx = self.contract_call(message, metadata, tx_gas_estimate)?;
345+
346+
// Explicitly set `from` to the relayer's signer address so that during
347+
// eth_estimateGas the simulated msg.sender matches the trusted relayer.
348+
// TrustedRelayerIsm sets deliveries[id].processor = msg.sender *before*
349+
// calling ism.verify(), so verify() checks msg.sender == trustedRelayer.
350+
// Without this, from defaults to address(0) and estimation reverts.
351+
if let Some(sender) = self.provider.default_sender() {
352+
tx = tx.from(sender);
353+
}
345354

346355
fill_tx_gas_params(
347356
tx,
@@ -644,22 +653,32 @@ where
644653
.ok_or(HyperlaneProtocolError::ProcessGasLimitRequired)?;
645654

646655
// If we have a ArbitrumNodeInterface, we need to set the l2_gas_limit.
656+
// Note: estimate_retryable_ticket simulates execution via a retryable ticket, where
657+
// msg.sender is the L2 alias of the sender arg (not the actual relayer address).
658+
// For ISMs like TrustedRelayerIsm that check msg.sender, this simulation will fail.
659+
// In that case we fall back to l2_gas_limit = None so enforceable_gas_limit() uses
660+
// the direct process() gas estimate instead.
647661
let l2_gas_limit = if let Some(arbitrum_node_interface) = &self.arbitrum_node_interface {
648-
Some(
649-
arbitrum_node_interface
650-
.estimate_retryable_ticket(
651-
H160::zero().into(),
652-
// Give the sender a deposit (100 ETH), otherwise it reverts
653-
WEI_IN_ETHER.mul(100u32),
654-
self.contract.address(),
655-
U256::zero().into(),
656-
H160::zero().into(),
657-
H160::zero().into(),
658-
contract_call.calldata().unwrap_or_default(),
659-
)
660-
.estimate_gas()
661-
.await?,
662-
)
662+
match arbitrum_node_interface
663+
.estimate_retryable_ticket(
664+
H160::zero().into(),
665+
// Give the sender a deposit (100 ETH), otherwise it reverts
666+
WEI_IN_ETHER.mul(100u32),
667+
self.contract.address(),
668+
U256::zero().into(),
669+
H160::zero().into(),
670+
H160::zero().into(),
671+
contract_call.calldata().unwrap_or_default(),
672+
)
673+
.estimate_gas()
674+
.await
675+
{
676+
Ok(estimate) => Some(estimate),
677+
Err(err) => {
678+
warn!(?err, "Failed to estimate l2_gas_limit via ArbitrumNodeInterface, falling back to direct gas estimate");
679+
None
680+
}
681+
}
663682
} else {
664683
None
665684
};

0 commit comments

Comments
 (0)