## Message传递 ### L1 -> L2 The Mailbox only cares about transferring information from L2 to L1 and the other way but does not hold or transfer any assets (ETH, ERC20 tokens, or NFTs) Mailbox只关心从L2到L1的消息传递,不持有或转移任何资产。 目前只用于L1 -> L2层的消息传递,或者用于实施多层协议。与L1 -> L2 message传递相关的函数为: ``` requestL2Transaction:L1至L2的ETH充值用到此方法。 l2TransactionBaseCost:估计从L1请求L2交易的ETH成本。 serializeL2Transaction: ``` > 注意:每一笔L1 -> L2层的交易,系统程序都会发送一条固定格式的L2 -> L1 log 实际操作: L1至L2的桥合约一层牵涉两个合约,核心合约依旧是`MailBox`合约,核心方法为`requestL2Transaction`方法,最后会打印`NewPriorityRequest`事件。 | layer | contractName | contractAddress | | :---: | :----------------: | ------------------------------------------------------------ | | L1 | L1ERC20BridgeProxy | [0x57891966931Eb4Bb6FB81430E6cE0A03AAbDe063](https://etherscan.io/address/0x57891966931Eb4Bb6FB81430E6cE0A03AAbDe063#code) | | L1 | L1ERC20BridgeImpl | [0x7e5E66B01fe43293545eaB98ec4D31784A5Efa84](https://etherscan.io/address/0x7e5E66B01fe43293545eaB98ec4D31784A5Efa84#code) | | L1 | MailboxFacetProxy | [0x32400084C286CF3E17e7B677ea9583e60a000324](https://etherscan.io/address/0x32400084c286cf3e17e7b677ea9583e60a000324) | | L1 | MailboxFacetImpl | [0xb2097DBe4410B538a45574B1FCD767E2303c7867](https://etherscan.io/address/0xb2097dbe4410b538a45574b1fcd767e2303c7867) | 示例交易:[0x4f82205070222bc3a2149a73791f970eba511f421b1ed80daf0464cc0b0dfdec](https://etherscan.io/tx/0x4f82205070222bc3a2149a73791f970eba511f421b1ed80daf0464cc0b0dfdec) bridge合约`deposit`方法通过调用Mailbox合约`requestL2Transaction`方法最后打印`NewPriorityRequest`事件完成交易。 ### L2 -> L1 L2至L1的传输只基于information传输,不基于交易传输。 一个特殊的`zkEVM`操作码会将所有`l2ToL1Log`存储在 L2 block 中。当`validator`发送一个`L2 block to the L1`时,会发送所有的`l2ToL1Logs`。不久之后,用户能够在`L1`上看到自己的`l2ToL1logs`和证明。 在`L1`,每个`L2` block,都会计算出一个` Merkle root`,因此,用户可以为每一个`l2ToL1Logs`提供`Merkle proof`。 从官方给出的示例中,在L2层的`Receive`合约中,调用`proveL2MessageInclusion`方法。 ```solidity /// @notice Prove that a specific arbitrary-length message was sent in a specific L2 block number /// @param _blockNumber The executed L2 block number in which the message appeared /// @param _index The position in the L2 logs Merkle tree of the l2Log that was sent with the message /// @param _message Information about the sent message: sender address, the message itself, tx index in the L2 block where the message was sent /// @param _proof Merkle proof for inclusion of L2 log that was sent with the message /// @return Whether the proof is valid function proveL2MessageInclusion( uint256 _blockNumber, uint256 _index, L2Message memory _message, bytes32[] calldata _proof ) public view returns (bool) { return _proveL2LogInclusion(_blockNumber, _index, _L2MessageToLog(_message), _proof); } ``` > L2至L1不能直接通信,需要经过zkSync服务器。首先在L2发起交易,经过服务器发起交易调用`MailboxFacet`合约`proveL2MessageInclusion`函数.其验证方式为merkle树验证二层某一区块内有需要验证的log。 ```solidity bool success = zksync.proveL2MessageInclusion( _l2BlockNumber, _index, message, _proof ); require(success, "Failed to prove message inclusion"); ``` L2资金提取至L1有三种方式: - Withdraw 此种模式为正常交易模式,适用于有自己账户并且拥有私钥。 - ForcedExit 此模式依旧为正常交易模式,适用于无法设置签名密钥的账户(智能合约)提款。 - FullExit 此种模式为“优先操作”模式,此种模式从L1发起交易,此种模式下,即使节点停止工作,用户也可以提取资金。适用于遭到审查用户直接提取资金。 | layer | contractName | contractAddress | | :---: | :----------: | :----------------------------------------------------------: | | L2 | L2EthToken | [0x000000000000000000000000000000000000800A](https://goerli.explorer.zksync.io/address/0x000000000000000000000000000000000000800A#contract) | | L1 | 未开源合约 | [0x4cCF429019abAa7e06AAB09Dbc2e05f33C11429c](https://goerli.etherscan.io/address/0x4ccf429019abaa7e06aab09dbc2e05f33c11429c#code) | 以Withdraw方法为例: L2层发起Withdraw交易:[0x89cf50c8af20043514a30e99303a1e9f4ee791edcbed4b03993a86ce56c9197a](https://goerli.explorer.zksync.io/tx/0x89cf50c8af20043514a30e99303a1e9f4ee791edcbed4b03993a86ce56c9197a) 交易调用Withdraw方法,主要代码为: ```solidity /// @notice Initiate the ETH withdrawal, funds will be available to claim on L1 `finalizeEthWithdrawal` method. /// @param _l1Receiver The address on L1 to receive the funds. /// @dev The function accepts the `msg.value`. Since this contract holds the mapping of all ether /// balances of the system, the sent `msg.value` is added to the `this` balance before the call. /// So the balance of `address(this)` is always bigger or equal to the `msg.value`! function withdraw(address _l1Receiver) external payable override { uint256 amount = msg.value; // Silent burning of the ether unchecked { // This is safe, since this contract holds the ether balances, and if user // send a `msg.value` it will be added to the contract (`this`) balance. balance[address(this)] -= amount; totalSupply -= amount; } // Send the L2 log, a user could use it as proof of the withdrawal bytes memory message = _getL1WithdrawMessage(_l1Receiver, amount); L1_MESSENGER_CONTRACT.sendToL1(message); emit Withdrawal(msg.sender, _l1Receiver, amount); } /// @dev Get the message to be sent to L1 to initiate a withdrawal. function _getL1WithdrawMessage(address _to, uint256 _amount) internal pure returns (bytes memory) { return abi.encodePacked(IMailbox.finalizeEthWithdrawal.selector, _to, _amount); } ``` 二层发起交易,从Goerli链上合约转移ETH至个人账户 示例交易:[0x21016f74e2cdc6e746815452e264ec059521ba943b3486a8bc235156b0aac2d2](https://goerli.etherscan.io/tx/0x21016f74e2cdc6e746815452e264ec059521ba943b3486a8bc235156b0aac2d2) 此合约并未开源,仅知道调用`finalizeWithdrawals(tuple[] requests)`函数。此函数在L1ERC20Bridge合约中也有出现,出现形式为`finalizeWithdrawal`,依旧为Merkle tree 验证log形式。 ```solidity /// @notice Finalize the withdrawal and release funds /// @param _l2BlockNumber The L2 block number where the withdrawal was processed /// @param _l2MessageIndex The position in the L2 logs Merkle tree of the l2Log that was sent with the message /// @param _l2TxNumberInBlock The L2 transaction number in a block, in which the log was sent /// @param _message The L2 withdraw data, stored in an L2 -> L1 message /// @param _merkleProof The Merkle proof of the inclusion L2 -> L1 message about withdrawal initialization function finalizeWithdrawal( uint256 _l2BlockNumber, uint256 _l2MessageIndex, uint16 _l2TxNumberInBlock, bytes calldata _message, bytes32[] calldata _merkleProof ) external nonReentrant senderCanCallFunction(allowList) {} ``` ## ## Github库 git@github.com:matter-labs/v2-testnet-contracts.git git@github.com:matter-labs/era-contracts.git #### NFT 跨链 Goerli: 0x23f59730F2416078546dfDE95CA5A8Ec6C4272f4 L2:0x1d3E15C85552F8B224125edb28D5180a9f5Cabc3 MInt NFT L2: [0x0a1b702b1021ede69ee8cc528e0cdce1247135e5958c1c850cd1d1d3448c7981](https://goerli.explorer.zksync.io/tx/0x0a1b702b1021ede69ee8cc528e0cdce1247135e5958c1c850cd1d1d3448c7981) WithDraw NFT to L1: [0xcfdbd4ce95200144cfd386f558a3615cf430f642c849358271b92718ef3ba9ab](https://goerli.explorer.zksync.io/tx/0xcfdbd4ce95200144cfd386f558a3615cf430f642c849358271b92718ef3ba9ab)