L1ToL2CrossDomainMessengerGatewayAdapterLib
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
| Name | Type | Description |
|---|---|---|
| $ | 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
| Name | Type | Description |
|---|---|---|
| counterpartChainId | uint256 | The paired-domain chain id. |
| counterpartAdapter | address | The sibling adapter on the paired domain (must be non-zero). |
| minGasLimit_ | uint32 | The 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
| Name | Type | Description |
|---|---|---|
| <none> | address |
counterpartChainId
function counterpartChainId() internal view returns (uint256);Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint256 |
counterpartAdapter
function counterpartAdapter() internal view returns (address);Returns
| Name | Type | Description |
|---|---|---|
| <none> | address |
minGasLimit
function minGasLimit() internal view returns (uint32);Returns
| Name | Type | Description |
|---|---|---|
| <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
| Name | Type | Description |
|---|---|---|
| _ | bytes4 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | bool |
setCounterpart
function setCounterpart(uint256 chainId, address adapter) internal;Parameters
| Name | Type | Description |
|---|---|---|
| chainId | uint256 | |
| adapter | address |
setMinGasLimit
function setMinGasLimit(uint32 newMinGasLimit) internal;Parameters
| Name | Type | Description |
|---|---|---|
| newMinGasLimit | uint32 |
_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
| Name | Type | Description |
|---|---|---|
| chainId | uint256 | |
| adapter | address |
_setMinGasLimit
Unguarded min-gas write shared by init + the admin setter.
function _setMinGasLimit(uint32 newMinGasLimit) private;Parameters
| Name | Type | Description |
|---|---|---|
| newMinGasLimit | uint32 |
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
| Name | Type | Description |
|---|---|---|
| recipient | bytes | |
| payload | bytes | |
| attributes | bytes[] |
Returns
| Name | Type | Description |
|---|---|---|
| <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
| Name | Type | Description |
|---|---|---|
| sender | bytes | |
| recipient | bytes | |
| payload | bytes | |
| nonce | uint256 |