1
1
// SPDX-License-Identifier: Apache 2
2
2
pragma solidity >= 0.8.8 < 0.9.0 ;
3
3
4
- /// @title TransceiverRegistry
5
- /// @author Wormhole Project Contributors.
6
- /// @notice This contract is responsible for handling the registration of Transceivers.
7
- /// @dev This contract checks that a few critical invariants hold when transceivers are added or removed,
8
- /// including:
9
- /// 1. If a transceiver is not registered, it should be enabled.
10
- /// 2. The value set in the bitmap of trannsceivers
11
- /// should directly correspond to the whether the transceiver is enabled
12
- abstract contract TransceiverRegistry {
13
- constructor () {
14
- _checkTransceiversInvariants ();
15
- }
16
-
4
+ /// @dev TransceiverRegistryBase is a base class shared between TransceiverRegistry and TransceiverRegistryAdmin.
5
+ abstract contract TransceiverRegistryBase {
17
6
/// @dev Information about registered transceivers.
18
7
struct TransceiverInfo {
19
8
// whether this transceiver is registered
@@ -38,7 +27,83 @@ abstract contract TransceiverRegistry {
38
27
uint8 enabled;
39
28
}
40
29
41
- uint8 constant MAX_TRANSCEIVERS = 64 ;
30
+ uint8 public constant MAX_TRANSCEIVERS = 64 ;
31
+
32
+ bytes32 internal constant TRANSCEIVER_INFOS_SLOT =
33
+ bytes32 (uint256 (keccak256 ("ntt.transceiverInfos " )) - 1 );
34
+
35
+ bytes32 internal constant TRANSCEIVER_BITMAP_SLOT =
36
+ bytes32 (uint256 (keccak256 ("ntt.transceiverBitmap " )) - 1 );
37
+
38
+ bytes32 internal constant ENABLED_TRANSCEIVERS_SLOT =
39
+ bytes32 (uint256 (keccak256 ("ntt.enabledTransceivers " )) - 1 );
40
+
41
+ bytes32 internal constant REGISTERED_TRANSCEIVERS_SLOT =
42
+ bytes32 (uint256 (keccak256 ("ntt.registeredTransceivers " )) - 1 );
43
+
44
+ bytes32 internal constant NUM_REGISTERED_TRANSCEIVERS_SLOT =
45
+ bytes32 (uint256 (keccak256 ("ntt.numRegisteredTransceivers " )) - 1 );
46
+
47
+ function _getTransceiverInfosStorage ()
48
+ internal
49
+ pure
50
+ returns (mapping (address => TransceiverInfo) storage $)
51
+ {
52
+ uint256 slot = uint256 (TRANSCEIVER_INFOS_SLOT);
53
+ assembly ("memory-safe" ) {
54
+ $.slot := slot
55
+ }
56
+ }
57
+
58
+ function _getTransceiverBitmapStorage ()
59
+ internal
60
+ pure
61
+ returns (_EnabledTransceiverBitmap storage $)
62
+ {
63
+ uint256 slot = uint256 (TRANSCEIVER_BITMAP_SLOT);
64
+ assembly ("memory-safe" ) {
65
+ $.slot := slot
66
+ }
67
+ }
68
+
69
+ function _getRegisteredTransceiversStorage () internal pure returns (address [] storage $) {
70
+ uint256 slot = uint256 (REGISTERED_TRANSCEIVERS_SLOT);
71
+ assembly ("memory-safe" ) {
72
+ $.slot := slot
73
+ }
74
+ }
75
+
76
+ function _getNumTransceiversStorage () internal pure returns (_NumTransceivers storage $) {
77
+ uint256 slot = uint256 (NUM_REGISTERED_TRANSCEIVERS_SLOT);
78
+ assembly ("memory-safe" ) {
79
+ $.slot := slot
80
+ }
81
+ }
82
+
83
+ function _getEnabledTransceiversStorage () internal pure returns (address [] storage $) {
84
+ uint256 slot = uint256 (ENABLED_TRANSCEIVERS_SLOT);
85
+ assembly ("memory-safe" ) {
86
+ $.slot := slot
87
+ }
88
+ }
89
+ }
90
+
91
+ /// @title TransceiverRegistry
92
+ /// @author Wormhole Project Contributors.
93
+ /// @notice This contract is responsible for handling the registration of Transceivers.
94
+ /// @dev This contract checks that a few critical invariants hold when transceivers are added or removed,
95
+ /// including:
96
+ /// 1. If a transceiver is not registered, it should be enabled.
97
+ /// 2. The value set in the bitmap of trannsceivers
98
+ /// should directly correspond to the whether the transceiver is enabled
99
+ abstract contract TransceiverRegistry is TransceiverRegistryBase {
100
+ // TODO: Tests fail if I remove the immutable. Could pass this into the constructor and make `TransceiverRegistryAdmin` upgradeable.
101
+ address private immutable _admin;
102
+
103
+ constructor () {
104
+ _admin = address (new TransceiverRegistryAdmin ());
105
+ _checkTransceiversInvariants ();
106
+ }
42
107
43
108
/// @notice Error when the caller is not the transceiver.
44
109
/// @dev Selector 0xa0ae911d.
@@ -76,86 +141,114 @@ abstract contract TransceiverRegistry {
76
141
_;
77
142
}
78
143
79
- // =============== Storage ======= ========================================
144
+ // =============== Storage Getters/Setters ========================================
80
145
81
- bytes32 private constant TRANSCEIVER_INFOS_SLOT =
82
- bytes32 (uint256 (keccak256 ("ntt.transceiverInfos " )) - 1 );
146
+ function _setTransceiver (
147
+ address transceiver
148
+ ) internal returns (uint8 index ) {
149
+ (bool success , bytes memory returnData ) = _admin.delegatecall (
150
+ abi.encodeWithSelector (TransceiverRegistryAdmin._setTransceiver.selector , transceiver)
151
+ );
152
+ _checkDelegateCallRevert (success, returnData);
153
+ (index) = abi.decode (returnData, (uint8 ));
154
+ }
83
155
84
- bytes32 private constant TRANSCEIVER_BITMAP_SLOT =
85
- bytes32 (uint256 (keccak256 ("ntt.transceiverBitmap " )) - 1 );
156
+ function _removeTransceiver (
157
+ address transceiver
158
+ ) internal {
159
+ (bool success , bytes memory returnData ) = _admin.delegatecall (
160
+ abi.encodeWithSelector (
161
+ TransceiverRegistryAdmin._removeTransceiver.selector , transceiver
162
+ )
163
+ );
164
+ _checkDelegateCallRevert (success, returnData);
165
+ }
86
166
87
- bytes32 private constant ENABLED_TRANSCEIVERS_SLOT =
88
- bytes32 (uint256 (keccak256 ("ntt.enabledTransceivers " )) - 1 );
167
+ function _getEnabledTransceiversBitmap () internal view virtual returns (uint64 bitmap ) {
168
+ return _getTransceiverBitmapStorage ().bitmap;
169
+ }
89
170
90
- bytes32 private constant REGISTERED_TRANSCEIVERS_SLOT =
91
- bytes32 (uint256 (keccak256 ("ntt.registeredTransceivers " )) - 1 );
171
+ /// @notice Returns the Transceiver contracts that have been enabled via governance.
172
+ function getTransceivers () external pure returns (address [] memory result ) {
173
+ result = _getEnabledTransceiversStorage ();
174
+ }
92
175
93
- bytes32 private constant NUM_REGISTERED_TRANSCEIVERS_SLOT =
94
- bytes32 (uint256 (keccak256 ("ntt.numRegisteredTransceivers " )) - 1 );
176
+ /// @notice Returns the info for all enabled transceivers
177
+ /// @dev moving this into `TransceiverRegistryAdmin` reduces the size of `NttManger` but increases the size of `NttManagerNoRateLimiting`.
178
+ function getTransceiverInfo () external view returns (TransceiverInfo[] memory ) {
179
+ address [] memory enabledTransceivers = _getEnabledTransceiversStorage ();
180
+ uint256 numEnabledTransceivers = enabledTransceivers.length ;
181
+ TransceiverInfo[] memory result = new TransceiverInfo [](numEnabledTransceivers);
95
182
96
- function _getTransceiverInfosStorage ()
97
- internal
98
- pure
99
- returns (mapping (address => TransceiverInfo) storage $)
100
- {
101
- uint256 slot = uint256 (TRANSCEIVER_INFOS_SLOT);
102
- assembly ("memory-safe" ) {
103
- $.slot := slot
183
+ for (uint256 i = 0 ; i < numEnabledTransceivers; ++ i) {
184
+ result[i] = _getTransceiverInfosStorage ()[enabledTransceivers[i]];
104
185
}
105
- }
106
186
107
- function _getEnabledTransceiversStorage () internal pure returns (address [] storage $) {
108
- uint256 slot = uint256 (ENABLED_TRANSCEIVERS_SLOT);
109
- assembly ("memory-safe" ) {
110
- $.slot := slot
111
- }
187
+ return result;
112
188
}
113
189
114
- function _getTransceiverBitmapStorage ()
115
- private
116
- pure
117
- returns (_EnabledTransceiverBitmap storage $)
118
- {
119
- uint256 slot = uint256 (TRANSCEIVER_BITMAP_SLOT);
120
- assembly ("memory-safe" ) {
121
- $.slot := slot
122
- }
190
+ // ============== Invariants =============================================
191
+
192
+ /// @dev Check that the transceiver nttManager is in a valid state.
193
+ /// Checking these invariants is somewhat costly, but we only need to do it
194
+ /// when modifying the transceivers, which happens infrequently.
195
+ function _checkTransceiversInvariants () internal view {
196
+ (bool success , bytes memory returnData ) = _admin.staticcall (
197
+ abi.encodeWithSelector (TransceiverRegistryAdmin._checkTransceiversInvariants.selector )
198
+ );
199
+ _checkDelegateCallRevert (success, returnData);
123
200
}
124
201
125
- function _getRegisteredTransceiversStorage () internal pure returns (address [] storage $) {
126
- uint256 slot = uint256 (REGISTERED_TRANSCEIVERS_SLOT);
127
- assembly ("memory-safe" ) {
128
- $.slot := slot
129
- }
202
+ // @dev Check that the transceiver is in a valid state.
203
+ function _checkTransceiverInvariants (
204
+ address transceiver
205
+ ) private view {
206
+ (bool success , bytes memory returnData ) = _admin.staticcall (
207
+ abi.encodeWithSelector (
208
+ TransceiverRegistryAdmin._checkTransceiverInvariants.selector , transceiver
209
+ )
210
+ );
211
+ _checkDelegateCallRevert (success, returnData);
130
212
}
131
213
132
- function _getNumTransceiversStorage () internal pure returns (_NumTransceivers storage $) {
133
- uint256 slot = uint256 (NUM_REGISTERED_TRANSCEIVERS_SLOT);
134
- assembly ("memory-safe" ) {
135
- $.slot := slot
214
+ function _checkDelegateCallRevert (bool success , bytes memory returnData ) private pure {
215
+ // if the function call reverted
216
+ if (success == false ) {
217
+ // if there is a return reason string
218
+ if (returnData.length > 0 ) {
219
+ // bubble up any reason for revert
220
+ assembly {
221
+ let returndata_size := mload (returnData)
222
+ revert (add (32 , returnData), returndata_size)
223
+ }
224
+ } else {
225
+ revert ("_removeTransceiver reverted " );
226
+ }
136
227
}
137
228
}
229
+ }
138
230
139
- // =============== Storage Getters/Setters ========================================
140
-
231
+ /// @dev TransceiverRegistryAdmin is a helper contract to TransceiverRegistry.
232
+ /// It implements admin functionality and is called via `delegatecall`.
233
+ contract TransceiverRegistryAdmin is TransceiverRegistryBase {
141
234
function _setTransceiver (
142
235
address transceiver
143
- ) internal returns (uint8 index ) {
236
+ ) public returns (uint8 index ) {
144
237
mapping (address => TransceiverInfo) storage transceiverInfos = _getTransceiverInfosStorage ();
145
238
_EnabledTransceiverBitmap storage _enabledTransceiverBitmap = _getTransceiverBitmapStorage ();
146
239
address [] storage _enabledTransceivers = _getEnabledTransceiversStorage ();
147
240
148
241
_NumTransceivers storage _numTransceivers = _getNumTransceiversStorage ();
149
242
150
243
if (transceiver == address (0 )) {
151
- revert InvalidTransceiverZeroAddress ();
244
+ revert TransceiverRegistry. InvalidTransceiverZeroAddress ();
152
245
}
153
246
154
247
if (transceiverInfos[transceiver].registered) {
155
248
transceiverInfos[transceiver].enabled = true ;
156
249
} else {
157
250
if (_numTransceivers.registered >= MAX_TRANSCEIVERS) {
158
- revert TooManyTransceivers ();
251
+ revert TransceiverRegistry. TooManyTransceivers ();
159
252
}
160
253
161
254
transceiverInfos[transceiver] = TransceiverInfo ({
@@ -174,7 +267,7 @@ abstract contract TransceiverRegistry {
174
267
_enabledTransceiverBitmap.bitmap | uint64 (1 << transceiverInfos[transceiver].index);
175
268
// ensure that this actually changed the bitmap
176
269
if (updatedEnabledTransceiverBitmap == _enabledTransceiverBitmap.bitmap) {
177
- revert TransceiverAlreadyEnabled (transceiver);
270
+ revert TransceiverRegistry. TransceiverAlreadyEnabled (transceiver);
178
271
}
179
272
_enabledTransceiverBitmap.bitmap = updatedEnabledTransceiverBitmap;
180
273
@@ -185,21 +278,21 @@ abstract contract TransceiverRegistry {
185
278
186
279
function _removeTransceiver (
187
280
address transceiver
188
- ) internal {
281
+ ) public {
189
282
mapping (address => TransceiverInfo) storage transceiverInfos = _getTransceiverInfosStorage ();
190
283
_EnabledTransceiverBitmap storage _enabledTransceiverBitmap = _getTransceiverBitmapStorage ();
191
284
address [] storage _enabledTransceivers = _getEnabledTransceiversStorage ();
192
285
193
286
if (transceiver == address (0 )) {
194
- revert InvalidTransceiverZeroAddress ();
287
+ revert TransceiverRegistry. InvalidTransceiverZeroAddress ();
195
288
}
196
289
197
290
if (! transceiverInfos[transceiver].registered) {
198
- revert NonRegisteredTransceiver (transceiver);
291
+ revert TransceiverRegistry. NonRegisteredTransceiver (transceiver);
199
292
}
200
293
201
294
if (! transceiverInfos[transceiver].enabled) {
202
- revert DisabledTransceiver (transceiver);
295
+ revert TransceiverRegistry. DisabledTransceiver (transceiver);
203
296
}
204
297
205
298
transceiverInfos[transceiver].enabled = false ;
@@ -230,34 +323,10 @@ abstract contract TransceiverRegistry {
230
323
_checkTransceiverInvariants (transceiver);
231
324
}
232
325
233
- function _getEnabledTransceiversBitmap () internal view virtual returns (uint64 bitmap ) {
234
- return _getTransceiverBitmapStorage ().bitmap;
235
- }
236
-
237
- /// @notice Returns the Transceiver contracts that have been enabled via governance.
238
- function getTransceivers () external pure returns (address [] memory result ) {
239
- result = _getEnabledTransceiversStorage ();
240
- }
241
-
242
- /// @notice Returns the info for all enabled transceivers
243
- function getTransceiverInfo () external view returns (TransceiverInfo[] memory ) {
244
- address [] memory enabledTransceivers = _getEnabledTransceiversStorage ();
245
- uint256 numEnabledTransceivers = enabledTransceivers.length ;
246
- TransceiverInfo[] memory result = new TransceiverInfo [](numEnabledTransceivers);
247
-
248
- for (uint256 i = 0 ; i < numEnabledTransceivers; ++ i) {
249
- result[i] = _getTransceiverInfosStorage ()[enabledTransceivers[i]];
250
- }
251
-
252
- return result;
253
- }
254
-
255
- // ============== Invariants =============================================
256
-
257
326
/// @dev Check that the transceiver nttManager is in a valid state.
258
327
/// Checking these invariants is somewhat costly, but we only need to do it
259
328
/// when modifying the transceivers, which happens infrequently.
260
- function _checkTransceiversInvariants () internal view {
329
+ function _checkTransceiversInvariants () public view {
261
330
_NumTransceivers storage _numTransceivers = _getNumTransceiversStorage ();
262
331
address [] storage _enabledTransceivers = _getEnabledTransceiversStorage ();
263
332
@@ -282,7 +351,7 @@ abstract contract TransceiverRegistry {
282
351
// @dev Check that the transceiver is in a valid state.
283
352
function _checkTransceiverInvariants (
284
353
address transceiver
285
- ) private view {
354
+ ) public view {
286
355
mapping (address => TransceiverInfo) storage transceiverInfos = _getTransceiverInfosStorage ();
287
356
_EnabledTransceiverBitmap storage _enabledTransceiverBitmap = _getTransceiverBitmapStorage ();
288
357
_NumTransceivers storage _numTransceivers = _getNumTransceiversStorage ();
0 commit comments