Cross-Domain Messaging
Cross-Domain Messaging in Wischain
The Wischain ecosystem features a robust arbitrary message-passing bridge that facilitates token transfers and enables decentralized applications (dApps) to communicate seamlessly between Layer 1 (L1) and Layer 2 (L2). This capability allows dApps on L1 to trigger functions on L2 and vice versa. The following sections detail how messages are relayed between L1 and L2.
Sending Messages from L1 to L2
L1 to L2 Workflow
To send messages from L1 to L2, there are two primary methods: utilizing the L1WischainMessenger for arbitrary messages and the EnforcedTxGateway for enforced transactions. Both methods empower users to initiate L2 transactions from L1 and call arbitrary contracts on L2.
For arbitrary messages, the sender in L2 transactions is the aliased address of the L1WischainMessenger.
For enforced transactions, the sender is an Externally Owned Account (EOA).
Additionally, Wischain provides several standard token gateways to simplify the process of depositing ETH and other standard tokens, including ERC-20, ERC-677, ERC-721, and ERC-1155. These gateways encapsulate token deposits as messages and transmit them to their L2 counterparts through the L1WischainMessenger contract. More information regarding L1 token gateways can be found in the Deposit Gateways section.
Currently, enforced transactions are not yet activated in Wischain. Future updates will enable users to bypass the L1WischainMessenger and send messages directly to the L1MessageQueue.
As illustrated in the workflow, both arbitrary messages and enforced transactions are added to the message queue housed within the L1MessageQueue contract. This contract offers two primary functions for appending messages:
appendCrossDomainMessage for arbitrary messages.
appendEnforcedTransaction for enforced transactions.
Function Signatures:
Both functions create an L1-initiated transaction with a new transaction type, L1MessageTx, specific to the Wischain chain, and compute the transaction hash accordingly. The L1MessageQueue appends this transaction hash to the message queue and emits a QueueTransaction event.
Differences between Functions:
appendCrossDomainMessage is exclusively callable by the L1WischainMessenger, using the aliased address of
msg.sender
as the transaction sender.appendEnforcedTransaction is callable solely by EnforcedTxGateway, allowing users to initiate a withdrawal or transfer of ETH from their L2 accounts directly through the L1 bridge.
Upon successful execution of the transaction on L1, a watcher within the Wischain sequencer monitors the L1MessageQueue contract to collect new QueueTransaction events from L1 blocks. The sequencer constructs a new L1MessageTx transaction for each event and appends them to its local L1 transaction queue. During the construction of a new L2 block, the sequencer integrates transactions from both its L1 transaction queue and its L2 mempool, adhering to the sequential order defined by the L1MessageQueue contract. Currently, the number of L1MessageTx transactions included in an L2 block is limited to a maximum of NumL1MessagesPerBlock (currently set to 10).
Sending Arbitrary Messages
The L1WischainMessenger contract provides two functions for sending arbitrary messages. Both functions require users to specify a gas limit for the corresponding L1MessageTx transaction on L2 and prepay the message relay fee on L1, calculated based on the specified gas limit. The fee is collected by a feeVault contract on L1. If the transaction fails on L2 due to an incorrect gas limit, users can replay the message with an increased gas limit. Since any unused portion of these fees is refunded, there is no penalty for overestimating the gas limit.
The sendMessage
functions encode the provided arguments into a cross-domain message, where the message nonce corresponds to the next index in the L1 message queue. This encoded data serves as the calldata for the L1MessageTx transaction executed on L2. Note that these cross-domain messages will invoke the relayMessage function of the L2WischainMessenger contract on L2.
The deposited ETH amount is locked within the L1WischainMessenger contract. If the ETH amount in the message does not cover both the message relay fee and the deposited amount, the transaction will be reverted. The L1WischainMessenger contract will refund any excess amount to the designated refund address, or to the transaction sender if no refund address is specified. Finally, the L1WischainMessenger appends the cross-domain message to the L1MessageQueue using the appendCrossDomainMessage method.
Sending Enforced Transactions
Currently, Enforced Transactions are not enabled within Wischain, but future upgrades will allow users to bypass the L1WischainMessenger and send messages directly to the L1MessageQueue.
The EnforcedTxGateway contract offers two functions for sending enforced transactions. In the first function, the sender of the generated L1MessageTx transaction is the transaction sender. The second function allows the passed sender address to be used as the sender of the L1MessageTx transaction, enabling a third party to send an enforced transaction on behalf of the user and cover the relay fee. It is essential to note that both functions require the sender to be an EOA.
Function Signatures:
The sendTransaction functions deduct the message relay fee and transfer it to the L1 feeVault account. However, the value passed to the function indicates the ETH amount to be transferred from the sender's account on L2, not L1. Therefore, the
msg.value
only needs to account for the message relay fee. If the ETH amount in the message fails to cover this fee, the transaction will not succeed. Excess fees are refunded to the transaction sender in the first function and to the refund address in the second function. Finally, the EnforcedTxGateway calls L1MessageQueue.appendEnforcedTransaction to add the transaction to the message queue.
Retrying Failed Messages
If an L1MessageTx transaction fails on L2 due to inadequate gas, users can replay the message with a higher gas limit using the replayMessage method. This method allows users to resend the same information as the previous failed message but with an increased gas limit. This new message will be treated as a new L1MessageTx transaction on L2. Note that the gas fee for the previous failed transaction will not be refunded, as it has already been processed on L2.
Replay Function Signature: The L2WischainMessenger contract maintains a record of all L1 messages successfully relayed to L2. Consequently, if the original message is successful, the transaction for the replayed message will be reverted on L2.
Message Relay Fee
The L2GasPriceOracle contract deployed on L1 calculates the relay fee for messages based on their gas limit. This contract retains the l2BaseFee in its storage, updated by a dedicated relayer currently operated by Wischain. The relay fee for L1-to-L2 messages is computed as follows:
Relay Fee = gasLimit × l2BaseFee
Upgrade Notice
During the upcoming Bridge Upgrade in February 2024, the L2GasPriceOracle will be deprecated, with its functionalities integrated into the L1MessageQueueWithGasPriceOracle contract. This upgrade is expected to be finalized on February 21, 2024, following a two-week timelock. The Wischain Sepolia network has already undergone this upgrade. More information can be found here.
Address Alias
Due to the behavior of the CREATE opcode, it is possible for a contract to be deployed at the same address on both L1 and L2, albeit with different bytecode. To mitigate the risk of malicious activities, the bridge implements an address aliasing mechanism when the message sender is a contract on L1. The aliased sender address of the L1 message transaction is calculated as:
Aliased Address = l1_contract_address + offset, where offset = 0x........
Sending Messages from L2 to L1 in Wischain
L2 to L1 Workflow
The process of sending messages from Layer 2 (L2) to Layer 1 (L1) in the Wischain ecosystem is facilitated by the L2WischainMessenger contract. This contract enables users to send arbitrary messages, which can be used to withdraw tokens or invoke contracts on the L1 blockchain. To streamline the token withdrawal process, Wischain provides several standard token gateways. For comprehensive information on these L2 token gateways, please refer to the Withdraw Gateways documentation.
The L2WischainMessenger contract includes a function called sendMessage. Unlike the L1WischainMessenger.sendMessage function, the gas limit parameter in this function is ignored. This is because the execution transaction for withdrawals on L1 is initiated by users, with transaction fees being paid directly on the L1 network. Consequently, the sendMessage function requires the msg.value
to match the specified parameter value. The function encodes the arguments into a cross-domain message, adhering to the same schema used in the L1WischainMessenger.
sendMessage Function Signatures
When the sendMessage function is invoked, the hash of the cross-domain message is added to the L2MessageQueue by calling its appendMessage function. The L2MessageQueue contract maintains a structure known as the Withdraw Trie, which is an append-only Merkle tree. Each time a new message is appended to the queue, the contract inserts it into the Withdraw Trie and updates the root hash of the trie accordingly.
Once the transaction batch containing users' L2-to-L1 messages is finalized on the L1 rollup contract, users are required to submit the corresponding Execute Withdrawal transactions. This step involves calling the relayMessageWithProof method in the L1WischainMessenger contract, which facilitates the execution of the withdrawal on L1. The use of Merkle proofs ensures that the finalization of withdrawal transactions on L1 is trustless, allowing users or authorized third parties to submit these transactions on their behalf.
To simplify the construction of a withdrawal Merkle Inclusion Proof (MIP), Wischain offers a service known as the Bridge History API. This API monitors SentMessage events emitted from the L2WischainMessenger and maintains an internal Withdraw Trie. It continuously generates Merkle proofs for every withdrawal message. Both users and third-party services can query these Merkle proofs from the Bridge History API to include in their Execute Withdrawal transactions.
It is important to note that the Execute Withdrawal transactions can be submitted either by users themselves or by third-party services acting on their behalf.
Withdraw Trie Structure
The Withdraw Trie is structured as a dense binary Merkle tree. In this structure, the hash of a leaf node is derived from the message hash, while the hash of a non-leaf node is calculated as the Keccak hash digest of the concatenated hashes of its two child nodes. The depth of the Withdraw Trie dynamically increases based on the number of messages appended to it.
For instance, when the number of leaf nodes does not fully saturate a complete binary tree, padding is applied to the leaf nodes with a hash of zero. This is illustrated in the tree structures. When appending a new message to a non-complete Withdraw Trie, any padding node is replaced by a new leaf node containing the actual message hash.
This design ensures that the structure remains efficient and allows for quick verification of the messages contained within the Withdraw Trie, further enhancing the trustless nature of the withdrawal process in the Wischain ecosystem.
Last updated