/
L1ArbitrumMessenger.sol
204 lines (190 loc) · 6.38 KB
/
L1ArbitrumMessenger.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
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2020, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity ^0.8.0;
import "@arbitrum/nitro-contracts/src/bridge/IInbox.sol";
import "@arbitrum/nitro-contracts/src/bridge/IOutbox.sol";
/// @notice L1 utility contract to assist with L1 <=> L2 interactions
/// @dev this is an abstract contract instead of library so the functions can be easily overriden when testing
abstract contract L1ArbitrumMessenger {
event TxToL2(address indexed _from, address indexed _to, uint256 indexed _seqNum, bytes _data);
struct L2GasParams {
uint256 _maxSubmissionCost;
uint256 _maxGas;
uint256 _gasPriceBid;
}
function sendTxToL2CustomRefund(
address _inbox,
address _to,
address _refundTo,
address _user,
uint256 _l1CallValue,
uint256 _l2CallValue,
L2GasParams memory _l2GasParams,
bytes memory _data
) internal returns (uint256) {
// alternative function entry point when struggling with the stack size
return
sendTxToL2CustomRefund(
_inbox,
_to,
_refundTo,
_user,
_l1CallValue,
_l2CallValue,
_l2GasParams._maxSubmissionCost,
_l2GasParams._maxGas,
_l2GasParams._gasPriceBid,
_data
);
}
function sendTxToL2(
address _inbox,
address _to,
address _user,
uint256 _l1CallValue,
uint256 _l2CallValue,
L2GasParams memory _l2GasParams,
bytes memory _data
) internal returns (uint256) {
// alternative function entry point when struggling with the stack size
return
sendTxToL2(
_inbox,
_to,
_user,
_l1CallValue,
_l2CallValue,
_l2GasParams._maxSubmissionCost,
_l2GasParams._maxGas,
_l2GasParams._gasPriceBid,
_data
);
}
function sendTxToL2CustomRefund(
address _inbox,
address _to,
address _refundTo,
address _user,
uint256 _l1CallValue,
uint256 _l2CallValue,
uint256 _maxSubmissionCost,
uint256 _maxGas,
uint256 _gasPriceBid,
bytes memory _data
) internal returns (uint256) {
uint256 seqNum = _createRetryable(
_inbox,
_to,
_refundTo,
_user,
_l1CallValue,
_l2CallValue,
_maxSubmissionCost,
_maxGas,
_gasPriceBid,
_data
);
emit TxToL2(_user, _to, seqNum, _data);
return seqNum;
}
function sendTxToL2(
address _inbox,
address _to,
address _user,
uint256 _l1CallValue,
uint256 _l2CallValue,
uint256 _maxSubmissionCost,
uint256 _maxGas,
uint256 _gasPriceBid,
bytes memory _data
) internal returns (uint256) {
return
sendTxToL2CustomRefund(
_inbox,
_to,
_user,
_user,
_l1CallValue,
_l2CallValue,
_maxSubmissionCost,
_maxGas,
_gasPriceBid,
_data
);
}
function getBridge(address _inbox) internal view returns (IBridge) {
return IInbox(_inbox).bridge();
}
/// @dev the l2ToL1Sender behaves as the tx.origin, the msg.sender should be validated to protect against reentrancies
function getL2ToL1Sender(address _inbox) internal view returns (address) {
IOutbox outbox = IOutbox(getBridge(_inbox).activeOutbox());
address l2ToL1Sender = outbox.l2ToL1Sender();
require(l2ToL1Sender != address(0), "NO_SENDER");
return l2ToL1Sender;
}
/**
* @notice Calls inbox to create retryable ticket. Default implementation is for standard Eth-based rollup, but it can be overriden to create retryable in ERC20-based rollup.
* @param _inbox address of the rollup's inbox
* @param _to destination L2 contract address
* @param _refundTo refund address for excess fee
* @param _user refund address for callvalue
* @param _totalFeeAmount amount of fees to pay, in Eth or native token, for retryable's execution
* @param _l2CallValue call value for retryable L2 message
* @param _maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee
* @param _maxGas Max gas deducted from user's L2 balance to cover L2 execution
* @param _gasPriceBid price bid for L2 execution
* @param _data ABI encoded data of L2 message
* @return unique message number of the retryable transaction
*/
function _createRetryable(
address _inbox,
address _to,
address _refundTo,
address _user,
uint256 _totalFeeAmount,
uint256 _l2CallValue,
uint256 _maxSubmissionCost,
uint256 _maxGas,
uint256 _gasPriceBid,
bytes memory _data
) internal virtual returns (uint256) {
return
IInbox(_inbox).createRetryableTicket{ value: _totalFeeAmount }(
_to,
_l2CallValue,
_maxSubmissionCost,
_refundTo,
_user,
_maxGas,
_gasPriceBid,
_data
);
}
}
interface IERC20Inbox {
function createRetryableTicket(
address to,
uint256 l2CallValue,
uint256 maxSubmissionCost,
address excessFeeRefundAddress,
address callValueRefundAddress,
uint256 gasLimit,
uint256 maxFeePerGas,
uint256 tokenTotalFeeAmount,
bytes calldata data
) external returns (uint256);
}