L2ToL1MessagePasser.sol 4.32 KB
Newer Older
1
// SPDX-License-Identifier: MIT
2
pragma solidity 0.8.15;
3

4 5 6 7 8
import { Types } from "src/libraries/Types.sol";
import { Hashing } from "src/libraries/Hashing.sol";
import { Encoding } from "src/libraries/Encoding.sol";
import { Burn } from "src/libraries/Burn.sol";
import { ISemver } from "src/universal/ISemver.sol";
9

10 11 12 13 14 15
/// @custom:proxied
/// @custom:predeploy 0x4200000000000000000000000000000000000016
/// @title L2ToL1MessagePasser
/// @notice The L2ToL1MessagePasser is a dedicated contract where messages that are being sent from
///         L2 to L1 can be stored. The storage root of this contract is pulled up to the top level
///         of the L2 output to reduce the cost of proving the existence of sent messages.
16
contract L2ToL1MessagePasser is ISemver {
17
    /// @notice The L1 gas limit set when eth is withdrawn using the receive() function.
18 19
    uint256 internal constant RECEIVE_DEFAULT_GAS_LIMIT = 100_000;

20
    /// @notice The current message version identifier.
21 22
    uint16 public constant MESSAGE_VERSION = 1;

23
    /// @notice Includes the message hashes for all withdrawals
24 25
    mapping(bytes32 => bool) public sentMessages;

26
    /// @notice A unique value hashed with each withdrawal.
27
    uint240 internal msgNonce;
28

29 30 31 32 33 34 35 36
    /// @notice Emitted any time a withdrawal is initiated.
    /// @param nonce          Unique value corresponding to each withdrawal.
    /// @param sender         The L2 account address which initiated the withdrawal.
    /// @param target         The L1 account address the call will be send to.
    /// @param value          The ETH value submitted for withdrawal, to be forwarded to the target.
    /// @param gasLimit       The minimum amount of gas that must be provided when withdrawing.
    /// @param data           The data to be forwarded to the target on L1.
    /// @param withdrawalHash The hash of the withdrawal.
37
    event MessagePassed(
38 39 40 41 42
        uint256 indexed nonce,
        address indexed sender,
        address indexed target,
        uint256 value,
        uint256 gasLimit,
43 44
        bytes data,
        bytes32 withdrawalHash
45 46
    );

47 48
    /// @notice Emitted when the balance of this contract is burned.
    /// @param amount Amount of ETh that was burned.
49 50
    event WithdrawerBalanceBurnt(uint256 indexed amount);

51 52
    /// @custom:semver 1.1.0
    string public constant version = "1.1.0";
53

54
    /// @notice Allows users to withdraw ETH by sending directly to this contract.
55
    receive() external payable {
56
        initiateWithdrawal(msg.sender, RECEIVE_DEFAULT_GAS_LIMIT, bytes(""));
57 58
    }

59 60 61 62
    /// @notice Removes all ETH held by this contract from the state. Used to prevent the amount of
    ///         ETH on L2 inflating when ETH is withdrawn. Currently only way to do this is to
    ///         create a contract and self-destruct it to itself. Anyone can call this function. Not
    ///         incentivized since this function is very cheap.
63 64 65 66 67 68
    function burn() external {
        uint256 balance = address(this).balance;
        Burn.eth(balance);
        emit WithdrawerBalanceBurnt(balance);
    }

69 70 71 72
    /// @notice Sends a message from L2 to L1.
    /// @param _target   Address to call on L1 execution.
    /// @param _gasLimit Minimum gas limit for executing the message on L1.
    /// @param _data     Data to forward to L1 target.
73
    function initiateWithdrawal(address _target, uint256 _gasLimit, bytes memory _data) public payable {
74
        bytes32 withdrawalHash = Hashing.hashWithdrawal(
75
            Types.WithdrawalTransaction({
76
                nonce: messageNonce(),
77 78 79 80 81 82
                sender: msg.sender,
                target: _target,
                value: msg.value,
                gasLimit: _gasLimit,
                data: _data
            })
83 84 85 86
        );

        sentMessages[withdrawalHash] = true;

87
        emit MessagePassed(messageNonce(), msg.sender, _target, msg.value, _gasLimit, _data, withdrawalHash);
88

89
        unchecked {
90
            ++msgNonce;
91 92
        }
    }
93

94 95 96 97
    /// @notice Retrieves the next message nonce. Message version will be added to the upper two
    ///         bytes of the message nonce. Message version allows us to treat messages as having
    ///         different structures.
    /// @return Nonce of the next message to be sent, with added message version.
98 99 100
    function messageNonce() public view returns (uint256) {
        return Encoding.encodeVersionedNonce(msgNonce, MESSAGE_VERSION);
    }
101
}