This repository has been archived by the owner on Mar 25, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 106
/
L2EthToken.sol
147 lines (124 loc) · 6.45 KB
/
L2EthToken.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IEthToken} from "./interfaces/IEthToken.sol";
import {MSG_VALUE_SYSTEM_CONTRACT, DEPLOYER_SYSTEM_CONTRACT, BOOTLOADER_FORMAL_ADDRESS, L1_MESSENGER_CONTRACT} from "./Constants.sol";
import {SystemContractHelper} from "./libraries/SystemContractHelper.sol";
import {IMailbox} from "./interfaces/IMailbox.sol";
/**
* @author Matter Labs
* @notice Native ETH contract.
* @dev It does NOT provide interfaces for personal interaction with tokens like `transfer`, `approve`, and `transferFrom`.
* Instead, this contract is used by the bootloader and `MsgValueSimulator`/`ContractDeployer` system contracts
* to perform the balance changes while simulating the `msg.value` Ethereum behavior.
*/
contract L2EthToken is IEthToken {
/// @notice The balances of the users.
mapping(address => uint256) balance;
/// @notice The total amount of tokens that have been minted.
uint256 public override totalSupply;
modifier onlyBootloader() {
require(msg.sender == BOOTLOADER_FORMAL_ADDRESS, "Callable only by the bootloader");
_;
}
/// @notice Transfer tokens from one address to another.
/// @param _from The address to transfer the ETH from.
/// @param _to The address to transfer the ETH to.
/// @param _amount The amount of ETH in wei being transferred.
/// @dev This function can be called only by trusted system contracts.
/// @dev This function also emits "Transfer" event, which might be removed
/// later on.
function transferFromTo(address _from, address _to, uint256 _amount) external override {
require(
msg.sender == MSG_VALUE_SYSTEM_CONTRACT ||
msg.sender == address(DEPLOYER_SYSTEM_CONTRACT) ||
msg.sender == BOOTLOADER_FORMAL_ADDRESS,
"Only system contracts with special access can call this method"
);
uint256 fromBalance = balance[_from];
require(fromBalance >= _amount, "Transfer amount exceeds balance");
unchecked {
balance[_from] = fromBalance - _amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
balance[_to] += _amount;
}
emit Transfer(_from, _to, _amount);
}
/// @notice Returns ETH balance of an account
/// @dev It takes `uint256` as an argument to be able to properly simulate the behaviour of the
/// Ethereum's `BALANCE` opcode that accepts uint256 as an argument and truncates any upper bits
/// @param _account The address of the account to return the balance of.
function balanceOf(uint256 _account) external view override returns (uint256) {
return balance[address(uint160(_account))];
}
/// @notice Increase the total supply of tokens and balance of the receiver.
/// @dev This method is only callable by the bootloader.
/// @param _account The address which to mint the funds to.
/// @param _amount The amount of ETH in wei to be minted.
function mint(address _account, uint256 _amount) external override onlyBootloader {
totalSupply += _amount;
balance[_account] += _amount;
emit Mint(_account, _amount);
}
/// @notice Initiate the ETH withdrawal, funds will be available to claim on L1 `finalizeEthWithdrawal` method.
/// @param _l1Receiver The address on L1 to receive the funds.
function withdraw(address _l1Receiver) external payable override {
uint256 amount = _burnMsgValue();
// Send the L2 log, a user could use it as proof of the withdrawal
bytes memory message = _getL1WithdrawMessage(_l1Receiver, amount);
L1_MESSENGER_CONTRACT.sendToL1(message);
emit Withdrawal(msg.sender, _l1Receiver, amount);
}
/// @notice Initiate the ETH withdrawal, with the sent message. The funds will be available to claim on L1 `finalizeEthWithdrawal` method.
/// @param _l1Receiver The address on L1 to receive the funds.
/// @param _additionalData Additional data to be sent to L1 with the withdrawal.
function withdrawWithMessage(address _l1Receiver, bytes memory _additionalData) external payable override {
uint256 amount = _burnMsgValue();
// Send the L2 log, a user could use it as proof of the withdrawal
bytes memory message = _getExtendedWithdrawMessage(_l1Receiver, amount, msg.sender, _additionalData);
L1_MESSENGER_CONTRACT.sendToL1(message);
emit WithdrawalWithMessage(msg.sender, _l1Receiver, amount, _additionalData);
}
/// @dev The function burn the sent `msg.value`.
/// NOTE: Since this contract holds the mapping of all ether balances of the system,
/// the sent `msg.value` is added to the `this` balance before the call.
/// So the balance of `address(this)` is always bigger or equal to the `msg.value`!
function _burnMsgValue() internal returns (uint256 amount) {
amount = msg.value;
// Silent burning of the ether
unchecked {
// This is safe, since this contract holds the ether balances, and if user
// send a `msg.value` it will be added to the contract (`this`) balance.
balance[address(this)] -= amount;
totalSupply -= amount;
}
}
/// @dev Get the message to be sent to L1 to initiate a withdrawal.
function _getL1WithdrawMessage(address _to, uint256 _amount) internal pure returns (bytes memory) {
return abi.encodePacked(IMailbox.finalizeEthWithdrawal.selector, _to, _amount);
}
/// @dev Get the message to be sent to L1 to initiate a withdrawal.
function _getExtendedWithdrawMessage(
address _to,
uint256 _amount,
address _sender,
bytes memory _additionalData
) internal pure returns (bytes memory) {
return abi.encodePacked(IMailbox.finalizeEthWithdrawal.selector, _to, _amount, _sender, _additionalData);
}
/// @dev This method has not been stabilized and might be
/// removed later on.
function name() external pure override returns (string memory) {
return "Ether";
}
/// @dev This method has not been stabilized and might be
/// removed later on.
function symbol() external pure override returns (string memory) {
return "ETH";
}
/// @dev This method has not been stabilized and might be
/// removed later on.
function decimals() external pure override returns (uint8) {
return 18;
}
}