@hyperbridge/core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,335 @@
1
+ // Copyright (C) Polytope Labs Ltd.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ pragma solidity ^0.8.17;
15
+
16
+ import {StorageValue} from "@polytope-labs/solidity-merkle-trees/src/Types.sol";
17
+ import {StateMachineHeight} from "../interfaces/IConsensus.sol";
18
+
19
+ /**
20
+ * @title FrozenStatus
21
+ * @notice Represents the frozen state of the Host for security and emergency situations
22
+ * @dev Used to halt specific protocol operations during security incidents or upgrades
23
+ */
24
+ enum FrozenStatus {
25
+ /// @notice Normal operation - all functions are enabled
26
+ None,
27
+ /// @notice Incoming messages are blocked - prevents receiving cross-chain messages
28
+ Incoming,
29
+ /// @notice Outgoing messages are blocked - prevents sending cross-chain messages
30
+ Outgoing,
31
+ /// @notice All operations are frozen - complete protocol halt
32
+ All
33
+ }
34
+
35
+ /**
36
+ * @title PostRequest
37
+ * @notice Represents a cross-chain message request
38
+ * @dev Contains all necessary information for routing and processing a cross-chain message
39
+ */
40
+ struct PostRequest {
41
+ /// @notice Source chain identifier (e.g., "POLKADOT-1000", "EVM-1")
42
+ bytes source;
43
+ /// @notice Destination chain identifier
44
+ bytes dest;
45
+ /// @notice Unique nonce for this request on the source chain
46
+ uint64 nonce;
47
+ /// @notice Source application address that initiated this request
48
+ bytes from;
49
+ /// @notice Destination application address to receive this request
50
+ bytes to;
51
+ /// @notice Unix timestamp when this request expires
52
+ uint64 timeoutTimestamp;
53
+ /// @notice Request payload to be delivered to the destination
54
+ bytes body;
55
+ }
56
+
57
+ /**
58
+ * @title GetRequest
59
+ * @notice Represents a cross-chain state query request
60
+ * @dev Used to read storage values from other chains at specific heights
61
+ */
62
+ struct GetRequest {
63
+ /// @notice Source chain identifier where the query originated
64
+ bytes source;
65
+ /// @notice Destination chain identifier to query
66
+ bytes dest;
67
+ /// @notice Unique nonce for this request on the source chain
68
+ uint64 nonce;
69
+ /// @notice Address of the application that initiated this query
70
+ address from;
71
+ /// @notice Unix timestamp when this query expires
72
+ uint64 timeoutTimestamp;
73
+ /// @notice Storage keys to retrieve from the destination chain
74
+ bytes[] keys;
75
+ /// @notice Block height at which to read the state (0 for latest)
76
+ uint64 height;
77
+ /// @notice Application-specific metadata for tracking the query
78
+ bytes context;
79
+ }
80
+
81
+ /**
82
+ * @title GetResponse
83
+ * @notice Represents a response to a cross-chain state query
84
+ * @dev Contains the original query request and the retrieved storage values
85
+ */
86
+ struct GetResponse {
87
+ /// @notice The original GET request being responded to
88
+ GetRequest request;
89
+ /// @notice Retrieved storage values from the queried chain
90
+ StorageValue[] values;
91
+ }
92
+
93
+ /**
94
+ * @title PostResponse
95
+ * @notice Represents a response to a cross-chain POST request
96
+ * @dev Contains the original request and the response data
97
+ */
98
+ struct PostResponse {
99
+ /// @notice The original request being responded to
100
+ PostRequest request;
101
+ /// @notice Response payload to send back to the requester
102
+ bytes response;
103
+ /// @notice Unix timestamp when this response expires
104
+ uint64 timeoutTimestamp;
105
+ }
106
+
107
+ /**
108
+ * @title PostRequestLeaf
109
+ * @notice Represents a POST request as a leaf in a Merkle Mountain Range tree
110
+ * @dev Used for generating and verifying merkle proofs of requests
111
+ */
112
+ struct PostRequestLeaf {
113
+ /// @notice The POST request data
114
+ PostRequest request;
115
+ /// @notice Position in the MMR leaves array
116
+ uint256 index;
117
+ /// @notice K-index for MMR proof generation
118
+ uint256 kIndex;
119
+ }
120
+
121
+ /**
122
+ * @title PostResponseLeaf
123
+ * @notice Represents a POST response as a leaf in a Merkle Mountain Range tree
124
+ * @dev Used for generating and verifying merkle proofs of responses
125
+ */
126
+ struct PostResponseLeaf {
127
+ /// @notice The POST response data
128
+ PostResponse response;
129
+ /// @notice Position in the MMR leaves array
130
+ uint256 index;
131
+ /// @notice K-index for MMR proof generation
132
+ uint256 kIndex;
133
+ }
134
+
135
+ // A get response as a leaf in a merkle mountain range tree
136
+ /**
137
+ * @title GetResponseLeaf
138
+ * @notice Represents a GET response as a leaf in a Merkle Mountain Range tree
139
+ * @dev Used for generating and verifying merkle proofs of state query responses
140
+ */
141
+ struct GetResponseLeaf {
142
+ /// @notice The GET response data
143
+ GetResponse response;
144
+ /// @notice Position in the MMR leaves array
145
+ uint256 index;
146
+ /// @notice K-index for MMR proof generation
147
+ uint256 kIndex;
148
+ }
149
+
150
+ /**
151
+ * @title Proof
152
+ * @notice Merkle Mountain Range proof for message verification
153
+ * @dev Used to prove inclusion of messages in the protocol's merkle tree
154
+ */
155
+ struct Proof {
156
+ /// @notice State machine height where this proof is anchored
157
+ StateMachineHeight height;
158
+ /// @notice Array of merkle tree nodes forming the inclusion proof
159
+ bytes32[] multiproof;
160
+ /// @notice Total number of leaves in the MMR at this height
161
+ uint256 leafCount;
162
+ }
163
+
164
+ // A message for handling incoming requests
165
+ /**
166
+ * @title PostRequestMessage
167
+ * @notice Batch of POST requests with their merkle proof
168
+ * @dev Used by the Handler to verify and process incoming POST requests
169
+ */
170
+ struct PostRequestMessage {
171
+ /// @notice Merkle proof for verifying the requests
172
+ Proof proof;
173
+ /// @notice Array of POST requests as MMR leaves
174
+ PostRequestLeaf[] requests;
175
+ }
176
+
177
+ // A message for handling incoming GET responses
178
+ struct GetResponseMessage {
179
+ // proof for the responses
180
+ Proof proof;
181
+ // The responses, contained in the merkle mountain range tree
182
+ GetResponseLeaf[] responses;
183
+ }
184
+
185
+ /**
186
+ * @title GetTimeoutMessage
187
+ * @notice Batch of timed-out GET requests with their non-membership proof
188
+ * @dev Used to prove that GET requests were not responded to before timeout
189
+ */
190
+ struct GetTimeoutMessage {
191
+ /// @notice Array of GET requests that have timed out
192
+ GetRequest[] timeouts;
193
+ /// @notice Height at which the timeout proof is generated
194
+ StateMachineHeight height;
195
+ /// @notice Non-membership proof showing requests were not processed
196
+ bytes[] proof;
197
+ }
198
+
199
+ /**
200
+ * @title PostRequestTimeoutMessage
201
+ * @notice Batch of timed-out POST requests with their non-membership proof
202
+ * @dev Used to prove that POST requests were not responded to before timeout
203
+ */
204
+ struct PostRequestTimeoutMessage {
205
+ /// @notice Array of POST requests that have timed out
206
+ PostRequest[] timeouts;
207
+ /// @notice Height at which the timeout proof is generated
208
+ StateMachineHeight height;
209
+ /// @notice Non-membership proof showing requests were not processed
210
+ bytes[] proof;
211
+ }
212
+
213
+ /**
214
+ * @title PostResponseTimeoutMessage
215
+ * @notice Batch of timed-out POST responses with their non-membership proof
216
+ * @dev Used to prove that POST responses were not acknowledged before timeout
217
+ */
218
+ struct PostResponseTimeoutMessage {
219
+ /// @notice Array of POST responses that have timed out
220
+ PostResponse[] timeouts;
221
+ /// @notice Height at which the timeout proof is generated
222
+ StateMachineHeight height;
223
+ /// @notice Non-membership proof showing responses were not processed
224
+ bytes[] proof;
225
+ }
226
+
227
+ // A message for handling incoming responses
228
+ /**
229
+ * @title PostResponseMessage
230
+ * @notice Batch of POST responses with their merkle proof
231
+ * @dev Used by the Handler to verify and process incoming POST responses
232
+ */
233
+ struct PostResponseMessage {
234
+ /// @notice Merkle proof for verifying the responses
235
+ Proof proof;
236
+ /// @notice Array of POST responses as MMR leaves
237
+ PostResponseLeaf[] responses;
238
+ }
239
+
240
+ library Message {
241
+ /**
242
+ * @dev Calculates the absolute timeout value for a PostRequest
243
+ */
244
+ function timeout(PostRequest memory req) internal pure returns (uint64) {
245
+ if (req.timeoutTimestamp == 0) {
246
+ return type(uint64).max;
247
+ } else {
248
+ return req.timeoutTimestamp;
249
+ }
250
+ }
251
+
252
+ /**
253
+ * @dev Calculates the absolute timeout value for a GetRequest
254
+ */
255
+ function timeout(GetRequest memory req) internal pure returns (uint64) {
256
+ if (req.timeoutTimestamp == 0) {
257
+ return type(uint64).max;
258
+ } else {
259
+ return req.timeoutTimestamp;
260
+ }
261
+ }
262
+
263
+ /**
264
+ * @dev Calculates the absolute timeout value for a PostResponse
265
+ */
266
+ function timeout(PostResponse memory res) internal pure returns (uint64) {
267
+ if (res.timeoutTimestamp == 0) {
268
+ return type(uint64).max;
269
+ } else {
270
+ return res.timeoutTimestamp;
271
+ }
272
+ }
273
+
274
+ /**
275
+ * @dev Encode the given post request for commitment
276
+ */
277
+ function encode(PostRequest memory req) internal pure returns (bytes memory) {
278
+ return abi.encodePacked(req.source, req.dest, req.nonce, req.timeoutTimestamp, req.from, req.to, req.body);
279
+ }
280
+
281
+ /**
282
+ * @dev Encode the given get request for commitment
283
+ */
284
+ function encode(GetRequest memory req) internal pure returns (bytes memory) {
285
+ bytes memory keysEncoding = bytes("");
286
+ uint256 len = req.keys.length;
287
+ for (uint256 i = 0; i < len; i++) {
288
+ keysEncoding = bytes.concat(keysEncoding, req.keys[i]);
289
+ }
290
+
291
+ return abi.encodePacked(
292
+ req.source,
293
+ req.dest,
294
+ req.nonce,
295
+ req.height,
296
+ req.timeoutTimestamp,
297
+ abi.encodePacked(req.from),
298
+ keysEncoding,
299
+ req.context
300
+ );
301
+ }
302
+
303
+ /**
304
+ * @dev Returns the commitment for the given post response
305
+ */
306
+ function hash(PostResponse memory res) internal pure returns (bytes32) {
307
+ return keccak256(bytes.concat(encode(res.request), abi.encodePacked(res.response, res.timeoutTimestamp)));
308
+ }
309
+
310
+ /**
311
+ * @dev Returns the commitment for the given post request
312
+ */
313
+ function hash(PostRequest memory req) internal pure returns (bytes32) {
314
+ return keccak256(encode(req));
315
+ }
316
+
317
+ /**
318
+ * @dev Returns the commitment for the given get request
319
+ */
320
+ function hash(GetRequest memory req) internal pure returns (bytes32) {
321
+ return keccak256(encode(req));
322
+ }
323
+
324
+ /**
325
+ * @dev Returns the commitment for the given get response
326
+ */
327
+ function hash(GetResponse memory res) internal pure returns (bytes32) {
328
+ bytes memory response = bytes("");
329
+ uint256 len = res.values.length;
330
+ for (uint256 i = 0; i < len; i++) {
331
+ response = bytes.concat(response, bytes.concat(res.values[i].key, res.values[i].value));
332
+ }
333
+ return keccak256(bytes.concat(encode(res.request), response));
334
+ }
335
+ }
@@ -0,0 +1,75 @@
1
+ // Copyright (C) Polytope Labs Ltd.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ pragma solidity ^0.8.17;
15
+
16
+ import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
17
+
18
+ /**
19
+ * @title StateMachine
20
+ * @author Polytope Labs (hello@polytope.technology)
21
+ * @notice Utility library for generating standardized state machine identifiers
22
+ * @dev This library provides helper functions to create consistent identifiers for different
23
+ * blockchain networks and state machines in the Hyperbridge protocol. Each blockchain type
24
+ * has its own identifier format to ensure uniqueness across the ecosystem.
25
+ * These identifiers are used throughout the protocol for routing messages between chains.
26
+ */
27
+ library StateMachine {
28
+ /// @notice The identifier for relay chains (Polkadot/Kusama relay chain)
29
+ /// @dev Used to identify the main relay chain in the Polkadot ecosystem
30
+ uint256 public constant RELAY_CHAIN = 0;
31
+
32
+ /**
33
+ * @notice Generate an identifier for a Polkadot parachain
34
+ * @dev Creates a standardized identifier in the format "POLKADOT-{id}"
35
+ * @param id The parachain ID on the Polkadot network
36
+ * @return The formatted state machine identifier as bytes
37
+ * @custom:example polkadot(1000) returns "POLKADOT-1000"
38
+ */
39
+ function polkadot(uint256 id) internal pure returns (bytes memory) {
40
+ return bytes(string.concat("POLKADOT-", Strings.toString(id)));
41
+ }
42
+
43
+ /**
44
+ * @notice Generate an identifier for a Kusama parachain
45
+ * @dev Creates a standardized identifier in the format "KUSAMA-{id}"
46
+ * @param id The parachain ID on the Kusama network
47
+ * @return The formatted state machine identifier as bytes
48
+ * @custom:example kusama(2000) returns "KUSAMA-2000"
49
+ */
50
+ function kusama(uint256 id) internal pure returns (bytes memory) {
51
+ return bytes(string.concat("KUSAMA-", Strings.toString(id)));
52
+ }
53
+
54
+ /**
55
+ * @notice Generate an identifier for an EVM-compatible chain
56
+ * @dev Creates a standardized identifier in the format "EVM-{chainId}"
57
+ * @param chainid The chain ID of the EVM network (e.g., 1 for Ethereum mainnet)
58
+ * @return The formatted state machine identifier as bytes
59
+ * @custom:example evm(1) returns "EVM-1" for Ethereum mainnet
60
+ */
61
+ function evm(uint256 chainid) internal pure returns (bytes memory) {
62
+ return bytes(string.concat("EVM-", Strings.toString(chainid)));
63
+ }
64
+
65
+ /**
66
+ * @notice Generate an identifier for a Substrate-based chain
67
+ * @dev Creates a standardized identifier in the format "SUBSTRATE-{id}"
68
+ * @param id The 4-byte identifier for the Substrate chain
69
+ * @return The formatted state machine identifier as bytes
70
+ * @custom:example substrate(0x12345678) returns "SUBSTRATE-0x12345678"
71
+ */
72
+ function substrate(bytes4 id) internal pure returns (bytes memory) {
73
+ return bytes(string.concat("SUBSTRATE-", string(abi.encodePacked(id))));
74
+ }
75
+ }
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@hyperbridge/core",
3
+ "version": "1.0.0",
4
+ "description": "Hyperbridge Solidity SDK for dispatching & receiving cross-chain messages",
5
+ "author": "Polytope Labs <hello@polytope.technology>",
6
+ "license": "Apache-2.0",
7
+ "bugs": {
8
+ "url": "https://github.com/polytope-labs/hyperbridge-sdk/issues"
9
+ },
10
+ "homepage": "https://github.com/polytope-labs/hyperbridge-sdk/tree/main/packages/core#readme",
11
+ "directories": {
12
+ "lib": "contracts"
13
+ },
14
+ "files": [
15
+ "./contracts/**/*.sol"
16
+ ],
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/polytope-labs/hyperbridge-sdk.git"
23
+ },
24
+ "keywords": [
25
+ "hyperbridge",
26
+ "ethereum",
27
+ "polkadot",
28
+ "interoperability",
29
+ "cross-chain",
30
+ "bridges"
31
+ ],
32
+ "dependencies": {
33
+ "@polytope-labs/solidity-merkle-trees": "^0.3.3",
34
+ "openzeppelin-solidity": "^4.8.1",
35
+ "prettier": "^3.3.3",
36
+ "prettier-plugin-solidity": "^1.3.1"
37
+ },
38
+ "scripts": {
39
+ "build": "forge build --contracts contracts/ --skip test --skip script",
40
+ "format": "forge fmt contracts/",
41
+ "format:check": "forge fmt --check contracts/"
42
+ }
43
+ }