L1 contracts deployed on Ethereum mainnet that handle cross-domain messaging and asset bridging between Ethereum and Optimism L2. These contracts enable secure communication and token transfers with cryptographic proof verification.
Contract Path: L1/messaging/L1CrossDomainMessenger.sol
The core L1 contract for cross-domain messaging that sends messages from L1 to L2 and relays messages from L2 to L1 with fraud proof verification.
contract L1CrossDomainMessenger {
function initialize(address _libAddressManager) external;
function sendMessage(
address _target,
bytes calldata _message,
uint32 _gasLimit
) external;
function relayMessage(
address _target,
address _sender,
bytes memory _message,
uint256 _messageNonce,
L2MessageInclusionProof memory _proof
) external;
function replayMessage(
address _target,
address _sender,
bytes memory _message,
uint256 _queueIndex,
uint32 _oldGasLimit,
uint32 _newGasLimit
) external;
function pause() external;
function unpause() external;
function blockMessage(bytes32 _xDomainCalldataHash) external;
function allowMessage(bytes32 _xDomainCalldataHash) external;
function xDomainMessageSender() external view returns (address);
}Initializes the messenger contract with the address manager.
Parameters:
_libAddressManager (address): Address of the Lib_AddressManager contractUsage:
messenger.initialize(addressManagerAddress);Sends a message from L1 to L2.
Parameters:
_target (address): Target contract address on L2_message (bytes): Encoded message data to send_gasLimit (uint32): Gas limit for L2 executionEvents Emitted:
SentMessage(address indexed target, address sender, bytes message, uint256 messageNonce, uint256 gasLimit)Usage:
// Send a simple message
messenger.sendMessage(
l2ContractAddress,
abi.encodeWithSignature("handleL1Message(uint256)", 12345),
200000
);Relays a message from L2 to L1 with cryptographic proof verification.
Parameters:
_target (address): Target contract address on L1_sender (address): Original sender address on L2_message (bytes): Message data to relay_messageNonce (uint256): Message nonce from L2_proof (L2MessageInclusionProof): Merkle proof of message inclusionEvents Emitted:
RelayedMessage(bytes32 indexed msgHash) (on success)FailedRelayedMessage(bytes32 indexed msgHash) (on failure)Usage:
L2MessageInclusionProof memory proof = L2MessageInclusionProof({
stateRoot: stateRoot,
stateRootBatchHeader: batchHeader,
stateRootProof: inclusionProof,
stateTrieWitness: stateWitness,
storageTrieWitness: storageWitness
});
messenger.relayMessage(
targetAddress,
senderAddress,
messageData,
messageNonce,
proof
);Replays a failed message with a new gas limit.
Parameters:
_target (address): Target contract address_sender (address): Original sender address_message (bytes): Message data to replay_queueIndex (uint256): Queue index of the original message_oldGasLimit (uint32): Previous gas limit that failed_newGasLimit (uint32): New gas limit for retryPauses or unpauses message relaying (owner only).
Blocks or unblocks specific message hashes (owner only).
Parameters:
_xDomainCalldataHash (bytes32): Hash of the cross-domain message to block/allowmapping(bytes32 => bool) public blockedMessages;
mapping(bytes32 => bool) public relayedMessages;
mapping(bytes32 => bool) public successfulMessages;
uint256 public messageNonce;event MessageBlocked(bytes32 indexed _xDomainCalldataHash);
event MessageAllowed(bytes32 indexed _xDomainCalldataHash);
event SentMessage(
address indexed target,
address sender,
bytes message,
uint256 messageNonce,
uint256 gasLimit
);
event RelayedMessage(bytes32 indexed msgHash);
event FailedRelayedMessage(bytes32 indexed msgHash);Contract Path: L1/messaging/L1StandardBridge.sol
The standard bridge contract for ETH and ERC20 token transfers between L1 and L2.
contract L1StandardBridge {
function initialize(
address _l1messenger,
address _l2TokenBridge
) external;
function depositETH(
uint32 _l2Gas,
bytes calldata _data
) external payable;
function depositETHTo(
address _to,
uint32 _l2Gas,
bytes calldata _data
) external payable;
function depositERC20(
address _l1Token,
address _l2Token,
uint256 _amount,
uint32 _l2Gas,
bytes calldata _data
) external;
function depositERC20To(
address _l1Token,
address _l2Token,
address _to,
uint256 _amount,
uint32 _l2Gas,
bytes calldata _data
) external;
function finalizeETHWithdrawal(
address _from,
address _to,
uint256 _amount,
bytes calldata _data
) external;
function finalizeERC20Withdrawal(
address _l1Token,
address _l2Token,
address _from,
address _to,
uint256 _amount,
bytes calldata _data
) external;
}Initializes the bridge with the L1 messenger and L2 bridge address.
Parameters:
_l1messenger (address): L1CrossDomainMessenger contract address_l2TokenBridge (address): L2StandardBridge contract addressDeposits ETH to L2 for the sender.
Parameters:
_l2Gas (uint32): Gas limit for L2 execution_data (bytes): Optional data to pass to L2Usage:
// Deposit 1 ETH to L2
bridge.depositETH{value: 1 ether}(200000, "");Deposits ETH to L2 for a specific recipient.
Parameters:
_to (address): Recipient address on L2_l2Gas (uint32): Gas limit for L2 execution_data (bytes): Optional data to pass to L2Deposits ERC20 tokens to L2.
Parameters:
_l1Token (address): L1 token contract address_l2Token (address): Corresponding L2 token contract address_amount (uint256): Amount of tokens to deposit_l2Gas (uint32): Gas limit for L2 execution_data (bytes): Optional data to pass to L2Usage:
// Approve bridge to spend tokens
IERC20(l1TokenAddress).approve(bridgeAddress, amount);
// Deposit tokens
bridge.depositERC20(
l1TokenAddress,
l2TokenAddress,
amount,
200000,
""
);Deposits ERC20 tokens to L2 for a specific recipient.
Parameters:
_l1Token (address): L1 token contract address_l2Token (address): L2 token contract address_to (address): Recipient address on L2_amount (uint256): Amount of tokens to deposit_l2Gas (uint32): Gas limit for L2 execution_data (bytes): Optional data to pass to L2Finalizes an ETH withdrawal from L2 (called by the messenger).
Parameters:
_from (address): Sender address on L2_to (address): Recipient address on L1_amount (uint256): Amount of ETH to withdraw_data (bytes): Optional data from L2Finalizes an ERC20 token withdrawal from L2 (called by the messenger).
Parameters:
_l1Token (address): L1 token contract address_l2Token (address): L2 token contract address_from (address): Sender address on L2_to (address): Recipient address on L1_amount (uint256): Amount of tokens to withdraw_data (bytes): Optional data from L2event ETHDepositInitiated(
address indexed _from,
address indexed _to,
uint256 _amount,
bytes _data
);
event ETHWithdrawalFinalized(
address indexed _from,
address indexed _to,
uint256 _amount,
bytes _data
);
event ERC20DepositInitiated(
address indexed _l1Token,
address indexed _l2Token,
address indexed _from,
address _to,
uint256 _amount,
bytes _data
);
event ERC20WithdrawalFinalized(
address indexed _l1Token,
address indexed _l2Token,
address indexed _from,
address _to,
uint256 _amount,
bytes _data
);struct L2MessageInclusionProof {
bytes32 stateRoot;
ChainBatchHeader stateRootBatchHeader;
ChainInclusionProof stateRootProof;
bytes stateTrieWitness;
bytes storageTrieWitness;
}Proof structure for verifying L2 message inclusion in L1.
struct ChainBatchHeader {
uint256 batchIndex;
bytes32 batchRoot;
uint256 batchSize;
uint256 prevTotalElements;
bytes extraData;
}Header structure for state batch proofs.
struct ChainInclusionProof {
uint256 index;
bytes32[] siblings;
}Merkle proof structure for chain inclusion verification.
// L1 Contract sending message to L2
contract L1Contract {
IL1CrossDomainMessenger public messenger;
function sendToL2(address l2Target, bytes calldata data) external {
messenger.sendMessage(l2Target, data, 200000);
}
function handleFromL2(uint256 value) external {
require(
msg.sender == address(messenger) &&
messenger.xDomainMessageSender() == trustedL2Address,
"Invalid sender"
);
// Handle message from L2
processValue(value);
}
}// Bridge ETH and tokens
contract BridgeUser {
IL1StandardBridge public bridge;
function bridgeETH(uint256 amount) external {
bridge.depositETH{value: amount}(200000, "");
}
function bridgeTokens(
address l1Token,
address l2Token,
uint256 amount
) external {
IERC20(l1Token).transferFrom(msg.sender, address(this), amount);
IERC20(l1Token).approve(address(bridge), amount);
bridge.depositERC20(l1Token, l2Token, amount, 200000, "");
}
}