-
Notifications
You must be signed in to change notification settings - Fork 479
Expand file tree
/
Copy pathMessageLibManager.sol
More file actions
324 lines (279 loc) · 14.5 KB
/
MessageLibManager.sol
File metadata and controls
324 lines (279 loc) · 14.5 KB
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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
// SPDX-License-Identifier: LZBL-1.2
pragma solidity ^0.8.20;
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IMessageLib, MessageLibType } from "./interfaces/IMessageLib.sol";
import { IMessageLibManager, SetConfigParam } from "./interfaces/IMessageLibManager.sol";
import { Errors } from "./libs/Errors.sol";
import { BlockedMessageLib } from "./messagelib/BlockedMessageLib.sol";
abstract contract MessageLibManager is Ownable, IMessageLibManager {
address private constant DEFAULT_LIB = address(0);
// the library that reverts both on send and quote
// must be configured on construction and be immutable
address public immutable blockedLibrary;
// only registered libraries all valid libraries
// the blockedLibrary will be registered on construction
address[] internal registeredLibraries;
mapping(address lib => bool) public isRegisteredLibrary;
// both sendLibrary and receiveLibrary config can be lazily resolved
mapping(address sender => mapping(uint32 dstEid => address lib)) internal sendLibrary;
mapping(address receiver => mapping(uint32 srcEid => address lib)) internal receiveLibrary;
mapping(address receiver => mapping(uint32 srcEid => Timeout)) public receiveLibraryTimeout;
mapping(uint32 dstEid => address lib) public defaultSendLibrary;
mapping(uint32 srcEid => address lib) public defaultReceiveLibrary;
mapping(uint32 srcEid => Timeout) public defaultReceiveLibraryTimeout;
constructor() {
blockedLibrary = address(new BlockedMessageLib());
registerLibrary(blockedLibrary);
}
modifier onlyRegistered(address _lib) {
if (!isRegisteredLibrary[_lib]) revert Errors.LZ_OnlyRegisteredLib();
_;
}
modifier isSendLib(address _lib) {
if (_lib != DEFAULT_LIB) {
if (IMessageLib(_lib).messageLibType() == MessageLibType.Receive) revert Errors.LZ_OnlySendLib();
}
_;
}
modifier isReceiveLib(address _lib) {
if (_lib != DEFAULT_LIB) {
if (IMessageLib(_lib).messageLibType() == MessageLibType.Send) revert Errors.LZ_OnlyReceiveLib();
}
_;
}
modifier onlyRegisteredOrDefault(address _lib) {
if (!isRegisteredLibrary[_lib] && _lib != DEFAULT_LIB) revert Errors.LZ_OnlyRegisteredOrDefaultLib();
_;
}
/// @dev check if the library supported the eid.
modifier onlySupportedEid(address _lib, uint32 _eid) {
/// @dev doesnt need to check for default lib, because when they are initially added they get passed through this modifier
if (_lib != DEFAULT_LIB) {
if (!IMessageLib(_lib).isSupportedEid(_eid)) revert Errors.LZ_UnsupportedEid();
}
_;
}
function getRegisteredLibraries() external view returns (address[] memory) {
return registeredLibraries;
}
/// @notice The Send Library is the Oapp specified library that will be used to send the message to the destination
/// endpoint. If the Oapp does not specify a Send Library, the default Send Library will be used.
/// @dev If the Oapp does not have a selected Send Library, this function will resolve to the default library
/// configured by LayerZero
/// @return lib address of the Send Library
/// @param _sender The address of the Oapp that is sending the message
/// @param _dstEid The destination endpoint id
function getSendLibrary(address _sender, uint32 _dstEid) public view returns (address lib) {
lib = sendLibrary[_sender][_dstEid];
if (lib == DEFAULT_LIB) {
lib = defaultSendLibrary[_dstEid];
if (lib == address(0x0)) revert Errors.LZ_DefaultSendLibUnavailable();
}
}
function isDefaultSendLibrary(address _sender, uint32 _dstEid) public view returns (bool) {
return sendLibrary[_sender][_dstEid] == DEFAULT_LIB;
}
/// @dev the receiveLibrary can be lazily resolved that if not set it will point to the default configured by LayerZero
function getReceiveLibrary(address _receiver, uint32 _srcEid) public view returns (address lib, bool isDefault) {
lib = receiveLibrary[_receiver][_srcEid];
if (lib == DEFAULT_LIB) {
lib = defaultReceiveLibrary[_srcEid];
if (lib == address(0x0)) revert Errors.LZ_DefaultReceiveLibUnavailable();
isDefault = true;
}
}
/// @dev called when the endpoint checks if the msgLib attempting to verify the msg is the configured msgLib of the Oapp
/// @dev this check provides the ability for Oapp to lock in a trusted msgLib
/// @dev it will fist check if the msgLib is the currently configured one. then check if the msgLib is the one in grace period of msgLib versioning upgrade
function isValidReceiveLibrary(
address _receiver,
uint32 _srcEid,
address _actualReceiveLib
) public view returns (bool) {
// early return true if the _actualReceiveLib is the currently configured one
(address expectedReceiveLib, bool isDefault) = getReceiveLibrary(_receiver, _srcEid);
if (_actualReceiveLib == expectedReceiveLib) {
return true;
}
// check the timeout condition otherwise
// if the Oapp is using defaultReceiveLibrary, use the default Timeout config
// otherwise, use the Timeout configured by the Oapp
Timeout memory timeout = isDefault
? defaultReceiveLibraryTimeout[_srcEid]
: receiveLibraryTimeout[_receiver][_srcEid];
// requires the _actualReceiveLib to be the same as the one in grace period and the grace period has not expired
// block.number is uint256 so timeout.expiry must > 0, which implies a non-ZERO value
if (timeout.lib == _actualReceiveLib && timeout.expiry > block.number) {
// timeout lib set and has not expired
return true;
}
// returns false by default
return false;
}
//------- Owner interfaces
/// @dev all libraries have to implement the erc165 interface to prevent wrong configurations
/// @dev only owner
function registerLibrary(address _lib) public onlyOwner {
// must have the right interface
if (!IERC165(_lib).supportsInterface(type(IMessageLib).interfaceId)) revert Errors.LZ_UnsupportedInterface();
// must have not been registered
if (isRegisteredLibrary[_lib]) revert Errors.LZ_AlreadyRegistered();
// insert into both the map and the list
isRegisteredLibrary[_lib] = true;
registeredLibraries.push(_lib);
emit LibraryRegistered(_lib);
}
/// @dev owner setting the defaultSendLibrary
/// @dev can set to the blockedLibrary, which is a registered library
/// @dev the msgLib must enable the support before they can be registered to the endpoint as the default
/// @dev only owner
function setDefaultSendLibrary(
uint32 _eid,
address _newLib
) external onlyOwner onlyRegistered(_newLib) isSendLib(_newLib) onlySupportedEid(_newLib, _eid) {
// must provide a different value
if (defaultSendLibrary[_eid] == _newLib) revert Errors.LZ_SameValue();
defaultSendLibrary[_eid] = _newLib;
emit DefaultSendLibrarySet(_eid, _newLib);
}
/// @dev owner setting the defaultSendLibrary
/// @dev must be a registered library (including blockLibrary) with the eid support enabled
/// @dev in version migration, it can add a grace period to the old library. if the grace period is 0, it will delete the timeout configuration.
/// @dev only owner
function setDefaultReceiveLibrary(
uint32 _eid,
address _newLib,
uint256 _gracePeriod
) external onlyOwner onlyRegistered(_newLib) isReceiveLib(_newLib) onlySupportedEid(_newLib, _eid) {
address oldLib = defaultReceiveLibrary[_eid];
// must provide a different value
if (oldLib == _newLib) revert Errors.LZ_SameValue();
defaultReceiveLibrary[_eid] = _newLib;
emit DefaultReceiveLibrarySet(_eid, _newLib);
if (_gracePeriod > 0) {
// override the current default timeout to the [old_lib + new expiry]
Timeout storage timeout = defaultReceiveLibraryTimeout[_eid];
timeout.lib = oldLib;
timeout.expiry = block.number + _gracePeriod;
emit DefaultReceiveLibraryTimeoutSet(_eid, oldLib, timeout.expiry);
} else {
// otherwise, remove the old configuration.
delete defaultReceiveLibraryTimeout[_eid];
emit DefaultReceiveLibraryTimeoutSet(_eid, oldLib, 0);
}
}
/// @dev owner setting the defaultSendLibrary
/// @dev must be a registered library (including blockLibrary) with the eid support enabled
/// @dev can used to (1) extend the current configuration (2) force remove the current configuration (3) change to a new configuration
/// @param _expiry the block number when lib expires
function setDefaultReceiveLibraryTimeout(
uint32 _eid,
address _lib,
uint256 _expiry
) external onlyRegistered(_lib) isReceiveLib(_lib) onlySupportedEid(_lib, _eid) onlyOwner {
if (_expiry == 0) {
// force remove the current configuration
delete defaultReceiveLibraryTimeout[_eid];
} else {
// override it with new configuration
if (_expiry <= block.number) revert Errors.LZ_InvalidExpiry();
Timeout storage timeout = defaultReceiveLibraryTimeout[_eid];
timeout.lib = _lib;
timeout.expiry = _expiry;
}
emit DefaultReceiveLibraryTimeoutSet(_eid, _lib, _expiry);
}
/// @dev returns true only if both the default send/receive libraries are set
function isSupportedEid(uint32 _eid) external view returns (bool) {
return defaultSendLibrary[_eid] != address(0) && defaultReceiveLibrary[_eid] != address(0);
}
//------- OApp interfaces
/// @dev Oapp setting the sendLibrary
/// @dev must be a registered library (including blockLibrary) with the eid support enabled
/// @dev authenticated by the Oapp
function setSendLibrary(
address _oapp,
uint32 _eid,
address _newLib
) external onlyRegisteredOrDefault(_newLib) isSendLib(_newLib) onlySupportedEid(_newLib, _eid) {
_assertAuthorized(_oapp);
// must provide a different value
if (sendLibrary[_oapp][_eid] == _newLib) revert Errors.LZ_SameValue();
sendLibrary[_oapp][_eid] = _newLib;
emit SendLibrarySet(_oapp, _eid, _newLib);
}
/// @dev Oapp setting the receiveLibrary
/// @dev must be a registered library (including blockLibrary) with the eid support enabled
/// @dev in version migration, it can add a grace period to the old library. if the grace period is 0, it will delete the timeout configuration.
/// @dev authenticated by the Oapp
/// @param _gracePeriod the number of blocks from now until oldLib expires
function setReceiveLibrary(
address _oapp,
uint32 _eid,
address _newLib,
uint256 _gracePeriod
) external onlyRegisteredOrDefault(_newLib) isReceiveLib(_newLib) onlySupportedEid(_newLib, _eid) {
_assertAuthorized(_oapp);
address oldLib = receiveLibrary[_oapp][_eid];
// must provide new values
if (oldLib == _newLib) revert Errors.LZ_SameValue();
receiveLibrary[_oapp][_eid] = _newLib;
emit ReceiveLibrarySet(_oapp, _eid, _newLib);
if (_gracePeriod > 0) {
// to simplify the logic, we only allow to set timeout if neither the new lib nor old lib is DEFAULT_LIB, which would should read the default timeout configurations
// (1) if the Oapp wants to fall back to the DEFAULT, then set the newLib to DEFAULT with grace period == 0
// (2) if the Oapp wants to change to a non DEFAULT from DEFAULT, then set the newLib to 'non-default' with _gracePeriod == 0, then use setReceiveLibraryTimeout() interface
if (oldLib == DEFAULT_LIB || _newLib == DEFAULT_LIB) revert Errors.LZ_OnlyNonDefaultLib();
// write to storage
Timeout memory timeout = Timeout({ lib: oldLib, expiry: block.number + _gracePeriod });
receiveLibraryTimeout[_oapp][_eid] = timeout;
emit ReceiveLibraryTimeoutSet(_oapp, _eid, oldLib, timeout.expiry);
} else {
delete receiveLibraryTimeout[_oapp][_eid];
emit ReceiveLibraryTimeoutSet(_oapp, _eid, oldLib, 0);
}
}
/// @dev Oapp setting the defaultSendLibrary
/// @dev must be a registered library (including blockLibrary) with the eid support enabled
/// @dev can used to (1) extend the current configuration (2) force remove the current configuration (3) change to a new configuration
/// @param _expiry the block number when lib expires
function setReceiveLibraryTimeout(
address _oapp,
uint32 _eid,
address _lib,
uint256 _expiry
) external onlyRegistered(_lib) isReceiveLib(_lib) onlySupportedEid(_lib, _eid) {
_assertAuthorized(_oapp);
(, bool isDefault) = getReceiveLibrary(_oapp, _eid);
// if current library is DEFAULT, Oapp cant set the timeout
if (isDefault) revert Errors.LZ_OnlyNonDefaultLib();
if (_expiry == 0) {
// force remove the current configuration
delete receiveLibraryTimeout[_oapp][_eid];
} else {
// override it with new configuration
if (_expiry <= block.number) revert Errors.LZ_InvalidExpiry();
Timeout storage timeout = receiveLibraryTimeout[_oapp][_eid];
timeout.lib = _lib;
timeout.expiry = _expiry;
}
emit ReceiveLibraryTimeoutSet(_oapp, _eid, _lib, _expiry);
}
//------- library config setter/getter. all pass-through functions to the msgLib
/// @dev authenticated by the _oapp
function setConfig(address _oapp, address _lib, SetConfigParam[] calldata _params) external onlyRegistered(_lib) {
_assertAuthorized(_oapp);
IMessageLib(_lib).setConfig(_oapp, _params);
}
/// @dev a view function to query the current configuration of the OApp
function getConfig(
address _oapp,
address _lib,
uint32 _eid,
uint32 _configType
) external view onlyRegistered(_lib) returns (bytes memory config) {
return IMessageLib(_lib).getConfig(_eid, _oapp, _configType);
}
function _assertAuthorized(address _oapp) internal virtual;
}