Skip to main content
Sigvex

L2 Rollup Risks Remediation

How to handle L2-specific hazards: sequencer downtime, cross-domain message authentication, and L1/L2 block-property differences.

L2 Rollup Risks Remediation

Overview

Related Detector: L2 Rollup Risks

Contracts ported to Optimism, Arbitrum, Base, zkSync, and similar rollups inherit assumptions that do not hold on L2: block time and block.number behave differently, a price feed can go stale if the sequencer is down, and cross-domain messages must be authenticated against the bridge. The remediation is to make these differences explicit rather than assuming L1 semantics.

// 1. Check the sequencer uptime feed before trusting an L2 oracle price.
(, int256 up, uint256 startedAt, , ) = sequencerUptimeFeed.latestRoundData();
require(up == 0, "Sequencer down");
require(block.timestamp - startedAt > GRACE_PERIOD, "Grace period");

// 2. Authenticate cross-domain messages against the messenger and remote sender.
require(msg.sender == address(l2Messenger), "Not messenger");
require(l2Messenger.xDomainMessageSender() == trustedL1Sender, "Bad L1 sender");

// 3. Do not use block.number for wall-clock time on L2; use block.timestamp,
//    and understand each chain's timing semantics before relying on either.

Read the specific rollup’s documentation for its block-property and messaging semantics; they differ between stacks.

Common Mistakes

  • Reading an L2 price feed without checking the sequencer uptime feed, accepting a stale price during downtime.
  • Trusting xDomainMessageSender() without also confirming msg.sender is the canonical messenger.
  • Using block.number as a timer on a chain where its cadence differs from L1.

References