Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0x79b6eAbfFAa958FDF2Aa2Bf632878bD323DCbF69
Balance 0 ETH
Nonce 1
Code Size 8475 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

8475 bytes
0x608060405260043610610134575f3560e01c80638da5cb5b116100a8578063cb23bcb51161006d578063cb23bcb5146103b7578063cd172b23146103ea578063e70fc93b1461041d578063ea7ec51414610456578063f2fde38b14610482578063f8c8765e146104a1575f80fd5b80638da5cb5b146103165780639eee46a114610333578063b2267a7b14610366578063bedb86fb14610379578063c311b6fc14610398575f80fd5b80635c975abb116100f95780635c975abb146102265780635f7b15771461023d5780636e296e4514610250578063715018a61461026f578063797594b014610283578063846d4d7a146102b6575f80fd5b8063088681a7146101475780632a6cccb21461018a5780633e83496c146101a9578063478222c2146101f45780635500410514610213575f80fd5b36610143576101416104c0565b005b5f80fd5b348015610152575f80fd5b50610175610161366004611b10565b60fc6020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b348015610195575f80fd5b506101416101a4366004611b42565b610521565b3480156101b4575f80fd5b506101dc7f00000000000000000000000072cacbcfde2d1e19122f8a36a4d6676cd39d7a5d81565b6040516001600160a01b039091168152602001610181565b3480156101ff575f80fd5b5060cb546101dc906001600160a01b031681565b610141610221366004611c28565b61058a565b348015610231575f80fd5b5060655460ff16610175565b61014161024b366004611cbf565b610aea565b34801561025b575f80fd5b5060c9546101dc906001600160a01b031681565b34801561027a575f80fd5b50610141610b3e565b34801561028e575f80fd5b506101dc7f000000000000000000000000781e90f1c8fc4611c9b7497c3b47f99ef6969cbc81565b3480156102c1575f80fd5b506102f66102d0366004611b10565b6101016020525f90815260409020546001600160801b0380821691600160801b90041682565b604080516001600160801b03938416815292909116602083015201610181565b348015610321575f80fd5b506033546001600160a01b03166101dc565b34801561033e575f80fd5b506101dc7f00000000000000000000000056971da63a3c0205184fef096e9ddfc7a8c2d18a81565b610141610374366004611d5d565b610b4f565b348015610384575f80fd5b50610141610393366004611dc5565b610b6a565b3480156103a3575f80fd5b506101416103b2366004611de0565b610b8b565b3480156103c2575f80fd5b506101dc7f000000000000000000000000a13baf47339d63b743e7da8741db5456dac1e55681565b3480156103f5575f80fd5b506101dc7f0000000000000000000000000d7e906bd9cafa154b048cfa766cc1e54e39af9b81565b348015610428575f80fd5b50610448610437366004611b10565b60fb6020525f908152604090205481565b604051908152602001610181565b348015610461575f80fd5b50610448610470366004611b10565b6101026020525f908152604090205481565b34801561048d575f80fd5b5061014161049c366004611b42565b61105c565b3480156104ac575f80fd5b506101416104bb366004611ea9565b6110d2565b6033546001600160a01b0316331461051f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b565b6105296104c0565b60cb80546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527f4aadc32827849f797733838c61302f7f56d2b6db28caa175eb3f7f8e5aba25f5910160405180910390a15050565b610592611213565b60c9546001600160a01b03166001146105ed5760405162461bcd60e51b815260206004820152601f60248201527f4d65737361676520697320616c726561647920696e20657865637574696f6e006044820152606401610516565b5f6105fb8888888888611259565b90505f818051906020012090505f60fb5f8381526020019081526020015f2054116106775760405162461bcd60e51b815260206004820152602660248201527f50726f7669646564206d65737361676520686173206e6f74206265656e20656e6044820152651c5d595d595960d21b6064820152608401610516565b5f81815260fd602052604090205460ff16156106d55760405162461bcd60e51b815260206004820152601760248201527f4d65737361676520616c72656164792064726f707065640000000000000000006044820152606401610516565b604051636bb825d760e11b815263ffffffff851660048201525f907f00000000000000000000000056971da63a3c0205184fef096e9ddfc7a8c2d18a6001600160a01b03169063d7704bae90602401602060405180830381865afa15801561073f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107639190611efa565b9050803410156107b55760405162461bcd60e51b815260206004820152601e60248201527f496e73756666696369656e74206d73672e76616c756520666f722066656500006044820152606401610516565b80156108585760cb546040515f916001600160a01b03169083908381818185875af1925050503d805f8114610805576040519150601f19603f3d011682016040523d82523d5f602084013e61080a565b606091505b50509050806108565760405162461bcd60e51b81526020600482015260186024820152774661696c656420746f20646564756374207468652066656560401b6044820152606401610516565b505b5f7f00000000000000000000000056971da63a3c0205184fef096e9ddfc7a8c2d18a6001600160a01b031663fd0ad31e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108b5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108d99190611efa565b604051634d8acbc160e11b81529091506001600160a01b037f00000000000000000000000056971da63a3c0205184fef096e9ddfc7a8c2d18a1690639b1597829061094c907f000000000000000000000000781e90f1c8fc4611c9b7497c3b47f99ef6969cbc908a908990600401611f5e565b5f604051808303815f87803b158015610963575f80fd5b505af1158015610975573d5f803e3d5ffd5b5050505f848152610101602090815260408083208151808301909252546001600160801b038082168352600160801b90910416918101829052925090036109cf575f8281526101026020526040902060018a0190556109f7565b80602001516001016001600160801b03166101025f8481526020019081526020015f20819055505b6001600160801b0380831660208084019182528351600101831684525f87815261010190915260409020835191518316600160801b029190921617905534838103908414610adb575f876001600160a01b0316826040515f6040518083038185875af1925050503d805f8114610a88576040519150601f19603f3d011682016040523d82523d5f602084013e610a8d565b606091505b5050905080610ad95760405162461bcd60e51b81526020600482015260186024820152774661696c656420746f20726566756e64207468652066656560401b6044820152606401610516565b505b50505050505050505050505050565b610af2611213565b610b36868686868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152508892508791506112a99050565b505050505050565b610b466104c0565b61051f5f6116dc565b610b57611213565b610b6484848484336112a9565b50505050565b610b726104c0565b8015610b8357610b8061172d565b50565b610b80611787565b610b93611213565b60c9546001600160a01b0316600114610bee5760405162461bcd60e51b815260206004820152601f60248201527f4d65737361676520697320616c726561647920696e20657865637574696f6e006044820152606401610516565b5f610bfc8787878787611259565b80516020918201205f81815260fc90925260409091205490915060ff1615610c785760405162461bcd60e51b815260206004820152602960248201527f4d6573736167652077617320616c7265616479207375636365737366756c6c7960448201526808195e1958dd5d195960ba1b6064820152608401610516565b81516040516308b50fa160e11b815260048101919091527f000000000000000000000000a13baf47339d63b743e7da8741db5456dac1e5566001600160a01b03169063116a1f4290602401602060405180830381865afa158015610cde573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d029190611f96565b610d475760405162461bcd60e51b815260206004820152601660248201527510985d18da081a5cc81b9bdd08199a5b985b1a5e995960521b6044820152606401610516565b815160405163ea5f084f60e01b81525f916001600160a01b037f000000000000000000000000a13baf47339d63b743e7da8741db5456dac1e556169163ea5f084f91610d999160040190815260200190565b602060405180830381865afa158015610db4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610dd89190611efa565b9050610dea81838786602001516117c0565b610e265760405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b210383937b7b360991b6044820152606401610516565b507f0000000000000000000000000d7e906bd9cafa154b048cfa766cc1e54e39af9b6001600160a01b0316866001600160a01b03161480610e9857507f00000000000000000000000056971da63a3c0205184fef096e9ddfc7a8c2d18a6001600160a01b0316866001600160a01b0316145b80610ed457507f00000000000000000000000072cacbcfde2d1e19122f8a36a4d6676cd39d7a5d6001600160a01b0316866001600160a01b0316145b15610ef25760405163f254c74d60e01b815260040160405180910390fd5b610efb86611888565b60c9546001600160a01b0390811690881603610f525760405162461bcd60e51b815260206004820152601660248201527524b73b30b634b21036b2b9b9b0b3b29039b2b73232b960511b6044820152606401610516565b60c980546001600160a01b0319166001600160a01b03898116919091179091556040515f918816908790610f87908790611fb1565b5f6040518083038185875af1925050503d805f8114610fc1576040519150601f19603f3d011682016040523d82523d5f602084013e610fc6565b606091505b505060c980546001600160a01b031916600117905590508015611027575f82815260fc6020526040808220805460ff191660011790555183917f4641df4a962071e12719d8c8c8e5ac7fc4d97b927346a3d7a335b1f7517e133c91a2611052565b60405182907f99d0e048484baa1b1540b1367cb128acd7ab2946d1ed91ec10e3c85e4bf51b8f905f90a25b5050505050505050565b6110646104c0565b6001600160a01b0381166110c95760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610516565b610b80816116dc565b5f54610100900460ff16158080156110f057505f54600160ff909116105b806111095750303b15801561110957505f5460ff166001145b61116c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610516565b5f805460ff19166001179055801561118d575f805461ff0019166101001790555b61119785856118d6565b60fe80546001600160a01b038086166001600160a01b03199283161790925560ff805492851692909116919091179055801561120c575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b60655460ff161561051f5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610516565b60608585858585604051602401611274959493929190611fcc565b60408051601f198184030181529190526020810180516001600160e01b0316634778999760e11b179052905095945050505050565b6112b1611956565b5f7f00000000000000000000000056971da63a3c0205184fef096e9ddfc7a8c2d18a6001600160a01b031663fd0ad31e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561130e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113329190611efa565b90505f6113423388888589611259565b604051636bb825d760e11b8152600481018690529091505f906001600160a01b037f00000000000000000000000056971da63a3c0205184fef096e9ddfc7a8c2d18a169063d7704bae90602401602060405180830381865afa1580156113aa573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113ce9190611efa565b90506113da8782612010565b3410156114225760405162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e74206d73672e76616c756560501b6044820152606401610516565b80156114c55760cb546040515f916001600160a01b03169083908381818185875af1925050503d805f8114611472576040519150601f19603f3d011682016040523d82523d5f602084013e611477565b606091505b50509050806114c35760405162461bcd60e51b81526020600482015260186024820152774661696c656420746f20646564756374207468652066656560401b6044820152606401610516565b505b604051634d8acbc160e11b81526001600160a01b037f00000000000000000000000056971da63a3c0205184fef096e9ddfc7a8c2d18a1690639b15978290611535907f000000000000000000000000781e90f1c8fc4611c9b7497c3b47f99ef6969cbc9089908790600401612035565b5f604051808303815f87803b15801561154c575f80fd5b505af115801561155e573d5f803e3d5ffd5b505050505f8280519060200120905060fb5f8281526020019081526020015f20545f146115c25760405162461bcd60e51b81526020600482015260126024820152714475706c696361746564206d65737361676560701b6044820152606401610516565b5f81815260fb602052604090204290556001600160a01b038916336001600160a01b03167f104371f3b442861a2a7b82a070afbbaab748bb13757bf47769e170e37809ec1e8a878a8c60405161161b949392919061205b565b60405180910390a3348290038881039089146116cd575f866001600160a01b0316826040515f6040518083038185875af1925050503d805f811461167a576040519150601f19603f3d011682016040523d82523d5f602084013e61167f565b606091505b50509050806116cb5760405162461bcd60e51b81526020600482015260186024820152774661696c656420746f20726566756e64207468652066656560401b6044820152606401610516565b505b505050505061120c6001609755565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b611735611213565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861176a3390565b6040516001600160a01b03909116815260200160405180910390a1565b61178f6119b6565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa3361176a565b5f602082516117cf919061209d565b1561180c5760405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b210383937b7b360991b6044820152606401610516565b5f6020835161181b91906120b0565b90505f5b8181101561187b5760208181028501015161183b60028761209d565b5f03611855575f8781526020829052604090209650611865565b5f81815260208890526040902096505b6118706002876120b0565b95505060010161181f565b5050509290911492915050565b306001600160a01b03821603610b805760405162461bcd60e51b81526020600482015260136024820152722337b93134b2103a379031b0b6361039b2b63360691b6044820152606401610516565b5f54610100900460ff166118fc5760405162461bcd60e51b8152600401610516906120c3565b6119046119ff565b61190c611a2d565b611914611a5b565b60c980546001600160a01b03191660011790556001600160a01b038116156119525760cb80546001600160a01b0319166001600160a01b0383161790555b5050565b6002609754036119a85760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610516565b6002609755565b6001609755565b60655460ff1661051f5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610516565b5f54610100900460ff16611a255760405162461bcd60e51b8152600401610516906120c3565b61051f611a89565b5f54610100900460ff16611a535760405162461bcd60e51b8152600401610516906120c3565b61051f611ab8565b5f54610100900460ff16611a815760405162461bcd60e51b8152600401610516906120c3565b61051f611aea565b5f54610100900460ff16611aaf5760405162461bcd60e51b8152600401610516906120c3565b61051f336116dc565b5f54610100900460ff16611ade5760405162461bcd60e51b8152600401610516906120c3565b6065805460ff19169055565b5f54610100900460ff166119af5760405162461bcd60e51b8152600401610516906120c3565b5f60208284031215611b20575f80fd5b5035919050565b80356001600160a01b0381168114611b3d575f80fd5b919050565b5f60208284031215611b52575f80fd5b611b5b82611b27565b9392505050565b634e487b7160e01b5f52604160045260245ffd5b6040805190810167ffffffffffffffff81118282101715611b9957611b99611b62565b60405290565b5f82601f830112611bae575f80fd5b813567ffffffffffffffff80821115611bc957611bc9611b62565b604051601f8301601f19908116603f01168101908282118183101715611bf157611bf1611b62565b81604052838152866020858801011115611c09575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f805f805f805f60e0888a031215611c3e575f80fd5b611c4788611b27565b9650611c5560208901611b27565b95506040880135945060608801359350608088013567ffffffffffffffff811115611c7e575f80fd5b611c8a8a828b01611b9f565b93505060a088013563ffffffff81168114611ca3575f80fd5b9150611cb160c08901611b27565b905092959891949750929550565b5f805f805f8060a08789031215611cd4575f80fd5b611cdd87611b27565b955060208701359450604087013567ffffffffffffffff80821115611d00575f80fd5b818901915089601f830112611d13575f80fd5b813581811115611d21575f80fd5b8a6020828501011115611d32575f80fd5b60208301965080955050505060608701359150611d5160808801611b27565b90509295509295509295565b5f805f8060808587031215611d70575f80fd5b611d7985611b27565b935060208501359250604085013567ffffffffffffffff811115611d9b575f80fd5b611da787828801611b9f565b949793965093946060013593505050565b8015158114610b80575f80fd5b5f60208284031215611dd5575f80fd5b8135611b5b81611db8565b5f805f805f8060c08789031215611df5575f80fd5b611dfe87611b27565b9550611e0c60208801611b27565b94506040870135935060608701359250608087013567ffffffffffffffff80821115611e36575f80fd5b611e428a838b01611b9f565b935060a0890135915080821115611e57575f80fd5b908801906040828b031215611e6a575f80fd5b611e72611b76565b82358152602083013582811115611e87575f80fd5b611e938c828601611b9f565b6020830152508093505050509295509295509295565b5f805f8060808587031215611ebc575f80fd5b611ec585611b27565b9350611ed360208601611b27565b9250611ee160408601611b27565b9150611eef60608601611b27565b905092959194509250565b5f60208284031215611f0a575f80fd5b5051919050565b5f5b83811015611f2b578181015183820152602001611f13565b50505f910152565b5f8151808452611f4a816020860160208601611f11565b601f01601f19169290920160200192915050565b6001600160a01b038416815263ffffffff831660208201526060604082018190525f90611f8d90830184611f33565b95945050505050565b5f60208284031215611fa6575f80fd5b8151611b5b81611db8565b5f8251611fc2818460208701611f11565b9190910192915050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a0608082018190525f9061200590830184611f33565b979650505050505050565b8082018082111561202f57634e487b7160e01b5f52601160045260245ffd5b92915050565b60018060a01b0384168152826020820152606060408201525f611f8d6060830184611f33565b848152836020820152826040820152608060608201525f61207f6080830184611f33565b9695505050505050565b634e487b7160e01b5f52601260045260245ffd5b5f826120ab576120ab612089565b500690565b5f826120be576120be612089565b500490565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea164736f6c6343000818000a

Verified Source Code Partial Match

Compiler: v0.8.24+commit.e11b9ed9 EVM: cancun Optimization: Yes (200 runs)
L1ScrollMessenger.sol 326 lines
// SPDX-License-Identifier: MIT
pragma solidity =0.8.24;

import {IScrollChain} from "./rollup/IScrollChain.sol";
import {IL1MessageQueueV1} from "./rollup/IL1MessageQueueV1.sol";
import {IL1MessageQueueV2} from "./rollup/IL1MessageQueueV2.sol";
import {IL1ScrollMessenger} from "./IL1ScrollMessenger.sol";
import {ScrollConstants} from "../libraries/constants/ScrollConstants.sol";
import {IScrollMessenger} from "../libraries/IScrollMessenger.sol";
import {ScrollMessengerBase} from "../libraries/ScrollMessengerBase.sol";
import {WithdrawTrieVerifier} from "../libraries/verifier/WithdrawTrieVerifier.sol";

// solhint-disable avoid-low-level-calls
// solhint-disable not-rely-on-time
// solhint-disable reason-string

/// @title L1ScrollMessenger
/// @notice The `L1ScrollMessenger` contract can:
///
/// 1. send messages from layer 1 to layer 2;
/// 2. relay messages from layer 2 layer 1;
/// 3. replay failed message by replacing the gas limit;
/// 4. drop expired message due to sequencer problems.
///
/// @dev All deposited Ether (including `WETH` deposited throng `L1WETHGateway`) will locked in
/// this contract.
///
/// The messages sent through this contract may failed due to out of gas or some contract errors layer 2. In such case,
/// users can initiate `replayMessage` to retry this message in layer 2. If it is because out of gas, users can provide
/// a larger `gasLimit`. Users need also to pay the cross domain relay fee again.
///
/// The messages sent through this contract may possibly be skipped in layer 2 due to circuit capacity overflow.
/// In such case, users can initiate `dropMessage` to claim refunds. But the cross domain relay fee won't be refunded.
contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
    /**********
     * Errors *
     **********/

    error ErrorForbidToCallMessageQueue();

    /*************
     * Constants *
     *************/

    /// @notice The address of Rollup contract.
    address public immutable rollup;

    /// @notice The address of L1MessageQueueV1 contract.
    address public immutable messageQueueV1;

    /// @notice The address of L1MessageQueueV2 contract.
    address public immutable messageQueueV2;

    /// @notice The address of `EnforcedTxGateway`.
    address public immutable enforcedTxGateway;

    /***********
     * Structs *
     ***********/

    struct ReplayState {
        // The number of replayed times.
        uint128 times;
        // The queue index of lastest replayed one. If it is zero, it means the message has not been replayed.
        uint128 lastIndex;
    }

    /*************
     * Variables *
     *************/

    /// @notice Mapping from L1 message hash to the timestamp when the message is sent.
    mapping(bytes32 => uint256) public messageSendTimestamp;

    /// @notice Mapping from L2 message hash to a boolean value indicating if the message has been successfully executed.
    mapping(bytes32 => bool) public isL2MessageExecuted;

    /// @notice Mapping from L1 message hash to drop status.
    /// @custom:deprecated This is no longer used.
    // slither-disable-next-line uninitialized-state
    mapping(bytes32 => bool) private __isL1MessageDropped;

    /// @dev The storage slot used as Rollup contract, which is deprecated now.
    /// @custom:deprecated This is no longer used.
    address private __rollup;

    /// @dev The storage slot used as L1MessageQueue contract, which is deprecated now.
    /// @custom:deprecated This is no longer used.
    address private __messageQueue;

    /// @dev The maximum number of times each L1 message can be replayed.
    /// @custom:deprecated This is no longer used.
    uint256 private __maxReplayTimes;

    /// @notice Mapping from L1 message hash to replay state.
    mapping(bytes32 => ReplayState) public replayStates;

    /// @notice Mapping from queue index to previous replay queue index.
    ///
    /// @dev If a message `x` was replayed 3 times with index `q1`, `q2` and `q3`, the
    /// value of `prevReplayIndex` and `replayStates` will be `replayStates[hash(x)].lastIndex = q3`,
    /// `replayStates[hash(x)].times = 3`, `prevReplayIndex[q3] = q2`, `prevReplayIndex[q2] = q1`,
    /// `prevReplayIndex[q1] = x` and `prevReplayIndex[x]=nil`.
    ///
    /// @dev The index `x` that `prevReplayIndex[x]=nil` is used as the termination of the list.
    /// Usually we use `0` to represent `nil`, but we cannot distinguish it with the first message
    /// with index zero. So a nonzero offset `1` is added to the value of `prevReplayIndex[x]` to
    /// avoid such situation.
    mapping(uint256 => uint256) public prevReplayIndex;

    /***************
     * Constructor *
     ***************/

    constructor(
        address _counterpart,
        address _rollup,
        address _messageQueueV1,
        address _messageQueueV2,
        address _enforcedTxGateway
    ) ScrollMessengerBase(_counterpart) {
        _disableInitializers();

        rollup = _rollup;
        messageQueueV1 = _messageQueueV1;
        messageQueueV2 = _messageQueueV2;
        enforcedTxGateway = _enforcedTxGateway;
    }

    /// @notice Initialize the storage of L1ScrollMessenger.
    ///
    /// @dev The parameters `_counterpart`, `_rollup` and `_messageQueue` are no longer used.
    ///
    /// @param _counterpart The address of L2ScrollMessenger contract in L2.
    /// @param _feeVault The address of fee vault, which will be used to collect relayer fee.
    /// @param _rollup The address of ScrollChain contract.
    /// @param _messageQueue The address of L1MessageQueue contract.
    function initialize(
        address _counterpart,
        address _feeVault,
        address _rollup,
        address _messageQueue
    ) public initializer {
        ScrollMessengerBase.__ScrollMessengerBase_init(_counterpart, _feeVault);

        __rollup = _rollup;
        __messageQueue = _messageQueue;
    }

    /*****************************
     * Public Mutating Functions *
     *****************************/

    /// @inheritdoc IScrollMessenger
    function sendMessage(
        address _to,
        uint256 _value,
        bytes memory _message,
        uint256 _gasLimit
    ) external payable override whenNotPaused {
        _sendMessage(_to, _value, _message, _gasLimit, _msgSender());
    }

    /// @inheritdoc IScrollMessenger
    function sendMessage(
        address _to,
        uint256 _value,
        bytes calldata _message,
        uint256 _gasLimit,
        address _refundAddress
    ) external payable override whenNotPaused {
        _sendMessage(_to, _value, _message, _gasLimit, _refundAddress);
    }

    /// @inheritdoc IL1ScrollMessenger
    function relayMessageWithProof(
        address _from,
        address _to,
        uint256 _value,
        uint256 _nonce,
        bytes memory _message,
        L2MessageProof memory _proof
    ) external override whenNotPaused notInExecution {
        bytes32 _xDomainCalldataHash = keccak256(_encodeXDomainCalldata(_from, _to, _value, _nonce, _message));
        require(!isL2MessageExecuted[_xDomainCalldataHash], "Message was already successfully executed");

        {
            require(IScrollChain(rollup).isBatchFinalized(_proof.batchIndex), "Batch is not finalized");
            bytes32 _messageRoot = IScrollChain(rollup).withdrawRoots(_proof.batchIndex);
            require(
                WithdrawTrieVerifier.verifyMerkleProof(_messageRoot, _xDomainCalldataHash, _nonce, _proof.merkleProof),
                "Invalid proof"
            );
        }

        // @note check more `_to` address to avoid attack in the future when we add more gateways.
        if (_to == messageQueueV1 || _to == messageQueueV2 || _to == enforcedTxGateway) {
            revert ErrorForbidToCallMessageQueue();
        }
        _validateTargetAddress(_to);

        // @note This usually will never happen, just in case.
        require(_from != xDomainMessageSender, "Invalid message sender");

        xDomainMessageSender = _from;
        // xDomainMessageSender serves as reentrancy guard (notInExecution modifier).
        // slither-disable-next-line reentrancy-eth
        (bool success, ) = _to.call{value: _value}(_message);
        // reset value to refund gas.
        xDomainMessageSender = ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER;

        if (success) {
            isL2MessageExecuted[_xDomainCalldataHash] = true;
            emit RelayedMessage(_xDomainCalldataHash);
        } else {
            emit FailedRelayedMessage(_xDomainCalldataHash);
        }
    }

    /// @inheritdoc IL1ScrollMessenger
    function replayMessage(
        address _from,
        address _to,
        uint256 _value,
        uint256 _messageNonce,
        bytes memory _message,
        uint32 _newGasLimit,
        address _refundAddress
    ) external payable override whenNotPaused notInExecution {
        // We will use a different `queueIndex` for the replaced message. However, the original `queueIndex` or `nonce`
        // is encoded in the `_message`. We will check the `xDomainCalldata` on layer 2 to avoid duplicated execution.
        // So, only one message will succeed on layer 2. If one of the message is executed successfully, the other one
        // will revert with "Message was already successfully executed".
        bytes memory _xDomainCalldata = _encodeXDomainCalldata(_from, _to, _value, _messageNonce, _message);
        bytes32 _xDomainCalldataHash = keccak256(_xDomainCalldata);

        require(messageSendTimestamp[_xDomainCalldataHash] > 0, "Provided message has not been enqueued");
        // cannot replay dropped message
        require(!__isL1MessageDropped[_xDomainCalldataHash], "Message already dropped");

        // compute and deduct the messaging fee to fee vault.
        uint256 _fee = IL1MessageQueueV2(messageQueueV2).estimateCrossDomainMessageFee(_newGasLimit);

        // charge relayer fee
        require(msg.value >= _fee, "Insufficient msg.value for fee");
        if (_fee > 0) {
            (bool _success, ) = feeVault.call{value: _fee}("");
            require(_success, "Failed to deduct the fee");
        }

        // enqueue the new transaction
        uint256 _nextQueueIndex = IL1MessageQueueV2(messageQueueV2).nextCrossDomainMessageIndex();
        IL1MessageQueueV2(messageQueueV2).appendCrossDomainMessage(counterpart, _newGasLimit, _xDomainCalldata);

        ReplayState memory _replayState = replayStates[_xDomainCalldataHash];
        // update the replayed message chain.
        unchecked {
            if (_replayState.lastIndex == 0) {
                // the message has not been replayed before.
                prevReplayIndex[_nextQueueIndex] = _messageNonce + 1;
            } else {
                prevReplayIndex[_nextQueueIndex] = _replayState.lastIndex + 1;
            }
        }
        _replayState.lastIndex = uint128(_nextQueueIndex);

        unchecked {
            _replayState.times += 1;
        }
        replayStates[_xDomainCalldataHash] = _replayState;

        // refund fee to `_refundAddress`
        unchecked {
            uint256 _refund = msg.value - _fee;
            if (_refund > 0) {
                (bool _success, ) = _refundAddress.call{value: _refund}("");
                require(_success, "Failed to refund the fee");
            }
        }
    }

    /**********************
     * Internal Functions *
     **********************/

    function _sendMessage(
        address _to,
        uint256 _value,
        bytes memory _message,
        uint256 _gasLimit,
        address _refundAddress
    ) internal nonReentrant {
        // compute the actual cross domain message calldata.
        uint256 _messageNonce = IL1MessageQueueV2(messageQueueV2).nextCrossDomainMessageIndex();
        bytes memory _xDomainCalldata = _encodeXDomainCalldata(_msgSender(), _to, _value, _messageNonce, _message);

        // compute and deduct the messaging fee to fee vault.
        uint256 _fee = IL1MessageQueueV2(messageQueueV2).estimateCrossDomainMessageFee(_gasLimit);
        require(msg.value >= _fee + _value, "Insufficient msg.value");
        if (_fee > 0) {
            (bool _success, ) = feeVault.call{value: _fee}("");
            require(_success, "Failed to deduct the fee");
        }

        // append message to L1MessageQueue
        IL1MessageQueueV2(messageQueueV2).appendCrossDomainMessage(counterpart, _gasLimit, _xDomainCalldata);

        // record the message hash for future use.
        bytes32 _xDomainCalldataHash = keccak256(_xDomainCalldata);

        // normally this won't happen, since each message has different nonce, but just in case.
        require(messageSendTimestamp[_xDomainCalldataHash] == 0, "Duplicated message");
        messageSendTimestamp[_xDomainCalldataHash] = block.timestamp;

        emit SentMessage(_msgSender(), _to, _value, _messageNonce, _gasLimit, _message);

        // refund fee to `_refundAddress`
        unchecked {
            uint256 _refund = msg.value - _fee - _value;
            if (_refund > 0) {
                (bool _success, ) = _refundAddress.call{value: _refund}("");
                require(_success, "Failed to refund the fee");
            }
        }
    }
}
IScrollChain.sol 132 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.24;

/// @title IScrollChain
/// @notice The interface for ScrollChain.
interface IScrollChain {
    /**********
     * Events *
     **********/

    /// @notice Emitted when a new batch is committed.
    /// @param batchIndex The index of the batch.
    /// @param batchHash The hash of the batch.
    event CommitBatch(uint256 indexed batchIndex, bytes32 indexed batchHash);

    /// @notice revert a pending batch.
    /// @param batchIndex The index of the batch.
    /// @param batchHash The hash of the batch
    event RevertBatch(uint256 indexed batchIndex, bytes32 indexed batchHash);

    /// @notice revert a range of batches.
    /// @param startBatchIndex The start batch index of the range (inclusive).
    /// @param finishBatchIndex The finish batch index of the range (inclusive).
    event RevertBatch(uint256 indexed startBatchIndex, uint256 indexed finishBatchIndex);

    /// @notice Emitted when a batch is finalized.
    /// @param batchIndex The index of the batch.
    /// @param batchHash The hash of the batch
    /// @param stateRoot The state root on layer 2 after this batch.
    /// @param withdrawRoot The merkle root on layer2 after this batch.
    event FinalizeBatch(uint256 indexed batchIndex, bytes32 indexed batchHash, bytes32 stateRoot, bytes32 withdrawRoot);

    /// @notice Emitted when owner updates the status of sequencer.
    /// @param account The address of account updated.
    /// @param status The status of the account updated.
    event UpdateSequencer(address indexed account, bool status);

    /// @notice Emitted when owner updates the status of prover.
    /// @param account The address of account updated.
    /// @param status The status of the account updated.
    event UpdateProver(address indexed account, bool status);

    /// @notice Emitted when we enter or exit enforced batch mode.
    /// @param enabled True if we are entering enforced batch mode, false otherwise.
    /// @param lastCommittedBatchIndex The index of the last committed batch.
    event UpdateEnforcedBatchMode(bool enabled, uint256 lastCommittedBatchIndex);

    /*************************
     * Public View Functions *
     *************************/

    /// @return The latest finalized batch index.
    function lastFinalizedBatchIndex() external view returns (uint256);

    /// @param batchIndex The index of the batch.
    /// @return The batch hash of a committed batch.
    function committedBatches(uint256 batchIndex) external view returns (bytes32);

    /// @param batchIndex The index of the batch.
    /// @return The state root of a committed batch.
    function finalizedStateRoots(uint256 batchIndex) external view returns (bytes32);

    /// @param batchIndex The index of the batch.
    /// @return The message root of a committed batch.
    function withdrawRoots(uint256 batchIndex) external view returns (bytes32);

    /// @param batchIndex The index of the batch.
    /// @return Whether the batch is finalized by batch index.
    function isBatchFinalized(uint256 batchIndex) external view returns (bool);

    /*****************************
     * Public Mutating Functions *
     *****************************/

    /// @notice Commit one or more batches after the EuclidV2 upgrade.
    /// @param version The version of the committed batches.
    /// @param parentBatchHash The hash of parent batch.
    /// @param lastBatchHash The hash of the last committed batch after this call.
    /// @dev The batch payload is stored in the blobs.
    function commitBatches(
        uint8 version,
        bytes32 parentBatchHash,
        bytes32 lastBatchHash
    ) external;

    /// @notice Revert pending batches.
    /// @dev one can only revert unfinalized batches.
    /// @param batchHeader The header of the last batch we want to keep.
    function revertBatch(bytes calldata batchHeader) external;

    /// @notice Finalize a list of committed batches (i.e. bundle) on layer 1 after the EuclidV2 upgrade.
    /// @param batchHeader The header of the last batch in this bundle.
    /// @param totalL1MessagesPoppedOverall The number of messages processed after this bundle.
    /// @param postStateRoot The state root after this bundle.
    /// @param withdrawRoot The withdraw trie root after this bundle.
    /// @param aggrProof The bundle proof for this bundle.
    /// @dev See `BatchHeaderV7Codec` for the batch header encoding.
    function finalizeBundlePostEuclidV2(
        bytes calldata batchHeader,
        uint256 totalL1MessagesPoppedOverall,
        bytes32 postStateRoot,
        bytes32 withdrawRoot,
        bytes calldata aggrProof
    ) external;

    /// @notice The struct for permissionless batch finalization.
    /// @param batchHeader The header of this batch.
    /// @param totalL1MessagesPoppedOverall The number of messages processed after this bundle.
    /// @param postStateRoot The state root after this batch.
    /// @param withdrawRoot The withdraw trie root after this batch.
    /// @param zkProof The bundle proof for this batch (single-batch bundle).
    /// @dev See `BatchHeaderV7Codec` for the batch header encoding.
    struct FinalizeStruct {
        bytes batchHeader;
        uint256 totalL1MessagesPoppedOverall;
        bytes32 postStateRoot;
        bytes32 withdrawRoot;
        bytes zkProof;
    }

    /// @notice Commit and finalize a batch in permissionless mode.
    /// @param version The version of current batch.
    /// @param parentBatchHash The hash of parent batch.
    /// @param finalizeStruct The data needed to finalize this batch.
    /// @dev The batch payload is stored in the blob.
    function commitAndFinalizeBatch(
        uint8 version,
        bytes32 parentBatchHash,
        FinalizeStruct calldata finalizeStruct
    ) external;
}
IL1MessageQueueV1.sol 184 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.24;

/// @custom:deprecated This contract is no longer used in production.
interface IL1MessageQueueV1 {
    /**********
     * Events *
     **********/

    /// @notice Emitted when a new L1 => L2 transaction is appended to the queue.
    /// @param sender The address of account who initiates the transaction.
    /// @param target The address of account who will receive the transaction.
    /// @param value The value passed with the transaction.
    /// @param queueIndex The index of this transaction in the queue.
    /// @param gasLimit Gas limit required to complete the message relay on L2.
    /// @param data The calldata of the transaction.
    event QueueTransaction(
        address indexed sender,
        address indexed target,
        uint256 value,
        uint64 queueIndex,
        uint256 gasLimit,
        bytes data
    );

    /// @notice Emitted when some L1 => L2 transactions are included in L1.
    /// @param startIndex The start index of messages popped.
    /// @param count The number of messages popped.
    /// @param skippedBitmap A bitmap indicates whether a message is skipped.
    event DequeueTransaction(uint256 startIndex, uint256 count, uint256 skippedBitmap);

    /// @notice Emitted when dequeued transactions are reset.
    /// @param startIndex The start index of messages.
    event ResetDequeuedTransaction(uint256 startIndex);

    /// @notice Emitted when some L1 => L2 transactions are finalized in L1.
    /// @param finalizedIndex The last index of messages finalized.
    event FinalizedDequeuedTransaction(uint256 finalizedIndex);

    /// @notice Emitted when a message is dropped from L1.
    /// @param index The index of message dropped.
    event DropTransaction(uint256 index);

    /// @notice Emitted when owner updates gas oracle contract.
    /// @param _oldGasOracle The address of old gas oracle contract.
    /// @param _newGasOracle The address of new gas oracle contract.
    event UpdateGasOracle(address indexed _oldGasOracle, address indexed _newGasOracle);

    /// @notice Emitted when owner updates max gas limit.
    /// @param _oldMaxGasLimit The old max gas limit.
    /// @param _newMaxGasLimit The new max gas limit.
    event UpdateMaxGasLimit(uint256 _oldMaxGasLimit, uint256 _newMaxGasLimit);

    /**********
     * Errors *
     **********/

    /// @dev Thrown when the given address is `address(0)`.
    error ErrorZeroAddress();

    /*************************
     * Public View Functions *
     *************************/

    /// @notice The start index of all pending inclusion messages.
    /// @custom:deprecated Please use `IL1MessageQueueV2.pendingQueueIndex` instead.
    function pendingQueueIndex() external view returns (uint256);

    /// @notice The start index of all unfinalized messages.
    /// @dev All messages from `nextUnfinalizedQueueIndex` to `pendingQueueIndex-1` are committed but not finalized.
    /// @custom:deprecated Please use `IL1MessageQueueV2.nextUnfinalizedQueueIndex` instead.
    function nextUnfinalizedQueueIndex() external view returns (uint256);

    /// @notice Return the index of next appended message.
    /// @dev Also the total number of appended messages.
    /// @custom:deprecated Please use `IL1MessageQueueV2.nextCrossDomainMessageIndex` instead.
    function nextCrossDomainMessageIndex() external view returns (uint256);

    /// @notice Return the message of in `queueIndex`.
    /// @param queueIndex The index to query.
    /// @custom:deprecated Please use `IL1MessageQueueV2.getCrossDomainMessage` instead.
    function getCrossDomainMessage(uint256 queueIndex) external view returns (bytes32);

    /// @notice Return the amount of ETH should pay for cross domain message.
    /// @param gasLimit Gas limit required to complete the message relay on L2.
    /// @custom:deprecated Please use `IL1MessageQueueV2.estimateCrossDomainMessageFee` instead.
    function estimateCrossDomainMessageFee(uint256 gasLimit) external view returns (uint256);

    /// @notice Return the amount of intrinsic gas fee should pay for cross domain message.
    /// @param _calldata The calldata of L1-initiated transaction.
    /// @custom:deprecated Please use `IL1MessageQueueV2.calculateIntrinsicGasFee` instead.
    function calculateIntrinsicGasFee(bytes calldata _calldata) external view returns (uint256);

    /// @notice Return the hash of a L1 message.
    /// @param sender The address of sender.
    /// @param queueIndex The queue index of this message.
    /// @param value The amount of Ether transfer to target.
    /// @param target The address of target.
    /// @param gasLimit The gas limit provided.
    /// @param data The calldata passed to target address.
    /// @custom:deprecated Please use `IL1MessageQueueV2.computeTransactionHash` instead.
    function computeTransactionHash(
        address sender,
        uint256 queueIndex,
        uint256 value,
        address target,
        uint256 gasLimit,
        bytes calldata data
    ) external view returns (bytes32);

    /// @notice Return whether the message is skipped.
    /// @param queueIndex The queue index of the message to check.
    /// @custom:deprecated
    function isMessageSkipped(uint256 queueIndex) external view returns (bool);

    /// @notice Return whether the message is dropped.
    /// @param queueIndex The queue index of the message to check.
    /// @custom:deprecated
    function isMessageDropped(uint256 queueIndex) external view returns (bool);

    /*****************************
     * Public Mutating Functions *
     *****************************/

    /// @notice Append a L1 to L2 message into this contract.
    /// @param target The address of target contract to call in L2.
    /// @param gasLimit The maximum gas should be used for relay this message in L2.
    /// @param data The calldata passed to target contract.
    /// @custom:deprecated Please use `IL1MessageQueueV2.appendCrossDomainMessage` instead.
    function appendCrossDomainMessage(
        address target,
        uint256 gasLimit,
        bytes calldata data
    ) external;

    /// @notice Append an enforced transaction to this contract.
    /// @dev The address of sender should be an EOA.
    /// @param sender The address of sender who will initiate this transaction in L2.
    /// @param target The address of target contract to call in L2.
    /// @param value The value passed
    /// @param gasLimit The maximum gas should be used for this transaction in L2.
    /// @param data The calldata passed to target contract.
    /// @custom:deprecated Please use `IL1MessageQueueV2.appendEnforcedTransaction` instead.
    function appendEnforcedTransaction(
        address sender,
        address target,
        uint256 value,
        uint256 gasLimit,
        bytes calldata data
    ) external;

    /// @notice Pop messages from queue.
    ///
    /// @dev We can pop at most 256 messages each time. And if the message is not skipped,
    ///      the corresponding entry will be cleared.
    ///
    /// @param startIndex The start index to pop.
    /// @param count The number of messages to pop.
    /// @param skippedBitmap A bitmap indicates whether a message is skipped.
    /// @custom:deprecated
    function popCrossDomainMessage(
        uint256 startIndex,
        uint256 count,
        uint256 skippedBitmap
    ) external;

    /// @notice Reset status of popped messages.
    ///
    /// @dev We can only reset unfinalized popped messages.
    ///
    /// @param startIndex The start index to reset.
    /// @custom:deprecated
    function resetPoppedCrossDomainMessage(uint256 startIndex) external;

    /// @notice Finalize status of popped messages.
    /// @param newFinalizedQueueIndexPlusOne The index of message to finalize plus one.
    /// @custom:deprecated
    function finalizePoppedCrossDomainMessage(uint256 newFinalizedQueueIndexPlusOne) external;

    /// @notice Drop a skipped message from the queue.
    /// @custom:deprecated
    function dropCrossDomainMessage(uint256 index) external;
}
IL1MessageQueueV2.sol 116 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.24;

interface IL1MessageQueueV2 {
    /**********
     * Events *
     **********/

    /// @notice Emitted when a new L1 => L2 transaction is appended to the queue.
    /// @param sender The address of the sender account on L2.
    /// @param target The address of the target account on L2.
    /// @param value The ETH value transferred to the target account on L2.
    /// @param queueIndex The index of this transaction in the message queue.
    /// @param gasLimit The gas limit used on L2.
    /// @param data The calldata passed to the target account on L2.
    event QueueTransaction(
        address indexed sender,
        address indexed target,
        uint256 value,
        uint64 queueIndex,
        uint256 gasLimit,
        bytes data
    );

    /// @notice Emitted when some L1 => L2 transactions are finalized on L1.
    /// @param finalizedIndex The index of the last message finalized.
    event FinalizedDequeuedTransaction(uint256 finalizedIndex);

    /*************************
     * Public View Functions *
     *************************/

    /// @notice Return the start index of all messages in this contract.
    function firstCrossDomainMessageIndex() external view returns (uint256);

    /// @notice Return the start index of all unfinalized messages.
    function nextUnfinalizedQueueIndex() external view returns (uint256);

    /// @notice Return the index to be used for the next message.
    /// @dev Also the total number of appended messages, including messages in `L1MessageQueueV1`.
    function nextCrossDomainMessageIndex() external view returns (uint256);

    /// @notice Return the message rolling hash of `queueIndex`.
    /// @param queueIndex The index to query.
    function getMessageRollingHash(uint256 queueIndex) external view returns (bytes32);

    /// @notice Return the message enqueue timestamp of `queueIndex`.
    /// @param queueIndex The index to query.
    function getMessageEnqueueTimestamp(uint256 queueIndex) external view returns (uint256);

    /// @notice Return the first unfinalized message enqueue timestamp.
    function getFirstUnfinalizedMessageEnqueueTime() external view returns (uint256);

    /// @notice Return the amount of ETH that should be paid for a cross-domain message.
    /// @param gasLimit The gas limit required to complete the message relay on L2.
    function estimateCrossDomainMessageFee(uint256 gasLimit) external view returns (uint256);

    /// @notice Return the estimated base fee on L2.
    function estimateL2BaseFee() external view returns (uint256);

    /// @notice Return the intrinsic gas required by the provided cross-domain message.
    /// @param data The calldata of the cross-domain message.
    function calculateIntrinsicGasFee(bytes calldata data) external view returns (uint256);

    /// @notice Compute the transaction hash of an L1 message.
    /// @param sender The address of the sender account.
    /// @param queueIndex The index of this transaction in the message queue.
    /// @param value The ETH value transferred to the target account.
    /// @param target The address of the target account.
    /// @param gasLimit The gas limit provided.
    /// @param data The calldata passed to the target account.
    function computeTransactionHash(
        address sender,
        uint256 queueIndex,
        uint256 value,
        address target,
        uint256 gasLimit,
        bytes calldata data
    ) external view returns (bytes32);

    /*****************************
     * Public Mutating Functions *
     *****************************/

    /// @notice Append a L1 => L2 cross-domain message to the message queue.
    /// @param target The address of the target account on L2.
    /// @param gasLimit The gas limit used on L2.
    /// @param data The calldata passed to the target account on L2.
    /// @dev This function can only be called by `L1ScrollMessenger`.
    function appendCrossDomainMessage(
        address target,
        uint256 gasLimit,
        bytes calldata data
    ) external;

    /// @notice Append an enforced transaction to the message queue.
    /// @param sender The address of the sender account on L2.
    /// @param target The address of the target account on L2.
    /// @param value The ETH value transferred to the target account on L2.
    /// @param gasLimit The gas limit used on L2.
    /// @param data The calldata passed to the target account on L2.
    /// @dev This function can only be called by `EnforcedTxGateway`.
    function appendEnforcedTransaction(
        address sender,
        address target,
        uint256 value,
        uint256 gasLimit,
        bytes calldata data
    ) external;

    /// @notice Mark cross-domain messages as finalized.
    /// @param nextUnfinalizedQueueIndex The index of the first unfinalized message after this call.
    /// @dev This function can only be called by `ScrollChain`.
    function finalizePoppedCrossDomainMessage(uint256 nextUnfinalizedQueueIndex) external;
}
IL1ScrollMessenger.sol 56 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.24;

import {IScrollMessenger} from "../libraries/IScrollMessenger.sol";

interface IL1ScrollMessenger is IScrollMessenger {
    /***********
     * Structs *
     ***********/

    struct L2MessageProof {
        // The index of the batch where the message belongs to.
        uint256 batchIndex;
        // Concatenation of merkle proof for withdraw merkle trie.
        bytes merkleProof;
    }

    /*****************************
     * Public Mutating Functions *
     *****************************/

    /// @notice Relay a L2 => L1 message with message proof.
    /// @param from The address of the sender of the message.
    /// @param to The address of the recipient of the message.
    /// @param value The msg.value passed to the message call.
    /// @param nonce The nonce of the message to avoid replay attack.
    /// @param message The content of the message.
    /// @param proof The proof used to verify the correctness of the transaction.
    function relayMessageWithProof(
        address from,
        address to,
        uint256 value,
        uint256 nonce,
        bytes memory message,
        L2MessageProof memory proof
    ) external;

    /// @notice Replay an existing message.
    /// @param from The address of the sender of the message.
    /// @param to The address of the recipient of the message.
    /// @param value The msg.value passed to the message call.
    /// @param messageNonce The nonce for the message to replay.
    /// @param message The content of the message.
    /// @param newGasLimit New gas limit to be used for this message.
    /// @param refundAddress The address of account who will receive the refunded fee.
    function replayMessage(
        address from,
        address to,
        uint256 value,
        uint256 messageNonce,
        bytes memory message,
        uint32 newGasLimit,
        address refundAddress
    ) external payable;
}
ScrollConstants.sol 12 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.24;

library ScrollConstants {
    /// @notice The address of default cross chain message sender.
    address internal constant DEFAULT_XDOMAIN_MESSAGE_SENDER = address(1);

    /// @notice The address for dropping message.
    /// @dev The first 20 bytes of keccak("drop")
    address internal constant DROP_XDOMAIN_MESSAGE_SENDER = 0x6f297C61B5C92eF107fFD30CD56AFFE5A273e841;
}
IScrollMessenger.sol 77 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.24;

interface IScrollMessenger {
    /**********
     * Events *
     **********/

    /// @notice Emitted when a cross domain message is sent.
    /// @param sender The address of the sender who initiates the message.
    /// @param target The address of target contract to call.
    /// @param value The amount of value passed to the target contract.
    /// @param messageNonce The nonce of the message.
    /// @param gasLimit The optional gas limit passed to L1 or L2.
    /// @param message The calldata passed to the target contract.
    event SentMessage(
        address indexed sender,
        address indexed target,
        uint256 value,
        uint256 messageNonce,
        uint256 gasLimit,
        bytes message
    );

    /// @notice Emitted when a cross domain message is relayed successfully.
    /// @param messageHash The hash of the message.
    event RelayedMessage(bytes32 indexed messageHash);

    /// @notice Emitted when a cross domain message is failed to relay.
    /// @param messageHash The hash of the message.
    event FailedRelayedMessage(bytes32 indexed messageHash);

    /**********
     * Errors *
     **********/

    /// @dev Thrown when the given address is `address(0)`.
    error ErrorZeroAddress();

    /*************************
     * Public View Functions *
     *************************/

    /// @notice Return the sender of a cross domain message.
    function xDomainMessageSender() external view returns (address);

    /*****************************
     * Public Mutating Functions *
     *****************************/

    /// @notice Send cross chain message from L1 to L2 or L2 to L1.
    /// @param target The address of account who receive the message.
    /// @param value The amount of ether passed when call target contract.
    /// @param message The content of the message.
    /// @param gasLimit Gas limit required to complete the message relay on corresponding chain.
    function sendMessage(
        address target,
        uint256 value,
        bytes calldata message,
        uint256 gasLimit
    ) external payable;

    /// @notice Send cross chain message from L1 to L2 or L2 to L1.
    /// @param target The address of account who receive the message.
    /// @param value The amount of ether passed when call target contract.
    /// @param message The content of the message.
    /// @param gasLimit Gas limit required to complete the message relay on corresponding chain.
    /// @param refundAddress The address of account who will receive the refunded fee.
    function sendMessage(
        address target,
        uint256 value,
        bytes calldata message,
        uint256 gasLimit,
        address refundAddress
    ) external payable;
}
ScrollMessengerBase.sol 156 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.24;

import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";

import {ScrollConstants} from "./constants/ScrollConstants.sol";
import {IScrollMessenger} from "./IScrollMessenger.sol";

// solhint-disable var-name-mixedcase

abstract contract ScrollMessengerBase is
    OwnableUpgradeable,
    PausableUpgradeable,
    ReentrancyGuardUpgradeable,
    IScrollMessenger
{
    /**********
     * Events *
     **********/

    /// @notice Emitted when owner updates fee vault contract.
    /// @param _oldFeeVault The address of old fee vault contract.
    /// @param _newFeeVault The address of new fee vault contract.
    event UpdateFeeVault(address _oldFeeVault, address _newFeeVault);

    /*************
     * Constants *
     *************/

    /// @notice The address of counterpart ScrollMessenger contract in L1/L2.
    address public immutable counterpart;

    /*************
     * Variables *
     *************/

    /// @notice See {IScrollMessenger-xDomainMessageSender}
    address public override xDomainMessageSender;

    /// @dev The storage slot used as counterpart ScrollMessenger contract, which is deprecated now.
    address private __counterpart;

    /// @notice The address of fee vault, collecting cross domain messaging fee.
    address public feeVault;

    /// @dev The storage slot used as ETH rate limiter contract, which is deprecated now.
    address private __rateLimiter;

    /// @dev The storage slots for future usage.
    uint256[46] private __gap;

    /**********************
     * Function Modifiers *
     **********************/

    modifier notInExecution() {
        require(
            xDomainMessageSender == ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER,
            "Message is already in execution"
        );
        _;
    }

    /***************
     * Constructor *
     ***************/

    constructor(address _counterpart) {
        if (_counterpart == address(0)) {
            revert ErrorZeroAddress();
        }

        counterpart = _counterpart;
    }

    function __ScrollMessengerBase_init(address, address _feeVault) internal onlyInitializing {
        OwnableUpgradeable.__Ownable_init();
        PausableUpgradeable.__Pausable_init();
        ReentrancyGuardUpgradeable.__ReentrancyGuard_init();

        // initialize to a nonzero value
        xDomainMessageSender = ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER;

        if (_feeVault != address(0)) {
            feeVault = _feeVault;
        }
    }

    // make sure only owner can send ether to messenger to avoid possible user fund loss.
    receive() external payable onlyOwner {}

    /************************
     * Restricted Functions *
     ************************/

    /// @notice Update fee vault contract.
    /// @dev This function can only called by contract owner.
    /// @param _newFeeVault The address of new fee vault contract.
    function updateFeeVault(address _newFeeVault) external onlyOwner {
        address _oldFeeVault = feeVault;

        feeVault = _newFeeVault;
        emit UpdateFeeVault(_oldFeeVault, _newFeeVault);
    }

    /// @notice Pause the contract
    /// @dev This function can only called by contract owner.
    /// @param _status The pause status to update.
    function setPause(bool _status) external onlyOwner {
        if (_status) {
            _pause();
        } else {
            _unpause();
        }
    }

    /**********************
     * Internal Functions *
     **********************/

    /// @dev Internal function to generate the correct cross domain calldata for a message.
    /// @param _sender Message sender address.
    /// @param _target Target contract address.
    /// @param _value The amount of ETH pass to the target.
    /// @param _messageNonce Nonce for the provided message.
    /// @param _message Message to send to the target.
    /// @return ABI encoded cross domain calldata.
    function _encodeXDomainCalldata(
        address _sender,
        address _target,
        uint256 _value,
        uint256 _messageNonce,
        bytes memory _message
    ) internal pure returns (bytes memory) {
        return
            abi.encodeWithSignature(
                "relayMessage(address,address,uint256,uint256,bytes)",
                _sender,
                _target,
                _value,
                _messageNonce,
                _message
            );
    }

    /// @dev Internal function to check whether the `_target` address is allowed to avoid attack.
    /// @param _target The address of target address to check.
    function _validateTargetAddress(address _target) internal view {
        // @note check more `_target` address to avoid attack in the future when we add more external contracts.

        require(_target != address(this), "Forbid to call self");
    }
}
WithdrawTrieVerifier.sol 54 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.24;

// solhint-disable no-inline-assembly

library WithdrawTrieVerifier {
    /// @dev Verify the merkle proof given root, leaf node and proof.
    ///
    /// Vulnerability:
    ///   The initially provided message hash can be hashed with the first hash of the proof,
    ///   thereby giving an intermediate node of the trie. This can then be used with a shortened
    ///   proof to pass the verification, which may lead to replayability.
    ///
    ///   However, it is designed to verify the withdraw trie in `L2MessageQueue`. The `_hash` given
    ///   in the parameter is always a leaf node. So we assume the length of proof is correct and
    ///   cannot be shortened.
    /// @param _root The expected root node hash of the withdraw trie.
    /// @param _hash The leaf node hash of the withdraw trie.
    /// @param _nonce The index of the leaf node from left to right, starting from 0.
    /// @param _proof The concatenated merkle proof verified the leaf node.
    function verifyMerkleProof(
        bytes32 _root,
        bytes32 _hash,
        uint256 _nonce,
        bytes memory _proof
    ) internal pure returns (bool) {
        require(_proof.length % 32 == 0, "Invalid proof");
        uint256 _length = _proof.length / 32;

        for (uint256 i = 0; i < _length; i++) {
            bytes32 item;
            assembly {
                item := mload(add(add(_proof, 0x20), mul(i, 0x20)))
            }
            if (_nonce % 2 == 0) {
                _hash = _efficientHash(_hash, item);
            } else {
                _hash = _efficientHash(item, _hash);
            }
            _nonce /= 2;
        }
        return _hash == _root;
    }

    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        // solhint-disable-next-line no-inline-assembly
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}
OwnableUpgradeable.sol 95 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}
PausableUpgradeable.sol 117 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    function __Pausable_init() internal onlyInitializing {
        __Pausable_init_unchained();
    }

    function __Pausable_init_unchained() internal onlyInitializing {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}
ReentrancyGuardUpgradeable.sol 89 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuardUpgradeable is Initializable {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    function __ReentrancyGuard_init() internal onlyInitializing {
        __ReentrancyGuard_init_unchained();
    }

    function __ReentrancyGuard_init_unchained() internal onlyInitializing {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == _ENTERED;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}
ContextUpgradeable.sol 37 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}
Initializable.sol 166 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: setting the version to 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized != type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}
AddressUpgradeable.sol 244 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

Read Contract

counterpart 0x797594b0 → address
enforcedTxGateway 0x3e83496c → address
feeVault 0x478222c2 → address
isL2MessageExecuted 0x088681a7 → bool
messageQueueV1 0xcd172b23 → address
messageQueueV2 0x9eee46a1 → address
messageSendTimestamp 0xe70fc93b → uint256
owner 0x8da5cb5b → address
paused 0x5c975abb → bool
prevReplayIndex 0xea7ec514 → uint256
replayStates 0x846d4d7a → uint128, uint128
rollup 0xcb23bcb5 → address
xDomainMessageSender 0x6e296e45 → address

Write Contract 9 functions

These functions modify contract state and require a wallet transaction to execute.

initialize 0xf8c8765e
address _counterpart
address _feeVault
address _rollup
address _messageQueue
relayMessageWithProof 0x2ff1921e
address _from
address _to
uint256 _value
uint256 _nonce
bytes _message
tuple _proof
renounceOwnership 0x715018a6
No parameters
replayMessage 0x55004105
address _from
address _to
uint256 _value
uint256 _messageNonce
bytes _message
uint32 _newGasLimit
address _refundAddress
sendMessage 0x5f7b1577
address _to
uint256 _value
bytes _message
uint256 _gasLimit
address _refundAddress
sendMessage 0xb2267a7b
address _to
uint256 _value
bytes _message
uint256 _gasLimit
setPause 0xbedb86fb
bool _status
transferOwnership 0xf2fde38b
address newOwner
updateFeeVault 0x2a6cccb2
address _newFeeVault

Recent Transactions

No transactions found for this address