@@ -16,7 +16,7 @@ import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
16
16
import {InteroperableAddress} from "@openzeppelin/contracts/utils/draft-InteroperableAddress.sol " ;
17
17
import {IndirectCall} from "../utils/IndirectCall.sol " ;
18
18
19
- contract ERC7802Bridge is ERC721 ("ERC7802Bridge ", "ERC7802Bridge "), IERC7786Receiver {
19
+ abstract contract ERC7802Bridge is ERC721 ("ERC7802Bridge ", "ERC7802Bridge "), IERC7786Receiver {
20
20
using BitMaps for BitMaps.BitMap;
21
21
using InteroperableAddress for bytes ;
22
22
@@ -72,76 +72,39 @@ contract ERC7802Bridge is ERC721("ERC7802Bridge", "ERC7802Bridge"), IERC7786Rece
72
72
}
73
73
74
74
// ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
75
- // │ Bridge creation and administration │
75
+ // │ Bridge management │
76
76
// └─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
77
- struct Foreign {
78
- bytes32 id;
79
- address gateway;
80
- bytes remote;
81
- }
82
-
83
- function createBridge (
84
- address token ,
85
- address admin ,
86
- bool isCustodial ,
87
- Foreign[] calldata foreign
88
- ) public returns (bytes32 ) {
89
- bytes32 [] memory ids = new bytes32 [](foreign.length + 1 );
90
- bytes32 [] memory links = new bytes32 [](foreign.length );
91
- for (uint256 i = 0 ; i < foreign.length ; ++ i) {
92
- require (foreign[i].gateway != address (0 ) && foreign[i].remote.length > 0 );
93
- ids[i] = foreign[i].id;
94
- links[i] = keccak256 (
95
- abi.encode (InteroperableAddress.formatEvmV1 (block .chainid , foreign[i].gateway), foreign[i].remote)
96
- );
97
- }
98
- ids[foreign.length ] = keccak256 (
99
- abi.encode (
100
- InteroperableAddress.formatEvmV1 (block .chainid , token), // bytes token
101
- bytes32 (bytes20 (admin)) | bytes32 (SafeCast.toUint (isCustodial)), // bytes32 tokenOptions
102
- Arrays.sort (links)
103
- )
104
- );
105
-
106
- bytes32 bridgeId = keccak256 (abi.encodePacked (Arrays.sort (ids)));
107
-
108
- // Should we check for collision. I don't think that is necessary
109
- BridgeMetadata storage details = _bridges[bridgeId];
110
- details.token = token;
111
- details.isCustodial = isCustodial;
112
-
113
- _safeMint (admin == address (0 ) ? address (1 ) : admin, uint256 (bridgeId));
114
-
115
- for (uint256 i = 0 ; i < foreign.length ; ++ i) {
116
- (bytes2 chainType , bytes memory chainReference , ) = foreign[i].remote.parseV1 ();
117
- bytes memory chain = InteroperableAddress.formatV1 (chainType, chainReference, "" );
118
- require (details.gateway[chain] == address (0 ));
119
- details.gateway[chain] = foreign[i].gateway;
120
- details.remote[chain] = foreign[i].remote;
121
-
122
- emit BridgeLinkSet (bridgeId, foreign[i].gateway, foreign[i].remote);
123
- }
124
-
125
- return bridgeId;
126
- }
127
77
128
78
function setPaused (bytes32 bridgeId , bool isPaused ) public bridgeAdminRestricted (bridgeId) {
129
- _bridges[bridgeId].isPaused = isPaused;
130
- emit BridgePaused (bridgeId, isPaused);
79
+ _setPaused (bridgeId, isPaused);
131
80
}
132
81
133
82
function updateGateway (
134
83
bytes32 bridgeId ,
135
- bytes calldata chain ,
84
+ bytes memory chain ,
136
85
address gateway ,
137
- bytes calldata remote
138
- ) public bridgeAdminRestricted (bridgeId) {
139
- require (gateway != address (0 ) && remote.length > 0 );
86
+ bytes memory remote
87
+ ) public virtual bridgeAdminRestricted (bridgeId) {
88
+ _setGateway (bridgeId, chain, gateway, remote);
89
+ }
90
+
91
+ function _setBridge (bytes32 bridgeId , address token , address admin , bool isCustodial ) internal {
92
+ _safeMint (admin == address (0 ) ? address (1 ) : admin, uint256 (bridgeId));
93
+ _bridges[bridgeId].token = token;
94
+ _bridges[bridgeId].isCustodial = isCustodial;
95
+ }
96
+
97
+ function _setGateway (bytes32 bridgeId , bytes memory chain , address gateway , bytes memory remote ) internal {
140
98
_bridges[bridgeId].gateway[chain] = gateway;
141
99
_bridges[bridgeId].remote[chain] = remote;
142
100
emit BridgeLinkSet (bridgeId, gateway, remote);
143
101
}
144
102
103
+ function _setPaused (bytes32 bridgeId , bool isPaused ) internal {
104
+ _bridges[bridgeId].isPaused = isPaused;
105
+ emit BridgePaused (bridgeId, isPaused);
106
+ }
107
+
145
108
// ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
146
109
// │ Send / Receive tokens │
147
110
// └─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
@@ -254,3 +217,77 @@ contract ERC7802Bridge is ERC721("ERC7802Bridge", "ERC7802Bridge"), IERC7786Rece
254
217
return token;
255
218
}
256
219
}
220
+
221
+ contract ERC7802BridgeLinks is ERC7802Bridge {
222
+ function createBridge (address token , address admin , bool isCustodial , bytes32 salt ) public returns (bytes32 ) {
223
+ bytes32 bridgeId = keccak256 (abi.encodePacked (msg .sender , salt));
224
+
225
+ _setBridge (bridgeId, token, admin, isCustodial);
226
+
227
+ return bridgeId;
228
+ }
229
+ }
230
+
231
+ contract ERC7802BridgeCounterfactual is ERC7802Bridge {
232
+ using InteroperableAddress for bytes ;
233
+
234
+ struct Foreign {
235
+ bytes32 id;
236
+ address gateway;
237
+ bytes remote;
238
+ }
239
+
240
+ function createBridge (
241
+ address token ,
242
+ address admin ,
243
+ bool isCustodial ,
244
+ Foreign[] calldata foreign
245
+ ) public returns (bytes32 ) {
246
+ bytes32 bridgeId = _counterfactualBridgeId (
247
+ token,
248
+ bytes32 (bytes20 (admin)) | bytes32 (SafeCast.toUint (isCustodial)),
249
+ foreign
250
+ );
251
+
252
+ _setBridge (bridgeId, token, admin, isCustodial);
253
+ for (uint256 i = 0 ; i < foreign.length ; ++ i) {
254
+ (bytes2 chainType , bytes memory chainReference , ) = foreign[i].remote.parseV1Calldata ();
255
+ bytes memory chain = InteroperableAddress.formatV1 (chainType, chainReference, "" );
256
+ _setGateway (bridgeId, chain, foreign[i].gateway, foreign[i].remote);
257
+ }
258
+
259
+ return bridgeId;
260
+ }
261
+
262
+ function updateGateway (
263
+ bytes32 bridgeId ,
264
+ bytes memory chain ,
265
+ address gateway ,
266
+ bytes memory remote
267
+ ) public virtual override {
268
+ require (gateway != address (0 ) && remote.length > 0 );
269
+ // super call is bridgeAdminRestricted(bridgeId)
270
+ super .updateGateway (bridgeId, chain, gateway, remote);
271
+ }
272
+
273
+ function _counterfactualBridgeId (
274
+ address token ,
275
+ bytes32 opts ,
276
+ Foreign[] calldata foreign
277
+ ) private view returns (bytes32 ) {
278
+ bytes32 [] memory ids = new bytes32 [](foreign.length + 1 );
279
+ bytes32 [] memory links = new bytes32 [](foreign.length );
280
+ for (uint256 i = 0 ; i < foreign.length ; ++ i) {
281
+ require (foreign[i].gateway != address (0 ) && foreign[i].remote.length > 0 );
282
+ ids[i] = foreign[i].id;
283
+ links[i] = keccak256 (
284
+ abi.encode (InteroperableAddress.formatEvmV1 (block .chainid , foreign[i].gateway), foreign[i].remote)
285
+ );
286
+ }
287
+ ids[foreign.length ] = keccak256 (
288
+ abi.encode (InteroperableAddress.formatEvmV1 (block .chainid , token), opts, Arrays.sort (links))
289
+ );
290
+
291
+ return keccak256 (abi.encodePacked (Arrays.sort (ids)));
292
+ }
293
+ }
0 commit comments