@rhinestone/shared-configs 1.7.16 → 1.7.17

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.
@@ -6,6 +6,7 @@
6
6
  "decimals": 18,
7
7
  "symbol": "ETH"
8
8
  },
9
+ "network": "mainnet",
9
10
  "settlementLayers": [
10
11
  "ACROSS",
11
12
  "ECO",
@@ -72,6 +73,7 @@
72
73
  "decimals": 18,
73
74
  "symbol": "ETH"
74
75
  },
76
+ "network": "mainnet",
75
77
  "settlementLayers": [
76
78
  "ACROSS",
77
79
  "ECO",
@@ -146,6 +148,7 @@
146
148
  "decimals": 18,
147
149
  "symbol": "BNB"
148
150
  },
151
+ "network": "mainnet",
149
152
  "settlementLayers": [
150
153
  "ACROSS",
151
154
  "ECO",
@@ -200,6 +203,7 @@
200
203
  "decimals": 18,
201
204
  "symbol": "XDAI"
202
205
  },
206
+ "network": "mainnet",
203
207
  "settlementLayers": [
204
208
  "RELAY",
205
209
  "NEAR",
@@ -233,6 +237,7 @@
233
237
  "decimals": 18,
234
238
  "symbol": "ETH"
235
239
  },
240
+ "network": "mainnet",
236
241
  "settlementLayers": [
237
242
  "ACROSS",
238
243
  "ECO",
@@ -298,6 +303,7 @@
298
303
  "decimals": 18,
299
304
  "symbol": "POL"
300
305
  },
306
+ "network": "mainnet",
301
307
  "settlementLayers": [
302
308
  "ACROSS",
303
309
  "ECO",
@@ -356,6 +362,7 @@
356
362
  "decimals": 18,
357
363
  "symbol": "MON"
358
364
  },
365
+ "network": "mainnet",
359
366
  "settlementLayers": [
360
367
  "ACROSS",
361
368
  "RELAY",
@@ -411,6 +418,7 @@
411
418
  "decimals": 18,
412
419
  "symbol": "S"
413
420
  },
421
+ "network": "mainnet",
414
422
  "settlementLayers": [
415
423
  "ECO",
416
424
  "RELAY",
@@ -447,6 +455,7 @@
447
455
  "decimals": 18,
448
456
  "symbol": "HYPE"
449
457
  },
458
+ "network": "mainnet",
450
459
  "settlementLayers": [
451
460
  "ACROSS",
452
461
  "ECO",
@@ -490,6 +499,7 @@
490
499
  "decimals": 18,
491
500
  "symbol": "HYPE"
492
501
  },
502
+ "network": "mainnet",
493
503
  "settlementLayers": [],
494
504
  "swapQuoters": [],
495
505
  "tokens": [
@@ -517,6 +527,7 @@
517
527
  "decimals": 18,
518
528
  "symbol": "ETH"
519
529
  },
530
+ "network": "mainnet",
520
531
  "settlementLayers": [
521
532
  "ACROSS",
522
533
  "RELAY"
@@ -571,6 +582,7 @@
571
582
  "decimals": 18,
572
583
  "symbol": "ETH"
573
584
  },
585
+ "network": "mainnet",
574
586
  "settlementLayers": [
575
587
  "ACROSS",
576
588
  "RELAY"
@@ -620,6 +632,7 @@
620
632
  "decimals": 18,
621
633
  "symbol": "ETH"
622
634
  },
635
+ "network": "mainnet",
623
636
  "settlementLayers": [
624
637
  "ACROSS",
625
638
  "ECO",
@@ -675,6 +688,7 @@
675
688
  "decimals": 18,
676
689
  "symbol": "XPL"
677
690
  },
691
+ "network": "mainnet",
678
692
  "settlementLayers": [
679
693
  "ACROSS",
680
694
  "ECO",
@@ -684,7 +698,8 @@
684
698
  ],
685
699
  "swapQuoterConfig": {},
686
700
  "swapQuoters": [
687
- "0x"
701
+ "0x",
702
+ "fynd"
688
703
  ],
689
704
  "tokens": [
690
705
  {
@@ -711,6 +726,7 @@
711
726
  "decimals": 18,
712
727
  "symbol": "XPL"
713
728
  },
729
+ "network": "testnet",
714
730
  "settlementLayers": [
715
731
  "ECO"
716
732
  ],
@@ -748,6 +764,7 @@
748
764
  "decimals": 18,
749
765
  "symbol": "ETH"
750
766
  },
767
+ "network": "mainnet",
751
768
  "settlementLayers": [
752
769
  "ACROSS",
753
770
  "ECO",
@@ -814,6 +831,7 @@
814
831
  "decimals": 18,
815
832
  "symbol": "AVAX"
816
833
  },
834
+ "network": "mainnet",
817
835
  "settlementLayers": [
818
836
  "ACROSS",
819
837
  "RELAY",
@@ -883,6 +901,7 @@
883
901
  "decimals": 18,
884
902
  "symbol": "ETH"
885
903
  },
904
+ "network": "testnet",
886
905
  "settlementLayers": [
887
906
  "ACROSS",
888
907
  "ECO",
@@ -940,6 +959,7 @@
940
959
  "decimals": 18,
941
960
  "symbol": "ETH"
942
961
  },
962
+ "network": "testnet",
943
963
  "settlementLayers": [
944
964
  "ACROSS",
945
965
  "ECO",
@@ -987,6 +1007,7 @@
987
1007
  "decimals": 18,
988
1008
  "symbol": "ETH"
989
1009
  },
1010
+ "network": "mainnet",
990
1011
  "settlementLayers": [
991
1012
  "RELAY",
992
1013
  "RHINO"
@@ -1043,6 +1064,7 @@
1043
1064
  "decimals": 18,
1044
1065
  "symbol": "ETH"
1045
1066
  },
1067
+ "network": "testnet",
1046
1068
  "settlementLayers": [
1047
1069
  "ACROSS",
1048
1070
  "ECO",
@@ -1090,6 +1112,7 @@
1090
1112
  "decimals": 18,
1091
1113
  "symbol": "ETH"
1092
1114
  },
1115
+ "network": "testnet",
1093
1116
  "settlementLayers": [
1094
1117
  "ACROSS",
1095
1118
  "ECO",
@@ -1138,6 +1161,7 @@
1138
1161
  "decimals": 6,
1139
1162
  "symbol": "TRX"
1140
1163
  },
1164
+ "network": "mainnet",
1141
1165
  "settlementLayers": [
1142
1166
  "RELAY",
1143
1167
  "OFT",
@@ -1177,6 +1201,7 @@
1177
1201
  "decimals": 9,
1178
1202
  "symbol": "SOL"
1179
1203
  },
1204
+ "network": "mainnet",
1180
1205
  "settlementLayers": [
1181
1206
  "RELAY",
1182
1207
  "OFT",
@@ -2,18 +2,74 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const bun_test_1 = require("bun:test");
4
4
  const validation_1 = require("../validation");
5
- (0, bun_test_1.describe)("validateChainConfig", () => {
5
+ const index_1 = require("../../src/index");
6
+ const nativeToken = { address: "0x0", symbol: "ETH", decimals: 18 };
7
+ /** A structurally complete entry, so semantic tests don't trip structural checks. */
8
+ function validChain(overrides = {}) {
9
+ return {
10
+ name: "Ethereum",
11
+ vmType: "evm",
12
+ network: "mainnet",
13
+ nativeToken,
14
+ wrappedNativeToken: { ...nativeToken, symbol: "WETH" },
15
+ tokens: [{ ...nativeToken, balanceSlot: null, approvalSlot: null }],
16
+ settlementLayers: ["ACROSS", "ECO", "RELAY"],
17
+ swapQuoters: ["0x"],
18
+ ...overrides,
19
+ };
20
+ }
21
+ function errorsFor(chain) {
22
+ return (0, validation_1.validateChainConfig)({ "1": chain }).issues.filter((i) => i.severity === "error");
23
+ }
24
+ (0, bun_test_1.describe)("validateChainConfig — structure", () => {
25
+ // The real generated registry is the thing this actually has to accept; if
26
+ // the checks drift stricter than the generator, the build breaks on good data.
27
+ (0, bun_test_1.it)("accepts the real generated chain registry", () => {
28
+ const result = (0, validation_1.validateChainConfig)(index_1.chainRegistry);
29
+ const errors = result.issues.filter((i) => i.severity === "error");
30
+ (0, bun_test_1.expect)(errors).toEqual([]);
31
+ (0, bun_test_1.expect)(result.hasErrors).toBe(false);
32
+ });
33
+ (0, bun_test_1.it)("rejects a key that is not a canonical chain id", () => {
34
+ const result = (0, validation_1.validateChainConfig)({ "01": validChain() });
35
+ (0, bun_test_1.expect)(result.hasErrors).toBe(true);
36
+ (0, bun_test_1.expect)(result.issues[0].message).toContain("canonical chain id");
37
+ });
38
+ bun_test_1.it.each([
39
+ ["a missing name", { name: undefined }],
40
+ ["an unknown vmType", { vmType: "wasm" }],
41
+ ["a non-object nativeToken", { nativeToken: "0x0" }],
42
+ ["a nativeToken missing decimals", { nativeToken: { address: "0x0", symbol: "ETH" } }],
43
+ ["tokens not an array", { tokens: {} }],
44
+ ["a token missing its slots", { tokens: [nativeToken] }],
45
+ ["a token with a bad pegGroup", {
46
+ tokens: [{ ...nativeToken, balanceSlot: null, approvalSlot: null, pegGroup: "GBP" }],
47
+ }],
48
+ ["an unknown settlement layer", { settlementLayers: ["ACROSS", "TELEPORT"] }],
49
+ ["an unknown swap quoter", { swapQuoters: ["mystery-dex"] }],
50
+ ["a malformed swapQuoterConfig", { swapQuoterConfig: { "0x": { slug: 5 } } }],
51
+ ["a swapQuoterConfig for an unknown quoter", { swapQuoterConfig: { nope: {} } }],
52
+ ["a non-boolean virtual flag", { virtual: "true" }],
53
+ ["a missing network", { network: undefined }],
54
+ ["an unknown network", { network: "devnet" }],
55
+ ])("rejects %s", (_label, overrides) => {
56
+ (0, bun_test_1.expect)(errorsFor(validChain(overrides)).length).toBeGreaterThan(0);
57
+ });
58
+ (0, bun_test_1.it)("names the offending value so the build failure is actionable", () => {
59
+ const [error] = errorsFor(validChain({ settlementLayers: ["TELEPORT"] }));
60
+ (0, bun_test_1.expect)(error.message).toContain("TELEPORT");
61
+ (0, bun_test_1.expect)(error.message).toContain("src/types.ts");
62
+ });
63
+ });
64
+ (0, bun_test_1.describe)("validateChainConfig — reachability", () => {
6
65
  (0, bun_test_1.it)("returns no issues for chains with multiple settlement layers", () => {
7
- const chains = {
8
- "1": { name: "Ethereum", settlementLayers: ["ACROSS", "ECO", "RELAY"], tokens: [] },
9
- };
10
- const result = (0, validation_1.validateChainConfig)(chains);
66
+ const result = (0, validation_1.validateChainConfig)({ "1": validChain() });
11
67
  (0, bun_test_1.expect)(result.issues).toHaveLength(0);
12
68
  (0, bun_test_1.expect)(result.hasErrors).toBe(false);
13
69
  });
14
70
  (0, bun_test_1.it)("returns error for chain with zero settlement layers", () => {
15
71
  const chains = {
16
- "100": { name: "Gnosis", settlementLayers: [], tokens: [] },
72
+ "100": validChain({ name: "Gnosis", settlementLayers: [] }),
17
73
  };
18
74
  const result = (0, validation_1.validateChainConfig)(chains);
19
75
  (0, bun_test_1.expect)(result.issues).toHaveLength(1);
@@ -24,7 +80,7 @@ const validation_1 = require("../validation");
24
80
  });
25
81
  (0, bun_test_1.it)("returns warning for chain with single settlement layer", () => {
26
82
  const chains = {
27
- "100": { name: "Gnosis", settlementLayers: ["RELAY"], tokens: [] },
83
+ "100": validChain({ name: "Gnosis", settlementLayers: ["RELAY"] }),
28
84
  };
29
85
  const result = (0, validation_1.validateChainConfig)(chains);
30
86
  (0, bun_test_1.expect)(result.issues).toHaveLength(1);
@@ -32,11 +88,18 @@ const validation_1 = require("../validation");
32
88
  (0, bun_test_1.expect)(result.issues[0].message).toContain("RELAY");
33
89
  (0, bun_test_1.expect)(result.hasErrors).toBe(false);
34
90
  });
91
+ (0, bun_test_1.it)("skips the reachability check for virtual chains", () => {
92
+ const chains = {
93
+ "1337": validChain({ name: "HyperCore", virtual: true, settlementLayers: [] }),
94
+ };
95
+ const result = (0, validation_1.validateChainConfig)(chains);
96
+ (0, bun_test_1.expect)(result.issues).toHaveLength(0);
97
+ });
35
98
  (0, bun_test_1.it)("handles mixed chains correctly", () => {
36
99
  const chains = {
37
- "1": { name: "Ethereum", settlementLayers: ["ACROSS", "ECO", "RELAY"], tokens: [] },
38
- "100": { name: "Gnosis", settlementLayers: ["RELAY"], tokens: [] },
39
- "999": { name: "Broken", settlementLayers: [], tokens: [] },
100
+ "1": validChain(),
101
+ "100": validChain({ name: "Gnosis", settlementLayers: ["RELAY"] }),
102
+ "999": validChain({ name: "Broken", settlementLayers: [] }),
40
103
  };
41
104
  const result = (0, validation_1.validateChainConfig)(chains);
42
105
  (0, bun_test_1.expect)(result.issues).toHaveLength(2);
@@ -91,3 +154,62 @@ const validation_1 = require("../validation");
91
154
  (0, bun_test_1.expect)(output).toContain("Gnosis (100)");
92
155
  });
93
156
  });
157
+ (0, bun_test_1.describe)("classifyChainNetworks", () => {
158
+ const providers = { providers: ["DRPC"] };
159
+ (0, bun_test_1.it)("stamps the network from whichever map holds the chain id", () => {
160
+ const { chains, issues } = (0, validation_1.classifyChainNetworks)({ "1": validChain(), "11155111": validChain({ name: "Sepolia" }) }, { "1": providers }, { "11155111": providers });
161
+ (0, bun_test_1.expect)(chains["1"].network).toBe("mainnet");
162
+ (0, bun_test_1.expect)(chains["11155111"].network).toBe("testnet");
163
+ (0, bun_test_1.expect)(issues).toEqual([]);
164
+ });
165
+ (0, bun_test_1.it)("overwrites any network the jsonnet happens to carry, so the maps stay the one source", () => {
166
+ const { chains } = (0, validation_1.classifyChainNetworks)({ "1": validChain({ network: "testnet" }) }, { "1": providers }, {});
167
+ (0, bun_test_1.expect)(chains["1"].network).toBe("mainnet");
168
+ });
169
+ // The silent-miss case this guard exists for: an unclassified chain would
170
+ // otherwise reach the signed artifact with no way for a consumer to place it.
171
+ (0, bun_test_1.it)("errors when a chain is in neither network map", () => {
172
+ const { chains, issues } = (0, validation_1.classifyChainNetworks)({ "1": validChain() }, {}, {});
173
+ (0, bun_test_1.expect)(issues).toHaveLength(1);
174
+ (0, bun_test_1.expect)(issues[0].severity).toBe("error");
175
+ (0, bun_test_1.expect)(issues[0].chainId).toBe("1");
176
+ (0, bun_test_1.expect)(issues[0].message).toContain("neither");
177
+ (0, bun_test_1.expect)(chains["1"].network).toBeUndefined();
178
+ });
179
+ (0, bun_test_1.it)("errors when a chain is in both network maps", () => {
180
+ const { issues } = (0, validation_1.classifyChainNetworks)({ "1": validChain() }, { "1": providers }, { "1": providers });
181
+ (0, bun_test_1.expect)(issues).toHaveLength(1);
182
+ (0, bun_test_1.expect)(issues[0].severity).toBe("error");
183
+ (0, bun_test_1.expect)(issues[0].message).toContain("both");
184
+ });
185
+ (0, bun_test_1.it)("warns when a network map lists a chain the registry does not define", () => {
186
+ const { issues } = (0, validation_1.classifyChainNetworks)({ "1": validChain() }, { "1": providers, "999999": providers }, {});
187
+ (0, bun_test_1.expect)(issues).toHaveLength(1);
188
+ (0, bun_test_1.expect)(issues[0].severity).toBe("warning");
189
+ (0, bun_test_1.expect)(issues[0].chainId).toBe("999999");
190
+ (0, bun_test_1.expect)(issues[0].message).toContain("absent from the chain registry");
191
+ });
192
+ // The artifact is signed over these exact bytes, so the serialisation has to
193
+ // stay canonical rather than depending on where the field was spliced in.
194
+ (0, bun_test_1.it)("keeps entry keys sorted so the generated JSON stays canonical", () => {
195
+ const { chains } = (0, validation_1.classifyChainNetworks)({ "1": validChain() }, { "1": providers }, {});
196
+ const keys = Object.keys(chains["1"]);
197
+ (0, bun_test_1.expect)(keys).toEqual([...keys].sort());
198
+ (0, bun_test_1.expect)(keys).toContain("network");
199
+ });
200
+ (0, bun_test_1.it)("classifies the real registry with no issues", () => {
201
+ // Round-trips the shipped registry through its own maps: every real chain
202
+ // must land in exactly one, which is what makes the field derivable at all.
203
+ const mainnets = Object.fromEntries(Object.entries(index_1.chainRegistry)
204
+ .filter(([, c]) => c.network === "mainnet")
205
+ .map(([id]) => [id, providers]));
206
+ const testnets = Object.fromEntries(Object.entries(index_1.chainRegistry)
207
+ .filter(([, c]) => c.network === "testnet")
208
+ .map(([id]) => [id, providers]));
209
+ const { chains, issues } = (0, validation_1.classifyChainNetworks)(index_1.chainRegistry, mainnets, testnets);
210
+ (0, bun_test_1.expect)(issues).toEqual([]);
211
+ (0, bun_test_1.expect)(Object.keys(mainnets).length).toBeGreaterThan(0);
212
+ (0, bun_test_1.expect)(Object.keys(testnets).length).toBeGreaterThan(0);
213
+ (0, bun_test_1.expect)(Object.keys(chains)).toHaveLength(Object.keys(index_1.chainRegistry).length);
214
+ });
215
+ });
@@ -88,7 +88,7 @@ function renderChains(chainRegistry, mainnets, testnets) {
88
88
  }
89
89
  return [
90
90
  "// Auto-generated by scripts/generate.ts. Do not edit manually.",
91
- 'import type { PegGroup, ProviderName, SettlementLayer, SupportedChain, SwapQuoter, SwapQuoterConfig, VmType } from "./types";',
91
+ 'import type { ChainNetwork, PegGroup, ProviderName, SettlementLayer, SupportedChain, SwapQuoter, SwapQuoterConfig, VmType } from "./types";',
92
92
  "",
93
93
  "interface Token {",
94
94
  " /** EVM: 0x-prefixed hex. SVM: base58 SPL mint. TVM: base58 (T-prefixed). */",
@@ -112,6 +112,8 @@ function renderChains(chainRegistry, mainnets, testnets) {
112
112
  "interface Chain {",
113
113
  " name: string;",
114
114
  " vmType: VmType;",
115
+ " /** Whether this chain is a mainnet or a testnet. */",
116
+ " network: ChainNetwork;",
115
117
  " /** CAIP-2 chain identifier; populated for non-eip155 chains only. */",
116
118
  " caip2?: string;",
117
119
  " /** True for virtual chains (e.g. HyperCore) that settle on another chain. */",
@@ -354,14 +356,26 @@ async function generate() {
354
356
  const output = runJsonnet(yeetRoot);
355
357
  await (0, promises_1.mkdir)(configsDir, { recursive: true });
356
358
  await (0, promises_1.mkdir)(generatedDir, { recursive: true });
357
- await (0, promises_1.writeFile)(node_path_1.default.join(configsDir, "chains.json"), `${JSON.stringify(output.chains, null, 2)}\n`);
359
+ // Stamp mainnet/testnet onto each entry before anything is written, so the
360
+ // registry that reaches configs/chains.json — and from there the published
361
+ // facts artifact and the read-client's bundled fallback — carries the
362
+ // classification rather than leaving it implicit in the network maps.
363
+ const { chains: classifiedChains, issues: classificationIssues } = (0, validation_1.classifyChainNetworks)(output.chains, output.mainnets, output.testnets);
364
+ await (0, promises_1.writeFile)(node_path_1.default.join(configsDir, "chains.json"), `${JSON.stringify(classifiedChains, null, 2)}\n`);
358
365
  await (0, promises_1.writeFile)(node_path_1.default.join(configsDir, "mainnets.json"), `${JSON.stringify(output.mainnets, null, 2)}\n`);
359
366
  await (0, promises_1.writeFile)(node_path_1.default.join(configsDir, "testnets.json"), `${JSON.stringify(output.testnets, null, 2)}\n`);
360
367
  await (0, promises_1.writeFile)(node_path_1.default.join(configsDir, "providers.json"), `${JSON.stringify(output.providers, null, 2)}\n`);
361
368
  await (0, promises_1.writeFile)(node_path_1.default.join(configsDir, "oft.json"), `${JSON.stringify(output.oft, null, 2)}\n`);
362
369
  await (0, promises_1.writeFile)(node_path_1.default.join(configsDir, "oft-programs.json"), `${JSON.stringify(output.oftProgramIds ?? {}, null, 2)}\n`);
363
- // Validate chain configuration
364
- const validationResult = (0, validation_1.validateChainConfig)(output.chains);
370
+ // Validate chain configuration. Classification problems are reported in the
371
+ // same pass so one run surfaces everything wrong with the registry, rather than
372
+ // failing on the partition and hiding the rest.
373
+ const structural = (0, validation_1.validateChainConfig)(classifiedChains);
374
+ const validationResult = {
375
+ issues: [...classificationIssues, ...structural.issues],
376
+ hasErrors: structural.hasErrors ||
377
+ classificationIssues.some((issue) => issue.severity === 'error'),
378
+ };
365
379
  const validationOutput = (0, validation_1.formatValidationIssues)(validationResult);
366
380
  if (validationOutput) {
367
381
  console.log('\nChain config validation:');
@@ -371,7 +385,13 @@ async function generate() {
371
385
  if (validationResult.hasErrors) {
372
386
  throw new Error('Chain configuration has errors — see above');
373
387
  }
374
- await (0, promises_1.writeFile)(node_path_1.default.join(sharedConfigsRoot, "src", "chains.ts"), `${renderChains(output.chains, output.mainnets, output.testnets)}\n`);
388
+ await (0, promises_1.writeFile)(node_path_1.default.join(sharedConfigsRoot, "src", "chains.ts"), `${renderChains(classifiedChains, output.mainnets, output.testnets)}\n`);
389
+ // Stamp the package version so the read-client knows how fresh its BUNDLED
390
+ // registry is, and can refuse a remote artifact from an older release. The
391
+ // release workflow bumps package.json before building for exactly this
392
+ // reason — see shared-configs-publish.yml.
393
+ const packageVersion = JSON.parse(await (0, promises_1.readFile)(node_path_1.default.join(sharedConfigsRoot, "package.json"), "utf8")).version;
394
+ await (0, promises_1.writeFile)(node_path_1.default.join(generatedDir, "packageVersion.ts"), `// Auto-generated by scripts/generate.ts. Do not edit manually.\nconst PACKAGE_VERSION = "${packageVersion}";\n\nexport { PACKAGE_VERSION };\n`);
375
395
  await (0, promises_1.writeFile)(node_path_1.default.join(generatedDir, "networks.ts"), `${renderNetworks(output.networks)}\n`);
376
396
  const prodAddrConfig = runOrchestratorFile(yeetRoot, "prod", output.chainNames);
377
397
  const stagingAddrConfig = runOrchestratorFile(yeetRoot, "staging", output.chainNames);
@@ -1,4 +1,5 @@
1
- export type SettlementLayer = 'ACROSS' | 'ECO' | 'RELAY' | 'OFT';
1
+ export type SettlementLayer = 'ACROSS' | 'ECO' | 'RELAY' | 'OFT' | 'NEAR' | 'RHINO' | 'CCTP';
2
+ export type ChainNetwork = 'mainnet' | 'testnet';
2
3
  export interface ChainData {
3
4
  name: string;
4
5
  settlementLayers: SettlementLayer[];
@@ -6,6 +7,9 @@ export interface ChainData {
6
7
  symbol: string;
7
8
  [key: string]: unknown;
8
9
  }>;
10
+ /** Whether this chain is a mainnet or a testnet. Stamped by
11
+ * `classifyChainNetworks`, not authored in the jsonnet. */
12
+ network?: ChainNetwork;
9
13
  /** Virtual chains (e.g. HyperCore) settle on another chain and have no
10
14
  * direct settlement layers of their own — excluded from reachability checks. */
11
15
  virtual?: boolean;
@@ -24,9 +28,35 @@ export interface ValidationResult {
24
28
  hasErrors: boolean;
25
29
  }
26
30
  /**
27
- * Validates a chain registry for configuration problems.
31
+ * Stamps every chain with its mainnet/testnet classification, derived from which
32
+ * network map its chain id appears in.
33
+ *
34
+ * Why this exists: the split is otherwise implicit in *which file* an id lands in
35
+ * (configs/mainnets.json vs configs/testnets.json). The package surfaces it as
36
+ * `mainnetChains` / `MainnetNetwork`, but configs/chains.json — the registry the
37
+ * facts artifact publishes and the read-client bundles — carried no trace of it.
38
+ * So a consumer reading facts at runtime could not tell which environment a chain
39
+ * belonged to, which is exactly what the orchestrator's mainnet/testnet registry
40
+ * gating keys off: a CDN-added chain would arrive unclassifiable.
41
+ *
42
+ * Derived rather than authored per chain in the jsonnet, so it cannot drift from
43
+ * the membership it describes — "is this a testnet" keeps one source, the network
44
+ * maps.
45
+ *
46
+ * Lives in this module rather than generate.ts because the partition it relies on
47
+ * is a build-time invariant that has to fail the build, and generate.ts runs its
48
+ * generator on import, so nothing declared there is testable.
49
+ */
50
+ export declare function classifyChainNetworks(chains: ChainRegistry, mainnets: Record<string, unknown>, testnets: Record<string, unknown>): {
51
+ chains: ChainRegistry;
52
+ issues: ValidationIssue[];
53
+ };
54
+ /**
55
+ * Validates a chain registry for structural and configuration problems.
28
56
  *
29
57
  * Checks performed:
58
+ * - Structure: chain-id keys, and every field of every entry against the
59
+ * shapes and unions declared in src/types.ts (error)
30
60
  * - Orphaned chains: chains with no settlement layers (error)
31
61
  * - Single-layer fragility: chains with exactly one settlement layer (warning)
32
62
  */
@@ -1 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../scripts/validation.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,KAAK,GAAG,OAAO,GAAG,KAAK,CAAC;AAEjE,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,MAAM,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,CAAC;IAC1D;oFACgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAEtD,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,SAAS,CAAC;AAErD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,gBAAgB,CAkC3E;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAWvE"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../scripts/validation.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GACvB,QAAQ,GACR,KAAK,GACL,OAAO,GACP,KAAK,GACL,MAAM,GACN,OAAO,GACP,MAAM,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,CAAC;AAEjD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,MAAM,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,CAAC;IAC1D;+DAC2D;IAC3D,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB;oFACgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAqJD,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAEtD,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,SAAS,CAAC;AAErD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;CACpB;AAiBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,eAAe,EAAE,CAAA;CAAE,CAwEtD;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,gBAAgB,CAiE3E;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAWvE"}