Skip to content
Lattice

L1ToL2CrossDomainMessengerGatewayAdapterLib

Git Source

Title: L1ToL2CrossDomainMessengerGatewayAdapterLib

Authors: David Dada <daveproxy80@gmail.com> (https://github.com/dadadave80), Modified from Optimism (https://github.com/ethereum-optimism/optimism)

Logic + ERC-7201 storage for the canonical OP Stack L1<->L2 CrossDomainMessenger ERC-7786 gateway adapter. sendMessage wraps the ERC-7930 envelope as the calldata the messenger will execute on the counterpart adapter and dispatches via messenger.sendMessage (no fee — the message is relayed on the other domain); receiveCrossChainMessage is the messenger-invoked delivery callback that authenticates the counterpart out-of-band via xDomainMessageSender, de-duplicates, and delivers to the ERC-7930 recipient. Carries BOTH deposits (L1->L2) and withdrawals (L2->L1); the adapter is direction-agnostic.

INVERTED INBOUND AUTH: the adapter's inbound function is the _target the messenger CALLs during relay, so msg.sender is the L2 messenger predeploy (NOT the counterpart gateway). Trust is therefore established by reading the authenticated counterpart sender back from messenger.xDomainMessageSender() and matching it to the configured (non-zero) counterpart adapter. The messenger self-dedups on the message hash (relay reverts on replay via successfulMessages), so the per-envelope guard here is cheap defense-in-depth rather than the primary replay defense. Wire message = abi.encodeCall(receiveCrossChainMessage, (senderInterop, recipient, payload, nonce)).

Functions

l1ToL2CrossDomainMessengerGatewayAdapterStorage

function l1ToL2CrossDomainMessengerGatewayAdapterStorage()
        internal
        pure
        returns (L1ToL2CrossDomainMessengerGatewayAdapterStorage storage $);

Returns

NameTypeDescription
$L1ToL2CrossDomainMessengerGatewayAdapterStorage

__L1ToL2CrossDomainMessengerGatewayAdapter_init

Seeds the fixed counterpart + relay gas and registers the gateway-source ERC-165 id. The messenger is the fixed predeploy constant, so there is no endpoint/router to persist at init.

function __L1ToL2CrossDomainMessengerGatewayAdapter_init(
        uint256 counterpartChainId,
        address counterpartAdapter,
        uint32 minGasLimit_
    ) internal;

Parameters

NameTypeDescription
counterpartChainIduint256The paired-domain chain id.
counterpartAdapteraddressThe sibling adapter on the paired domain (must be non-zero).
minGasLimit_uint32The minGasLimit the messenger relays outbound messages with.

registerInterface

Writes true to the SHARED IERC7786GatewaySource ERC-165 map slot (0x11967553 → ...). Same slot the CCIP/LayerZero/Wormhole/Axelar adapters register; a Diamond mounts at most one gateway.

function registerInterface() internal;

messenger

function messenger() internal pure returns (address);

Returns

NameTypeDescription
<none>address

counterpartChainId

function counterpartChainId() internal view returns (uint256);

Returns

NameTypeDescription
<none>uint256

counterpartAdapter

function counterpartAdapter() internal view returns (address);

Returns

NameTypeDescription
<none>address

minGasLimit

function minGasLimit() internal view returns (uint32);

Returns

NameTypeDescription
<none>uint32

supportsAttribute

No sendMessage attributes are supported by this adapter: relay gas is a fixed adapter config (_minGasLimit), so there is no per-message gas config to attach.

function supportsAttribute(bytes4) internal pure returns (bool);

Parameters

NameTypeDescription
_bytes4

Returns

NameTypeDescription
<none>bool

setCounterpart

function setCounterpart(uint256 chainId, address adapter) internal;

Parameters

NameTypeDescription
chainIduint256
adapteraddress

setMinGasLimit

function setMinGasLimit(uint32 newMinGasLimit) internal;

Parameters

NameTypeDescription
newMinGasLimituint32

_setCounterpart

Unguarded counterpart write shared by init + the admin setter. Rejects a zero counterpart adapter so inbound auth can never be satisfied by an unconfigured (zero) sender.

function _setCounterpart(uint256 chainId, address adapter) private;

Parameters

NameTypeDescription
chainIduint256
adapteraddress

_setMinGasLimit

Unguarded min-gas write shared by init + the admin setter.

function _setMinGasLimit(uint32 newMinGasLimit) private;

Parameters

NameTypeDescription
newMinGasLimituint32

sendMessage

ERC-7786 source. Wraps the ERC-7930 envelope as the calldata the messenger will execute on the counterpart adapter and dispatches it via messenger.sendMessage. Charges NO fee: the message is relayed on the other domain and the messenger takes no native value here, so a non-empty msg.value is rejected. messenger.sendMessage returns VOID, so the ERC-7786 sendId is derived locally as keccak256(abi.encode(counterpartChainId, nonce)) — the (source, nonce) unique-id scheme using the counterpart as the id namespace.

No attributes are supported — any attribute reverts UnsupportedAttribute.

function sendMessage(bytes calldata recipient, bytes calldata payload, bytes[] calldata attributes)
        internal
        returns (bytes32);

Parameters

NameTypeDescription
recipientbytes
payloadbytes
attributesbytes[]

Returns

NameTypeDescription
<none>bytes32

receiveCrossChainMessage

Messenger-invoked delivery callback (INVERTED AUTH). Authenticates: (1) msg.sender is the L2 messenger predeploy; (2) the authenticated counterpart sender read from xDomainMessageSender() matches the configured (non-zero) counterpart adapter. De-dups per id marking BEFORE delivery (strict CEI), then delivers to the ERC-7930 recipient after asserting it targets THIS chain.

The per-envelope guard is defense-in-depth: the messenger already self-dedups on the message hash, reverting relay on replay via successfulMessages. L2->L1 (withdrawal) messages reach this callback only after the withdrawal challenge window elapses (finalization handled off-chain by the messenger).

function receiveCrossChainMessage(
        bytes calldata sender,
        bytes calldata recipient,
        bytes calldata payload,
        uint256 nonce
    ) internal;

Parameters

NameTypeDescription
senderbytes
recipientbytes
payloadbytes
nonceuint256