@@ -6,6 +6,7 @@ import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Own
6
6
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol " ;
7
7
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol " ;
8
8
import {DoubleEndedQueueUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/structs/DoubleEndedQueueUpgradeable.sol " ;
9
+ import {Address} from "@openzeppelin/contracts/utils/Address.sol " ;
9
10
import {IArbitrator} from "./interfaces/IArbitrator.sol " ;
10
11
import {IL1Gateway} from "./interfaces/IL1Gateway.sol " ;
11
12
import {IAdmin} from "./zksync/l1-contracts/zksync/interfaces/IAdmin.sol " ;
@@ -27,12 +28,14 @@ contract Arbitrator is IArbitrator, OwnableUpgradeable, UUPSUpgradeable, Reentra
27
28
mapping (IL1Gateway => DoubleEndedQueueUpgradeable.Bytes32Deque) public secondaryChainMessageHashQueues;
28
29
/// @notice List of permitted relayers
29
30
mapping (address relayerAddress = > bool isRelayer ) public relayers;
31
+ /// @dev A transient storage value for forwarding message from source chain to target chains
32
+ bytes32 private finalizeMessageHash;
30
33
/**
31
34
* @dev This empty reserved space is put in place to allow future versions to add new
32
35
* variables without shifting down storage in the inheritance chain.
33
36
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
34
37
*/
35
- uint256 [50 ] private __gap;
38
+ uint256 [49 ] private __gap;
36
39
37
40
/// @notice Primary chain gateway init
38
41
event InitPrimaryChain (IL1Gateway indexed gateway );
@@ -137,29 +140,41 @@ contract Arbitrator is IArbitrator, OwnableUpgradeable, UUPSUpgradeable, Reentra
137
140
emit NewFeeParams (_gateway, _newFeeParams);
138
141
}
139
142
140
- function receiveMessage (uint256 _value , bytes calldata _callData ) external payable {
143
+ function enqueueMessage (uint256 _value , bytes calldata _callData ) external payable {
141
144
require (msg .value == _value, "Invalid msg value " );
142
145
// store message hash for forwarding
143
- bytes32 finalizeMessageHash = keccak256 (abi.encode (_value, _callData));
146
+ bytes32 _finalizeMessageHash = keccak256 (abi.encode (_value, _callData));
144
147
IL1Gateway gateway = IL1Gateway (msg .sender );
145
148
if (gateway == primaryChainGateway) {
146
- primaryChainMessageHashQueue.pushBack (finalizeMessageHash );
149
+ primaryChainMessageHashQueue.pushBack (_finalizeMessageHash );
147
150
} else {
148
151
require (secondaryChainGateways[gateway], "Not secondary chain gateway " );
149
- secondaryChainMessageHashQueues[gateway].pushBack (finalizeMessageHash );
152
+ secondaryChainMessageHashQueues[gateway].pushBack (_finalizeMessageHash );
150
153
}
151
154
emit MessageReceived (_value, _callData);
152
155
}
153
156
157
+ /// @dev This function is called within the `claimMessageCallback` of L1 gateway
158
+ function receiveMessage (uint256 _value , bytes calldata _callData ) external payable {
159
+ require (msg .value == _value, "Invalid msg value " );
160
+ // temporary store message hash for forwarding
161
+ IL1Gateway gateway = IL1Gateway (msg .sender );
162
+ require (gateway == primaryChainGateway || secondaryChainGateways[gateway], "Invalid gateway " );
163
+ bytes32 _finalizeMessageHash = keccak256 (abi.encode (msg .sender , _value, _callData));
164
+ assembly {
165
+ tstore (finalizeMessageHash.slot, _finalizeMessageHash)
166
+ }
167
+ }
168
+
154
169
function forwardMessage (
155
170
IL1Gateway _gateway ,
156
171
uint256 _value ,
157
172
bytes calldata _callData ,
158
173
bytes calldata _adapterParams
159
174
) external payable nonReentrant onlyRelayer {
160
- bytes32 finalizeMessageHash = keccak256 (abi.encode (_value, _callData));
175
+ bytes32 _finalizeMessageHash = keccak256 (abi.encode (_value, _callData));
161
176
if (_gateway == primaryChainGateway) {
162
- require (finalizeMessageHash == primaryChainMessageHashQueue.popFront (), "Invalid finalize message hash " );
177
+ require (_finalizeMessageHash == primaryChainMessageHashQueue.popFront (), "Invalid finalize message hash " );
163
178
// Unpack destination chain and final callData
164
179
(IL1Gateway secondaryChainGateway , bytes memory finalCallData ) = abi.decode (_callData, (IL1Gateway, bytes ));
165
180
require (secondaryChainGateways[secondaryChainGateway], "Invalid secondary chain gateway " );
@@ -168,12 +183,84 @@ contract Arbitrator is IArbitrator, OwnableUpgradeable, UUPSUpgradeable, Reentra
168
183
} else {
169
184
require (secondaryChainGateways[_gateway], "Not secondary chain gateway " );
170
185
require (
171
- finalizeMessageHash == secondaryChainMessageHashQueues[_gateway].popFront (),
186
+ _finalizeMessageHash == secondaryChainMessageHashQueues[_gateway].popFront (),
172
187
"Invalid finalize message hash "
173
188
);
174
189
// Forward fee to send message
175
190
primaryChainGateway.sendMessage {value: msg .value + _value}(_value, _callData, _adapterParams);
176
191
}
177
192
emit MessageForwarded (_gateway, _value, _callData);
178
193
}
194
+
195
+ function claimMessage (
196
+ address _sourceChainCanonicalMessageService ,
197
+ bytes calldata _sourceChainClaimCallData ,
198
+ IL1Gateway _sourceChainL1Gateway ,
199
+ uint256 _receiveValue ,
200
+ bytes calldata _receiveCallData ,
201
+ bytes calldata _forwardParams
202
+ ) external payable nonReentrant onlyRelayer {
203
+ // Call the claim interface of source chain message service
204
+ // And it will inner call the `claimMessageCallback` interface of source chain L1Gateway
205
+ // In the `claimMessageCallback` of L1Gateway, it will inner call `receiveMessage` of Arbitrator
206
+ // No use of return value
207
+ Address.functionCall (_sourceChainCanonicalMessageService, _sourceChainClaimCallData);
208
+
209
+ // Load the transient `finalizeMessageHash`
210
+ bytes32 _finalizeMessageHash;
211
+ assembly {
212
+ _finalizeMessageHash := tload (finalizeMessageHash.slot)
213
+ }
214
+ require (
215
+ _finalizeMessageHash == keccak256 (abi.encode (_sourceChainL1Gateway, _receiveValue, _receiveCallData)),
216
+ "Incorrect finalize data "
217
+ );
218
+
219
+ // The msg value should be equal to the combined cost of all messages delivered from l1 to l2
220
+ // The excess fees will be refunded to the relayer by rollup canonical message service
221
+ if (_sourceChainL1Gateway == primaryChainGateway) {
222
+ // Unpack destination chain and final callData
223
+ bytes [] memory gatewayDataList = abi.decode (_receiveCallData, (bytes []));
224
+ bytes [] memory gatewayForwardParamsList = abi.decode (_forwardParams, (bytes []));
225
+ uint256 gatewayLength = gatewayDataList.length ;
226
+ require (gatewayLength == gatewayForwardParamsList.length , "Invalid forward params length " );
227
+ uint256 totalCallValue;
228
+ uint256 totalSendMsgFee;
229
+ unchecked {
230
+ for (uint256 i = 0 ; i < gatewayLength; ++ i) {
231
+ bytes memory gatewayData = gatewayDataList[i];
232
+ bytes memory gatewayForwardParams = gatewayForwardParamsList[i];
233
+ (IL1Gateway targetGateway , uint256 targetCallValue , bytes memory targetCallData ) = abi.decode (
234
+ gatewayData,
235
+ (IL1Gateway, uint256 , bytes )
236
+ );
237
+ require (secondaryChainGateways[targetGateway], "Invalid secondary chain gateway " );
238
+ totalCallValue += targetCallValue;
239
+ (uint256 sendMsgFee , bytes memory adapterParams ) = abi.decode (
240
+ gatewayForwardParams,
241
+ (uint256 , bytes )
242
+ );
243
+ totalSendMsgFee += sendMsgFee;
244
+ // Forward fee to send message
245
+ targetGateway.sendMessage {value: sendMsgFee + targetCallValue}(
246
+ targetCallValue,
247
+ targetCallData,
248
+ adapterParams
249
+ );
250
+ emit MessageForwarded (targetGateway, targetCallValue, targetCallData);
251
+ }
252
+ }
253
+ require (totalCallValue == _receiveValue, "Invalid call value " );
254
+ require (totalSendMsgFee == msg .value , "Invalid send msg fee " );
255
+ } else {
256
+ IL1Gateway targetGateway = primaryChainGateway;
257
+ // Forward fee to send message
258
+ targetGateway.sendMessage {value: msg .value + _receiveValue}(
259
+ _receiveValue,
260
+ _receiveCallData,
261
+ _forwardParams
262
+ );
263
+ emit MessageForwarded (targetGateway, _receiveValue, _receiveCallData);
264
+ }
265
+ }
179
266
}
0 commit comments