forked from scroll-tech/scroll
-
Notifications
You must be signed in to change notification settings - Fork 0
/
L1GatewayRouter.sol
253 lines (206 loc) · 8.32 KB
/
L1GatewayRouter.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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
// SPDX-License-Identifier: MIT
pragma solidity =0.8.24;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {IL1ETHGateway} from "./IL1ETHGateway.sol";
import {IL1ERC20Gateway} from "./IL1ERC20Gateway.sol";
import {IL1GatewayRouter} from "./IL1GatewayRouter.sol";
/// @title L1GatewayRouter
/// @notice The `L1GatewayRouter` is the main entry for depositing Ether and ERC20 tokens.
/// All deposited tokens are routed to corresponding gateways.
/// @dev One can also use this contract to query L1/L2 token address mapping.
/// In the future, ERC-721 and ERC-1155 tokens will be added to the router too.
contract L1GatewayRouter is OwnableUpgradeable, IL1GatewayRouter {
using SafeERC20Upgradeable for IERC20Upgradeable;
/*************
* Variables *
*************/
/// @notice The address of L1ETHGateway.
address public ethGateway;
/// @notice The address of default ERC20 gateway, normally the L1StandardERC20Gateway contract.
address public defaultERC20Gateway;
/// @notice Mapping from ERC20 token address to corresponding L1ERC20Gateway.
// solhint-disable-next-line var-name-mixedcase
mapping(address => address) public ERC20Gateway;
/// @notice The address of gateway in current execution context.
address public gatewayInContext;
/**********************
* Function Modifiers *
**********************/
modifier onlyNotInContext() {
require(gatewayInContext == address(0), "Only not in context");
_;
}
modifier onlyInContext() {
require(_msgSender() == gatewayInContext, "Only in deposit context");
_;
}
/***************
* Constructor *
***************/
constructor() {
_disableInitializers();
}
/// @notice Initialize the storage of L1GatewayRouter.
/// @param _ethGateway The address of L1ETHGateway contract.
/// @param _defaultERC20Gateway The address of default ERC20 Gateway contract.
function initialize(address _ethGateway, address _defaultERC20Gateway) external initializer {
OwnableUpgradeable.__Ownable_init();
// it can be zero during initialization
if (_defaultERC20Gateway != address(0)) {
defaultERC20Gateway = _defaultERC20Gateway;
emit SetDefaultERC20Gateway(address(0), _defaultERC20Gateway);
}
// it can be zero during initialization
if (_ethGateway != address(0)) {
ethGateway = _ethGateway;
emit SetETHGateway(address(0), _ethGateway);
}
}
/*************************
* Public View Functions *
*************************/
/// @inheritdoc IL1ERC20Gateway
function getL2ERC20Address(address _l1Address) external view override returns (address) {
address _gateway = getERC20Gateway(_l1Address);
if (_gateway == address(0)) {
return address(0);
}
return IL1ERC20Gateway(_gateway).getL2ERC20Address(_l1Address);
}
/// @inheritdoc IL1GatewayRouter
function getERC20Gateway(address _token) public view returns (address) {
address _gateway = ERC20Gateway[_token];
if (_gateway == address(0)) {
_gateway = defaultERC20Gateway;
}
return _gateway;
}
/*****************************
* Public Mutating Functions *
*****************************/
/// @inheritdoc IL1GatewayRouter
/// @dev All the gateways should have reentrancy guard to prevent potential attack though this function.
function requestERC20(
address _sender,
address _token,
uint256 _amount
) external onlyInContext returns (uint256) {
address _caller = _msgSender();
uint256 _balance = IERC20Upgradeable(_token).balanceOf(_caller);
IERC20Upgradeable(_token).safeTransferFrom(_sender, _caller, _amount);
_amount = IERC20Upgradeable(_token).balanceOf(_caller) - _balance;
return _amount;
}
/*************************************************
* Public Mutating Functions from L1ERC20Gateway *
*************************************************/
/// @inheritdoc IL1ERC20Gateway
function depositERC20(
address _token,
uint256 _amount,
uint256 _gasLimit
) external payable override {
depositERC20AndCall(_token, _msgSender(), _amount, new bytes(0), _gasLimit);
}
/// @inheritdoc IL1ERC20Gateway
function depositERC20(
address _token,
address _to,
uint256 _amount,
uint256 _gasLimit
) external payable override {
depositERC20AndCall(_token, _to, _amount, new bytes(0), _gasLimit);
}
/// @inheritdoc IL1ERC20Gateway
function depositERC20AndCall(
address _token,
address _to,
uint256 _amount,
bytes memory _data,
uint256 _gasLimit
) public payable override onlyNotInContext {
address _gateway = getERC20Gateway(_token);
require(_gateway != address(0), "no gateway available");
// enter deposit context
gatewayInContext = _gateway;
// encode msg.sender with _data
bytes memory _routerData = abi.encode(_msgSender(), _data);
IL1ERC20Gateway(_gateway).depositERC20AndCall{value: msg.value}(_token, _to, _amount, _routerData, _gasLimit);
// leave deposit context
gatewayInContext = address(0);
}
/// @inheritdoc IL1ERC20Gateway
function finalizeWithdrawERC20(
address,
address,
address,
address,
uint256,
bytes calldata
) external payable virtual override {
revert("should never be called");
}
/***********************************************
* Public Mutating Functions from L1ETHGateway *
***********************************************/
/// @inheritdoc IL1ETHGateway
function depositETH(uint256 _amount, uint256 _gasLimit) external payable override {
depositETHAndCall(_msgSender(), _amount, new bytes(0), _gasLimit);
}
/// @inheritdoc IL1ETHGateway
function depositETH(
address _to,
uint256 _amount,
uint256 _gasLimit
) external payable override {
depositETHAndCall(_to, _amount, new bytes(0), _gasLimit);
}
/// @inheritdoc IL1ETHGateway
function depositETHAndCall(
address _to,
uint256 _amount,
bytes memory _data,
uint256 _gasLimit
) public payable override onlyNotInContext {
address _gateway = ethGateway;
require(_gateway != address(0), "eth gateway available");
// encode msg.sender with _data
bytes memory _routerData = abi.encode(_msgSender(), _data);
IL1ETHGateway(_gateway).depositETHAndCall{value: msg.value}(_to, _amount, _routerData, _gasLimit);
}
/// @inheritdoc IL1ETHGateway
function finalizeWithdrawETH(
address,
address,
uint256,
bytes calldata
) external payable virtual override {
revert("should never be called");
}
/************************
* Restricted Functions *
************************/
/// @inheritdoc IL1GatewayRouter
function setETHGateway(address _newEthGateway) external onlyOwner {
address _oldETHGateway = ethGateway;
ethGateway = _newEthGateway;
emit SetETHGateway(_oldETHGateway, _newEthGateway);
}
/// @inheritdoc IL1GatewayRouter
function setDefaultERC20Gateway(address _newDefaultERC20Gateway) external onlyOwner {
address _oldDefaultERC20Gateway = defaultERC20Gateway;
defaultERC20Gateway = _newDefaultERC20Gateway;
emit SetDefaultERC20Gateway(_oldDefaultERC20Gateway, _newDefaultERC20Gateway);
}
/// @inheritdoc IL1GatewayRouter
function setERC20Gateway(address[] memory _tokens, address[] memory _gateways) external onlyOwner {
require(_tokens.length == _gateways.length, "length mismatch");
for (uint256 i = 0; i < _tokens.length; i++) {
address _oldGateway = ERC20Gateway[_tokens[i]];
ERC20Gateway[_tokens[i]] = _gateways[i];
emit SetERC20Gateway(_tokens[i], _oldGateway, _gateways[i]);
}
}
}