@@ -16,7 +16,7 @@ import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
1616import {InteroperableAddress} from "@openzeppelin/contracts/utils/draft-InteroperableAddress.sol " ;
1717import {IndirectCall} from "../utils/IndirectCall.sol " ;
1818
19- contract ERC7802Bridge is ERC721 ("ERC7802Bridge ", "ERC7802Bridge "), IERC7786Receiver {
19+ abstract contract ERC7802Bridge is ERC721 ("ERC7802Bridge ", "ERC7802Bridge "), IERC7786Receiver {
2020 using BitMaps for BitMaps.BitMap;
2121 using InteroperableAddress for bytes ;
2222
@@ -72,76 +72,39 @@ contract ERC7802Bridge is ERC721("ERC7802Bridge", "ERC7802Bridge"), IERC7786Rece
7272 }
7373
7474 // ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
75- // │ Bridge creation and administration │
75+ // │ Bridge management │
7676 // └─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
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- }
12777
12878 function setPaused (bytes32 bridgeId , bool isPaused ) public bridgeAdminRestricted (bridgeId) {
129- _bridges[bridgeId].isPaused = isPaused;
130- emit BridgePaused (bridgeId, isPaused);
79+ _setPaused (bridgeId, isPaused);
13180 }
13281
13382 function updateGateway (
13483 bytes32 bridgeId ,
135- bytes calldata chain ,
84+ bytes memory chain ,
13685 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 {
14098 _bridges[bridgeId].gateway[chain] = gateway;
14199 _bridges[bridgeId].remote[chain] = remote;
142100 emit BridgeLinkSet (bridgeId, gateway, remote);
143101 }
144102
103+ function _setPaused (bytes32 bridgeId , bool isPaused ) internal {
104+ _bridges[bridgeId].isPaused = isPaused;
105+ emit BridgePaused (bridgeId, isPaused);
106+ }
107+
145108 // ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
146109 // │ Send / Receive tokens │
147110 // └─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
@@ -254,3 +217,77 @@ contract ERC7802Bridge is ERC721("ERC7802Bridge", "ERC7802Bridge"), IERC7786Rece
254217 return token;
255218 }
256219}
220+
221+ contract ERC7802BridgeLinks is ERC7802Bridge {
222+ function createBridge (address token , bool isCustodial , bytes32 salt ) public returns (bytes32 ) {
223+ bytes32 bridgeId = keccak256 (abi.encodePacked (msg .sender , salt));
224+
225+ _setBridge (bridgeId, token, msg .sender , 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