Base gas is not updated which will lead to failed l2 -> l1 message
Summary
The CrossDomainMessenger::baseGas() function calculates the necessary gas to ensure the message relayed in the l1 has at least the specified amount in the l2 when the message was sent. However, the OptimismPortal::finalizeWithdrawalTransactionExternalProof() adds a few external calls (2 approvals or 1 transfer) and L1CrossDomainMessenger::relayMessage() also pulls token from the Optimism portal, which means the base gas will be higher than the previous.
As the value of the RELAY_CONSTANT_OVERHEAD, RELAY_RESERVED_GAS and RELAY_GAS_CHECK_BUFFER remains the same, the l1 message may not have enough gas to proceed.
Root Cause
In Constants.sol:96 the RELAY_CONSTANT_OVERHEAD is not updated.
Internal pre-conditions
None.
External pre-conditions
None.
Attack Path
User calls CrossDomainMessenger::sendMessage() with some gas in the l2.
Once the transaction is sent in the l1, OptimismPortal::finalizeWithdrawalTransactionExternalProof(), it will not have enough gas and revert. It may be possible to replay it later if there was still enough gas to store it in the failed messages mapping. Otherwise it will be impossible to replay.
Impact
Failed message that may or may not be replayed. Either way, the message may be time sensitive from the protocol. As the gas constants were not updated, it may underestimate the amount of gas needed to finish execution in L1CrossDomainMessenger::relayMessage(), and the message is not stored infailedMessages[versionedHash]`, leading to forever stuck funds.
PoC
See the changes to OptimismPortal and L1CrossDomainMessenger.
Mitigation
Update the base gas value to account for the extra calls.
0x73696d616f
High
Base gas is not updated which will lead to failed l2 -> l1 message
Summary
The CrossDomainMessenger::baseGas() function calculates the necessary gas to ensure the message relayed in the l1 has at least the specified amount in the l2 when the message was sent. However, the
OptimismPortal::finalizeWithdrawalTransactionExternalProof()
adds a few external calls (2 approvals or 1 transfer) andL1CrossDomainMessenger::relayMessage()
also pulls token from the Optimism portal, which means the base gas will be higher than the previous.As the value of the
RELAY_CONSTANT_OVERHEAD
,RELAY_RESERVED_GAS
andRELAY_GAS_CHECK_BUFFER
remains the same, the l1 message may not have enough gas to proceed.Root Cause
In
Constants.sol:96
theRELAY_CONSTANT_OVERHEAD
is not updated.Internal pre-conditions
None.
External pre-conditions
None.
Attack Path
CrossDomainMessenger::sendMessage()
with some gas in the l2.OptimismPortal::finalizeWithdrawalTransactionExternalProof()
, it will not have enough gas and revert. It may be possible to replay it later if there was still enough gas to store it in the failed messages mapping. Otherwise it will be impossible to replay.Impact
Failed message that may or may not be replayed. Either way, the message may be time sensitive from the protocol. As the gas constants were not updated, it may underestimate the amount of gas needed to finish execution in
L1CrossDomainMessenger::relayMessage(), and the message is not stored in
failedMessages[versionedHash]`, leading to forever stuck funds.PoC
See the changes to OptimismPortal and L1CrossDomainMessenger.
Mitigation
Update the base gas value to account for the extra calls.