@rhinestone/shared-configs 2.6.0 → 2.8.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,301 @@
1
+ {
2
+ "1": {
3
+ "finality": "probabilistic",
4
+ "finality_poll_interval_ms": 30000,
5
+ "finality_source": "finalized",
6
+ "grace_ms": 60000,
7
+ "max_catchup_blocks": 5000,
8
+ "parse_concurrency": 4,
9
+ "poll_interval_ms": 3000,
10
+ "reorg_window_k": 32,
11
+ "reverify_delay_ms": 500,
12
+ "scan_batch_max_blocks": 200,
13
+ "streaming_poll_interval_ms": 15000
14
+ },
15
+ "10": {
16
+ "finality": "sequencer",
17
+ "finality_poll_interval_ms": 15000,
18
+ "finality_source": "finalized",
19
+ "grace_ms": 30000,
20
+ "max_catchup_blocks": 5000,
21
+ "parse_concurrency": 4,
22
+ "poll_interval_ms": 1000,
23
+ "reorg_window_k": 16,
24
+ "reverify_delay_ms": 500,
25
+ "scan_batch_max_blocks": 200,
26
+ "streaming_poll_interval_ms": 15000
27
+ },
28
+ "56": {
29
+ "finality": "probabilistic",
30
+ "finality_poll_interval_ms": 15000,
31
+ "finality_source": "finalized",
32
+ "grace_ms": 30000,
33
+ "max_catchup_blocks": 5000,
34
+ "parse_concurrency": 8,
35
+ "poll_interval_ms": 1000,
36
+ "reorg_window_k": 32,
37
+ "reverify_delay_ms": 500,
38
+ "scan_batch_max_blocks": 200,
39
+ "streaming_poll_interval_ms": 15000
40
+ },
41
+ "100": {
42
+ "finality": "probabilistic",
43
+ "finality_poll_interval_ms": 30000,
44
+ "finality_source": "finalized",
45
+ "grace_ms": 60000,
46
+ "max_catchup_blocks": 5000,
47
+ "parse_concurrency": 4,
48
+ "poll_interval_ms": 2000,
49
+ "reorg_window_k": 32,
50
+ "reverify_delay_ms": 500,
51
+ "scan_batch_max_blocks": 200,
52
+ "streaming_poll_interval_ms": 15000
53
+ },
54
+ "130": {
55
+ "finality": "sequencer",
56
+ "finality_poll_interval_ms": 15000,
57
+ "finality_source": "finalized",
58
+ "grace_ms": 30000,
59
+ "max_catchup_blocks": 5000,
60
+ "parse_concurrency": 8,
61
+ "poll_interval_ms": 1000,
62
+ "reorg_window_k": 16,
63
+ "reverify_delay_ms": 500,
64
+ "scan_batch_max_blocks": 200,
65
+ "streaming_poll_interval_ms": 15000
66
+ },
67
+ "137": {
68
+ "finality": "probabilistic",
69
+ "finality_poll_interval_ms": 15000,
70
+ "finality_source": "finalized",
71
+ "grace_ms": 30000,
72
+ "max_catchup_blocks": 5000,
73
+ "parse_concurrency": 4,
74
+ "poll_interval_ms": 1000,
75
+ "reorg_window_k": 64,
76
+ "reverify_delay_ms": 500,
77
+ "scan_batch_max_blocks": 200,
78
+ "streaming_poll_interval_ms": 15000
79
+ },
80
+ "143": {
81
+ "finality": "instant",
82
+ "finality_poll_interval_ms": 0,
83
+ "finality_source": "instant",
84
+ "grace_ms": 0,
85
+ "max_catchup_blocks": 5000,
86
+ "parse_concurrency": 8,
87
+ "poll_interval_ms": 1000,
88
+ "reorg_window_k": 4,
89
+ "reverify_delay_ms": 0,
90
+ "scan_batch_max_blocks": 200,
91
+ "streaming_poll_interval_ms": 15000
92
+ },
93
+ "146": {
94
+ "finality": "instant",
95
+ "finality_poll_interval_ms": 0,
96
+ "finality_source": "instant",
97
+ "grace_ms": 0,
98
+ "max_catchup_blocks": 5000,
99
+ "parse_concurrency": 8,
100
+ "poll_interval_ms": 1000,
101
+ "reorg_window_k": 4,
102
+ "reverify_delay_ms": 0,
103
+ "scan_batch_max_blocks": 200,
104
+ "streaming_poll_interval_ms": 15000
105
+ },
106
+ "196": {
107
+ "finality": "sequencer",
108
+ "finality_poll_interval_ms": 15000,
109
+ "finality_source": "finalized",
110
+ "grace_ms": 30000,
111
+ "max_catchup_blocks": 5000,
112
+ "parse_concurrency": 4,
113
+ "poll_interval_ms": 1000,
114
+ "reorg_window_k": 16,
115
+ "reverify_delay_ms": 500,
116
+ "scan_batch_max_blocks": 200,
117
+ "streaming_poll_interval_ms": 15000
118
+ },
119
+ "999": {
120
+ "finality": "instant",
121
+ "finality_poll_interval_ms": 0,
122
+ "finality_source": "instant",
123
+ "grace_ms": 0,
124
+ "max_catchup_blocks": 5000,
125
+ "parse_concurrency": 8,
126
+ "poll_interval_ms": 1000,
127
+ "reorg_window_k": 4,
128
+ "reverify_delay_ms": 0,
129
+ "scan_batch_max_blocks": 200,
130
+ "streaming_poll_interval_ms": 15000
131
+ },
132
+ "1868": {
133
+ "finality": "sequencer",
134
+ "finality_poll_interval_ms": 15000,
135
+ "finality_source": "finalized",
136
+ "grace_ms": 30000,
137
+ "max_catchup_blocks": 5000,
138
+ "parse_concurrency": 4,
139
+ "poll_interval_ms": 1000,
140
+ "reorg_window_k": 16,
141
+ "reverify_delay_ms": 500,
142
+ "scan_batch_max_blocks": 200,
143
+ "streaming_poll_interval_ms": 15000
144
+ },
145
+ "4663": {
146
+ "finality": "sequencer",
147
+ "finality_poll_interval_ms": 15000,
148
+ "finality_source": "finalized",
149
+ "grace_ms": 30000,
150
+ "max_catchup_blocks": 5000,
151
+ "parse_concurrency": 4,
152
+ "poll_interval_ms": 1000,
153
+ "reorg_window_k": 16,
154
+ "reverify_delay_ms": 500,
155
+ "scan_batch_max_blocks": 200,
156
+ "streaming_poll_interval_ms": 15000
157
+ },
158
+ "8453": {
159
+ "finality": "sequencer",
160
+ "finality_poll_interval_ms": 15000,
161
+ "finality_source": "finalized",
162
+ "grace_ms": 30000,
163
+ "max_catchup_blocks": 5000,
164
+ "parse_concurrency": 8,
165
+ "poll_interval_ms": 1000,
166
+ "reorg_window_k": 16,
167
+ "reverify_delay_ms": 500,
168
+ "scan_batch_max_blocks": 200,
169
+ "streaming_poll_interval_ms": 15000
170
+ },
171
+ "9745": {
172
+ "finality": "instant",
173
+ "finality_poll_interval_ms": 0,
174
+ "finality_source": "instant",
175
+ "grace_ms": 0,
176
+ "max_catchup_blocks": 5000,
177
+ "parse_concurrency": 8,
178
+ "poll_interval_ms": 1000,
179
+ "reorg_window_k": 4,
180
+ "reverify_delay_ms": 0,
181
+ "scan_batch_max_blocks": 200,
182
+ "streaming_poll_interval_ms": 15000
183
+ },
184
+ "9746": {
185
+ "finality": "instant",
186
+ "finality_poll_interval_ms": 0,
187
+ "finality_source": "instant",
188
+ "grace_ms": 0,
189
+ "max_catchup_blocks": 5000,
190
+ "parse_concurrency": 4,
191
+ "poll_interval_ms": 1000,
192
+ "reorg_window_k": 4,
193
+ "reverify_delay_ms": 0,
194
+ "scan_batch_max_blocks": 200,
195
+ "streaming_poll_interval_ms": 5000
196
+ },
197
+ "42161": {
198
+ "finality": "sequencer",
199
+ "finality_poll_interval_ms": 15000,
200
+ "finality_source": "finalized",
201
+ "grace_ms": 30000,
202
+ "max_catchup_blocks": 5000,
203
+ "parse_concurrency": 8,
204
+ "poll_interval_ms": 1000,
205
+ "reorg_window_k": 16,
206
+ "reverify_delay_ms": 500,
207
+ "scan_batch_max_blocks": 200,
208
+ "streaming_poll_interval_ms": 15000
209
+ },
210
+ "43114": {
211
+ "finality": "instant",
212
+ "finality_poll_interval_ms": 0,
213
+ "finality_source": "instant",
214
+ "grace_ms": 0,
215
+ "max_catchup_blocks": 5000,
216
+ "parse_concurrency": 4,
217
+ "poll_interval_ms": 1000,
218
+ "reorg_window_k": 4,
219
+ "reverify_delay_ms": 0,
220
+ "scan_batch_max_blocks": 200,
221
+ "streaming_poll_interval_ms": 15000
222
+ },
223
+ "57073": {
224
+ "finality": "sequencer",
225
+ "finality_poll_interval_ms": 15000,
226
+ "finality_source": "finalized",
227
+ "grace_ms": 30000,
228
+ "max_catchup_blocks": 5000,
229
+ "parse_concurrency": 4,
230
+ "poll_interval_ms": 1000,
231
+ "reorg_window_k": 16,
232
+ "reverify_delay_ms": 500,
233
+ "scan_batch_max_blocks": 200,
234
+ "streaming_poll_interval_ms": 15000
235
+ },
236
+ "84532": {
237
+ "finality": "sequencer",
238
+ "finality_poll_interval_ms": 15000,
239
+ "finality_source": "finalized",
240
+ "grace_ms": 30000,
241
+ "max_catchup_blocks": 5000,
242
+ "parse_concurrency": 4,
243
+ "poll_interval_ms": 1000,
244
+ "reorg_window_k": 8,
245
+ "reverify_delay_ms": 500,
246
+ "scan_batch_max_blocks": 200,
247
+ "streaming_poll_interval_ms": 5000
248
+ },
249
+ "421614": {
250
+ "finality": "sequencer",
251
+ "finality_poll_interval_ms": 15000,
252
+ "finality_source": "finalized",
253
+ "grace_ms": 30000,
254
+ "max_catchup_blocks": 5000,
255
+ "parse_concurrency": 4,
256
+ "poll_interval_ms": 1000,
257
+ "reorg_window_k": 8,
258
+ "reverify_delay_ms": 500,
259
+ "scan_batch_max_blocks": 200,
260
+ "streaming_poll_interval_ms": 5000
261
+ },
262
+ "747474": {
263
+ "finality": "sequencer",
264
+ "finality_poll_interval_ms": 15000,
265
+ "finality_source": "finalized",
266
+ "grace_ms": 30000,
267
+ "max_catchup_blocks": 5000,
268
+ "parse_concurrency": 4,
269
+ "poll_interval_ms": 1000,
270
+ "reorg_window_k": 16,
271
+ "reverify_delay_ms": 500,
272
+ "scan_batch_max_blocks": 200,
273
+ "streaming_poll_interval_ms": 15000
274
+ },
275
+ "11155111": {
276
+ "finality": "probabilistic",
277
+ "finality_poll_interval_ms": 30000,
278
+ "finality_source": "finalized",
279
+ "grace_ms": 60000,
280
+ "max_catchup_blocks": 5000,
281
+ "parse_concurrency": 4,
282
+ "poll_interval_ms": 3000,
283
+ "reorg_window_k": 32,
284
+ "reverify_delay_ms": 500,
285
+ "scan_batch_max_blocks": 200,
286
+ "streaming_poll_interval_ms": 5000
287
+ },
288
+ "11155420": {
289
+ "finality": "sequencer",
290
+ "finality_poll_interval_ms": 15000,
291
+ "finality_source": "finalized",
292
+ "grace_ms": 30000,
293
+ "max_catchup_blocks": 5000,
294
+ "parse_concurrency": 4,
295
+ "poll_interval_ms": 1000,
296
+ "reorg_window_k": 8,
297
+ "reverify_delay_ms": 500,
298
+ "scan_batch_max_blocks": 200,
299
+ "streaming_poll_interval_ms": 5000
300
+ }
301
+ }
@@ -8,6 +8,7 @@ const viem_1 = require("viem");
8
8
  const validation_1 = require("../validation");
9
9
  const index_1 = require("../../src/index");
10
10
  const oft_json_1 = __importDefault(require("../../configs/oft.json"));
11
+ const chain_indexer_json_1 = __importDefault(require("../../configs/chain-indexer.json"));
11
12
  const nativeToken = { address: "0x0", symbol: "ETH", decimals: 18 };
12
13
  const usdcAddress = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
13
14
  const validAuthorization = {
@@ -497,6 +498,132 @@ function errorsFor(chain) {
497
498
  (0, bun_test_1.expect)((0, validation_1.validateOftCoverage)({}, { USDT0: { adapters: { "1": "0xa" } } })).toEqual([]);
498
499
  });
499
500
  });
501
+ /** A complete class-B entry, so semantic tests don't trip the shape checks. */
502
+ function validIndexerEntry(overrides = {}) {
503
+ return {
504
+ poll_interval_ms: 1000,
505
+ streaming_poll_interval_ms: 15000,
506
+ reorg_window_k: 16,
507
+ reverify_delay_ms: 500,
508
+ max_catchup_blocks: 5000,
509
+ parse_concurrency: 4,
510
+ scan_batch_max_blocks: 200,
511
+ finality: "sequencer",
512
+ finality_source: "finalized",
513
+ finality_poll_interval_ms: 15000,
514
+ grace_ms: 30000,
515
+ ...overrides,
516
+ };
517
+ }
518
+ (0, bun_test_1.describe)("validateChainIndexerCoverage", () => {
519
+ // What actually reaches the artifact: the shipped registry and the shipped
520
+ // settings must agree, or the release pipeline breaks on good data.
521
+ (0, bun_test_1.it)("classifies every real EVM chain", () => {
522
+ (0, bun_test_1.expect)((0, validation_1.validateChainIndexerCoverage)(index_1.chainRegistry, chain_indexer_json_1.default)).toEqual([]);
523
+ });
524
+ (0, bun_test_1.it)("reports an EVM chain with no entry", () => {
525
+ const issues = (0, validation_1.validateChainIndexerCoverage)({ "1": validChain() }, {});
526
+ (0, bun_test_1.expect)(issues).toHaveLength(1);
527
+ (0, bun_test_1.expect)(issues[0].message).toContain("no chain-indexer entry");
528
+ });
529
+ (0, bun_test_1.it)("reports an entry addressing no real EVM chain", () => {
530
+ const issues = (0, validation_1.validateChainIndexerCoverage)({}, {
531
+ "1": validIndexerEntry(),
532
+ });
533
+ (0, bun_test_1.expect)(issues).toHaveLength(1);
534
+ (0, bun_test_1.expect)(issues[0].message).toContain("no real EVM chain");
535
+ });
536
+ // HyperCore is vmType "evm" with a hypercore: caip2 — the eip155 namespace,
537
+ // not vmType, decides whether the indexer dials a chain.
538
+ (0, bun_test_1.it)("requires nothing of a virtual or non-eip155 chain", () => {
539
+ const chains = {
540
+ "1337001": validChain({ caip2: "hypercore:spot", virtual: true }),
541
+ "728126428": validChain({ vmType: "tvm", caip2: "tron:mainnet" }),
542
+ };
543
+ (0, bun_test_1.expect)((0, validation_1.validateChainIndexerCoverage)(chains, {})).toEqual([]);
544
+ });
545
+ (0, bun_test_1.it)("rejects a non-object entry", () => {
546
+ const issues = (0, validation_1.validateChainIndexerCoverage)({ "1": validChain() }, {
547
+ "1": 42,
548
+ });
549
+ (0, bun_test_1.expect)(issues).toHaveLength(1);
550
+ (0, bun_test_1.expect)(issues[0].message).toContain("not an object");
551
+ });
552
+ bun_test_1.it.each([
553
+ [
554
+ "a missing field",
555
+ { poll_interval_ms: undefined },
556
+ "missing `poll_interval_ms`",
557
+ ],
558
+ [
559
+ "a non-integer value",
560
+ { reorg_window_k: "16" },
561
+ "`reorg_window_k` = \"16\" is not a legal value",
562
+ ],
563
+ [
564
+ "an unknown finality class",
565
+ { finality: "optimistic" },
566
+ "`finality` = \"optimistic\" is not a legal value",
567
+ ],
568
+ [
569
+ "an unrecognized field",
570
+ { pol_interval_ms: 1000 },
571
+ "unrecognized field `pol_interval_ms`",
572
+ ],
573
+ [
574
+ "instant finality with a real finality source",
575
+ { finality: "instant" },
576
+ "instant chains take neither",
577
+ ],
578
+ [
579
+ "an instant source that still polls",
580
+ {
581
+ finality: "instant",
582
+ finality_source: "instant",
583
+ finality_poll_interval_ms: 15000,
584
+ },
585
+ "does not match finality_source",
586
+ ],
587
+ [
588
+ "a streaming poll below the base poll",
589
+ { streaming_poll_interval_ms: 500 },
590
+ "never a speedup",
591
+ ],
592
+ ])("rejects %s", (_label, overrides, expected) => {
593
+ const issues = (0, validation_1.validateChainIndexerCoverage)({ "1": validChain() }, {
594
+ "1": validIndexerEntry(overrides),
595
+ });
596
+ (0, bun_test_1.expect)(issues.map((i) => i.message).join("\n")).toContain(expected);
597
+ });
598
+ (0, bun_test_1.it)("accepts { indexed: false } as a complete entry", () => {
599
+ (0, bun_test_1.expect)((0, validation_1.validateChainIndexerCoverage)({ "1": validChain() }, {
600
+ "1": { indexed: false },
601
+ })).toEqual([]);
602
+ });
603
+ (0, bun_test_1.it)("rejects indexed: false carrying scan settings", () => {
604
+ const issues = (0, validation_1.validateChainIndexerCoverage)({ "1": validChain() }, {
605
+ "1": { indexed: false, poll_interval_ms: 1000 },
606
+ });
607
+ (0, bun_test_1.expect)(issues.map((i) => i.message).join("\n")).toContain("an opt-out is the whole entry");
608
+ });
609
+ (0, bun_test_1.it)("rejects indexed: true", () => {
610
+ const issues = (0, validation_1.validateChainIndexerCoverage)({ "1": validChain() }, {
611
+ "1": validIndexerEntry({ indexed: true }),
612
+ });
613
+ (0, bun_test_1.expect)(issues.map((i) => i.message).join("\n")).toContain("the only legal value is false");
614
+ });
615
+ (0, bun_test_1.it)("accepts a coherent instant-class entry", () => {
616
+ const entry = validIndexerEntry({
617
+ finality: "instant",
618
+ finality_source: "instant",
619
+ finality_poll_interval_ms: 0,
620
+ reverify_delay_ms: 0,
621
+ grace_ms: 0,
622
+ reorg_window_k: 4,
623
+ });
624
+ (0, bun_test_1.expect)((0, validation_1.validateChainIndexerCoverage)({ "1": validChain() }, { "1": entry })).toEqual([]);
625
+ });
626
+ });
500
627
  (0, bun_test_1.describe)("formatValidationIssues", () => {
501
628
  (0, bun_test_1.it)("returns empty string for no issues", () => {
502
629
  (0, bun_test_1.expect)((0, validation_1.formatValidationIssues)({ issues: [], hasErrors: false })).toBe("");
@@ -434,6 +434,11 @@ async function generate() {
434
434
  // and reads its addresses back out of the OFT registry, so only an adapter
435
435
  // added there without the matching chain entry can drift.
436
436
  const oftCoverageIssues = (0, validation_1.validateOftCoverage)(classifiedChains, output.oft);
437
+ // Chain-indexer settings are authored, not derived (config/chain-indexer.jsonnet),
438
+ // and the indexer hard-fails on an unclassified chain — so an EVM chain added
439
+ // without an entry fails this build instead of the indexer's boot. Needs the
440
+ // stamped caip2, hence after the classifiers.
441
+ const chainIndexerIssues = (0, validation_1.validateChainIndexerCoverage)(classifiedChains, output.chainIndexer);
437
442
  const classificationIssues = [
438
443
  ...networkIssues,
439
444
  ...stackIssues,
@@ -442,6 +447,7 @@ async function generate() {
442
447
  ...publicRpcUrlIssues,
443
448
  ...iconSlugIssues,
444
449
  ...oftCoverageIssues,
450
+ ...chainIndexerIssues,
445
451
  ];
446
452
  await (0, promises_1.writeFile)(node_path_1.default.join(configsDir, "chains.json"), `${JSON.stringify(classifiedChains, null, 2)}\n`);
447
453
  await (0, promises_1.writeFile)(node_path_1.default.join(configsDir, "mainnets.json"), `${JSON.stringify(output.mainnets, null, 2)}\n`);
@@ -449,6 +455,7 @@ async function generate() {
449
455
  await (0, promises_1.writeFile)(node_path_1.default.join(configsDir, "providers.json"), `${JSON.stringify(output.providers, null, 2)}\n`);
450
456
  await (0, promises_1.writeFile)(node_path_1.default.join(configsDir, "oft.json"), `${JSON.stringify(output.oft, null, 2)}\n`);
451
457
  await (0, promises_1.writeFile)(node_path_1.default.join(configsDir, "oft-programs.json"), `${JSON.stringify(output.oftProgramIds ?? {}, null, 2)}\n`);
458
+ await (0, promises_1.writeFile)(node_path_1.default.join(configsDir, "chain-indexer.json"), `${JSON.stringify(output.chainIndexer, null, 2)}\n`);
452
459
  // Validate chain configuration. Classification problems are reported in the
453
460
  // same pass so one run surfaces everything wrong with the registry, rather than
454
461
  // failing on the partition and hiding the rest.
@@ -225,6 +225,25 @@ export declare function validateChainConfig(chains: ChainRegistry): ValidationRe
225
225
  * a diff of either file on its own — this is the check that sees both.
226
226
  */
227
227
  export declare function validateOftCoverage(chains: ChainRegistry, oft: Record<string, unknown>): ValidationIssue[];
228
+ /**
229
+ * Insists that every real EVM chain carries a complete, coherent chain-indexer
230
+ * entry, and that no entry addresses a chain that does not exist.
231
+ *
232
+ * The indexer scans every dialable EVM chain, and its contract is that an
233
+ * unclassified chain is a hard failure — this check moves that failure from
234
+ * the indexer's boot to this build, where the person adding the chain sees it
235
+ * (RHI-6107). Selected by the `eip155:` caip2 namespace, NOT by vmType:
236
+ * HyperCore is vmType "evm" with a `hypercore:` caip2 and must not require an
237
+ * entry — the same discriminator the publish workflow's contracts guard uses,
238
+ * for the same reason. Runs after `classifyChainCaip2`, which stamps the field.
239
+ *
240
+ * The cross-field rules mirror chain-indexer's `ChainScanSettings::validate`,
241
+ * so a value set this check accepts is one the indexer will accept.
242
+ *
243
+ * A chain deliberately not indexed carries `{ indexed: false }` as its whole
244
+ * entry — a decision the check accepts, unlike a missing entry.
245
+ */
246
+ export declare function validateChainIndexerCoverage(chains: ChainRegistry, chainIndexer: Record<string, unknown>): ValidationIssue[];
228
247
  /**
229
248
  * Formats validation issues for console output.
230
249
  *
@@ -41,6 +41,7 @@ exports.classifyChainPublicRpcUrls = classifyChainPublicRpcUrls;
41
41
  exports.classifyChainStacks = classifyChainStacks;
42
42
  exports.validateChainConfig = validateChainConfig;
43
43
  exports.validateOftCoverage = validateOftCoverage;
44
+ exports.validateChainIndexerCoverage = validateChainIndexerCoverage;
44
45
  exports.formatValidationIssues = formatValidationIssues;
45
46
  const viem_1 = require("viem");
46
47
  const celo_1 = require("viem/celo");
@@ -1143,6 +1144,133 @@ function validateOftCoverage(chains, oft) {
1143
1144
  }
1144
1145
  return issues;
1145
1146
  }
1147
+ // Runtime mirrors of chain-indexer's `Finality` / `FinalitySource` Rust enums
1148
+ // (chain-indexer src/config.rs). Same build-time-only rationale as the sets at
1149
+ // the top of this file: a value outside these means the jsonnet invented a
1150
+ // classification the consumer cannot deserialize, which must fail the build
1151
+ // here rather than the indexer's boot. `safe` is legal and currently unused.
1152
+ const CHAIN_INDEXER_FINALITY = new Set([
1153
+ 'probabilistic',
1154
+ 'sequencer',
1155
+ 'instant',
1156
+ ]);
1157
+ const CHAIN_INDEXER_FINALITY_SOURCE = new Set([
1158
+ 'finalized',
1159
+ 'safe',
1160
+ 'instant',
1161
+ ]);
1162
+ // Every field of one chain-indexer entry, all required. The wire is exact on
1163
+ // purpose: the indexer's own contract is "every field mandatory — a knob nobody
1164
+ // set is a decision nobody made", so a missing field here is the same authoring
1165
+ // mistake as a missing entry, and an unrecognized field is a typo that would
1166
+ // otherwise ship silently.
1167
+ const CHAIN_INDEXER_FIELDS = {
1168
+ poll_interval_ms: isNonNegativeInt,
1169
+ streaming_poll_interval_ms: isNonNegativeInt,
1170
+ reorg_window_k: isNonNegativeInt,
1171
+ reverify_delay_ms: isNonNegativeInt,
1172
+ max_catchup_blocks: isNonNegativeInt,
1173
+ parse_concurrency: isNonNegativeInt,
1174
+ scan_batch_max_blocks: isNonNegativeInt,
1175
+ finality: (v) => typeof v === 'string' && CHAIN_INDEXER_FINALITY.has(v),
1176
+ finality_source: (v) => typeof v === 'string' && CHAIN_INDEXER_FINALITY_SOURCE.has(v),
1177
+ finality_poll_interval_ms: isNonNegativeInt,
1178
+ grace_ms: isNonNegativeInt,
1179
+ };
1180
+ /**
1181
+ * Insists that every real EVM chain carries a complete, coherent chain-indexer
1182
+ * entry, and that no entry addresses a chain that does not exist.
1183
+ *
1184
+ * The indexer scans every dialable EVM chain, and its contract is that an
1185
+ * unclassified chain is a hard failure — this check moves that failure from
1186
+ * the indexer's boot to this build, where the person adding the chain sees it
1187
+ * (RHI-6107). Selected by the `eip155:` caip2 namespace, NOT by vmType:
1188
+ * HyperCore is vmType "evm" with a `hypercore:` caip2 and must not require an
1189
+ * entry — the same discriminator the publish workflow's contracts guard uses,
1190
+ * for the same reason. Runs after `classifyChainCaip2`, which stamps the field.
1191
+ *
1192
+ * The cross-field rules mirror chain-indexer's `ChainScanSettings::validate`,
1193
+ * so a value set this check accepts is one the indexer will accept.
1194
+ *
1195
+ * A chain deliberately not indexed carries `{ indexed: false }` as its whole
1196
+ * entry — a decision the check accepts, unlike a missing entry.
1197
+ */
1198
+ function validateChainIndexerCoverage(chains, chainIndexer) {
1199
+ const issues = [];
1200
+ const requiresEntry = (chain) => typeof chain.caip2 === 'string' &&
1201
+ chain.caip2.startsWith('eip155:') &&
1202
+ chain.virtual !== true;
1203
+ for (const [chainId, chain] of Object.entries(chains)) {
1204
+ if (!requiresEntry(chain))
1205
+ continue;
1206
+ if (chainIndexer[chainId] === undefined) {
1207
+ issues.push({
1208
+ severity: 'error',
1209
+ chainId,
1210
+ chainName: isNonEmptyString(chain.name) ? chain.name : '<unnamed>',
1211
+ message: 'EVM chain has no chain-indexer entry — classify it in config/chain-indexer.jsonnet (see docs/add-chain.md, "Classify the chain for the indexer")',
1212
+ });
1213
+ }
1214
+ }
1215
+ for (const [chainId, entry] of Object.entries(chainIndexer)) {
1216
+ const chain = chains[chainId];
1217
+ const chainName = chain && isNonEmptyString(chain.name) ? chain.name : '<not in registry>';
1218
+ const issue = (message) => issues.push({ severity: 'error', chainId, chainName, message });
1219
+ if (!chain || !requiresEntry(chain)) {
1220
+ issue('chain-indexer entry addresses no real EVM chain — remove it from config/chain-indexer.jsonnet, or add the chain first');
1221
+ continue;
1222
+ }
1223
+ if (!isObject(entry)) {
1224
+ issue('chain-indexer entry is not an object');
1225
+ continue;
1226
+ }
1227
+ // `{ indexed: false }` is a complete entry: the explicit decision "this
1228
+ // chain is not indexed" — as opposed to a missing entry, which is no
1229
+ // decision at all and fails coverage above. Nothing may ride along: scan
1230
+ // settings on a chain that is not scanned are a contradiction, and
1231
+ // `indexed: true` is what a full entry already says.
1232
+ if ('indexed' in entry) {
1233
+ if (entry.indexed !== false) {
1234
+ issue(`chain-indexer \`indexed\` = ${JSON.stringify(entry.indexed)} — the only legal value is false (a full entry already means indexed)`);
1235
+ }
1236
+ const extras = Object.keys(entry).filter((field) => field !== 'indexed');
1237
+ if (extras.length) {
1238
+ issue(`chain-indexer entry sets indexed: false but also carries ${extras.map((field) => `\`${field}\``).join(', ')} — an opt-out is the whole entry, it takes no scan settings`);
1239
+ }
1240
+ continue;
1241
+ }
1242
+ for (const [field, check] of Object.entries(CHAIN_INDEXER_FIELDS)) {
1243
+ if (entry[field] === undefined) {
1244
+ issue(`chain-indexer entry is missing \`${field}\` — every field is mandatory, a knob nobody set is a decision nobody made`);
1245
+ }
1246
+ else if (!check(entry[field])) {
1247
+ issue(`chain-indexer \`${field}\` = ${JSON.stringify(entry[field])} is not a legal value`);
1248
+ }
1249
+ }
1250
+ for (const field of Object.keys(entry)) {
1251
+ if (!(field in CHAIN_INDEXER_FIELDS)) {
1252
+ issue(`chain-indexer entry carries unrecognized field \`${field}\` — the artifact's shape is exact, fix the name or drop it`);
1253
+ }
1254
+ }
1255
+ const instantClass = entry.finality === 'instant';
1256
+ const instantSource = entry.finality_source === 'instant';
1257
+ if (instantClass !== instantSource) {
1258
+ issue(`finality = ${JSON.stringify(entry.finality)} but finality_source = ${JSON.stringify(entry.finality_source)} — instant chains take neither the reorg nor the watermark path, everything else needs a real finality tag`);
1259
+ }
1260
+ if (isNonNegativeInt(entry.finality_poll_interval_ms) &&
1261
+ instantSource !== (entry.finality_poll_interval_ms === 0)) {
1262
+ issue(`finality_poll_interval_ms = ${entry.finality_poll_interval_ms} does not match finality_source = ${JSON.stringify(entry.finality_source)} — 0 exactly when the source is instant`);
1263
+ }
1264
+ const streaming = entry.streaming_poll_interval_ms;
1265
+ const poll = entry.poll_interval_ms;
1266
+ if (typeof streaming === 'number' &&
1267
+ typeof poll === 'number' &&
1268
+ streaming < poll) {
1269
+ issue(`streaming_poll_interval_ms = ${streaming} is below poll_interval_ms = ${poll} — the poll under a connected stream is a relaxation, never a speedup`);
1270
+ }
1271
+ }
1272
+ return issues;
1273
+ }
1146
1274
  /**
1147
1275
  * Formats validation issues for console output.
1148
1276
  *
@@ -17,7 +17,9 @@ declare const abiSignatures: {
17
17
  readonly multicallHandler: readonly ["function drainLeftoverToken(address, address)", "function drainLeftoverTokens(address[], address)", "function handleTargetOpsMulticall((bytes))", "function withdrawAllWETH(address)", "function withdrawWETH(address, uint256)"];
18
18
  readonly nexus: readonly ["function accountId() pure returns (string)", "function addDeposit() payable", "function checkERC7739Support(bytes32, bytes) view returns (bytes4)", "function eip712Domain() view returns (bytes1, string, string, uint256, address, bytes32, uint256[])", "function emergencyUninstallHook((address, uint256, bytes, uint256), bytes) payable", "function entryPoint() view returns (address)", "function execute(bytes32, bytes) payable", "function executeComposable((address, uint256, bytes4, (uint8, bytes, (uint8, bytes)[])[], (uint8, bytes)[])[]) payable", "function executeFromExecutor(bytes32, bytes) payable returns (bytes[])", "function executeUserOp((address, uint256, bytes, bytes, bytes32, uint256, bytes32, bytes, bytes), bytes32) payable", "function getActiveHook() view returns (address)", "function getDeposit() view returns (uint256)", "function getExecutorsPaginated(address, uint256) view returns (address[], address)", "function getFallbackHandlerBySelector(bytes4) view returns (bytes1, address)", "function getImplementation() view returns (address)", "function getRegistry() view returns (address)", "function getValidatorsPaginated(address, uint256) view returns (address[], address)", "function initializeAccount(bytes) payable", "function installModule(uint256, address, bytes) payable", "function isInitialized() view returns (bool)", "function isModuleInstalled(uint256, address, bytes) view returns (bool)", "function isValidSignature(bytes32, bytes) view returns (bytes4)", "function nonce(uint192) view returns (uint256)", "function proxiableUUID() view returns (bytes32)", "function setRegistry(address, address[], uint8) payable", "function supportsExecutionMode(bytes32) view returns (bool)", "function supportsModule(uint256) view returns (bool)", "function uninstallModule(uint256, address, bytes) payable", "function upgradeToAndCall(address, bytes) payable", "function validateUserOp((address, uint256, bytes, bytes, bytes32, uint256, bytes32, bytes, bytes), bytes32, uint256) returns (uint256)", "function withdrawDepositTo(address, uint256) payable"];
19
19
  readonly nexusAccountFactory: readonly ["function ACCOUNT_IMPLEMENTATION() view returns (address)", "function addStake(address, uint32) payable", "function cancelOwnershipHandover() payable", "function completeOwnershipHandover(address) payable", "function computeAccountAddress(bytes, bytes32) view returns (address)", "function createAccount(bytes, bytes32) payable returns (address)", "function owner() view returns (address)", "function ownershipHandoverExpiresAt(address) view returns (uint256)", "function renounceOwnership() payable", "function requestOwnershipHandover() payable", "function transferOwnership(address) payable", "function unlockStake(address)", "function withdrawStake(address, address)"];
20
+ readonly nexusAccountFactoryLegacy: readonly ["function ACCOUNT_IMPLEMENTATION() view returns (address)", "function addStake(address, uint32) payable", "function cancelOwnershipHandover() payable", "function completeOwnershipHandover(address) payable", "function computeAccountAddress(bytes, bytes32) view returns (address)", "function createAccount(bytes, bytes32) payable returns (address)", "function owner() view returns (address)", "function ownershipHandoverExpiresAt(address) view returns (uint256)", "function renounceOwnership() payable", "function requestOwnershipHandover() payable", "function transferOwnership(address) payable", "function unlockStake(address)", "function withdrawStake(address, address)"];
20
21
  readonly nexusBootstrap: readonly ["function eip712Domain() view returns (bytes1, string, string, uint256, address, bytes32, uint256[])", "function getActiveHook() view returns (address)", "function getExecutorsPaginated(address, uint256) view returns (address[], address)", "function getFallbackHandlerBySelector(bytes4) view returns (bytes1, address)", "function getRegistry() view returns (address)", "function getValidatorsPaginated(address, uint256) view returns (address[], address)", "function initNexus((address, bytes)[], (address, bytes)[], (address, bytes), (address, bytes)[], (uint256, address, bytes)[], (address, address[], uint8)) payable", "function initNexusNoRegistry((address, bytes)[], (address, bytes)[], (address, bytes), (address, bytes)[], (uint256, address, bytes)[]) payable", "function initNexusScoped((address, bytes)[], (address, bytes), (address, address[], uint8)) payable", "function initNexusScopedNoRegistry((address, bytes)[], (address, bytes)) payable", "function initNexusWithDefaultValidator(bytes) payable", "function initNexusWithDefaultValidatorAndOtherModules(bytes, (address, bytes)[], (address, bytes)[], (address, bytes), (address, bytes)[], (uint256, address, bytes)[], (address, address[], uint8)) payable", "function initNexusWithDefaultValidatorAndOtherModulesNoRegistry(bytes, (address, bytes)[], (address, bytes)[], (address, bytes), (address, bytes)[], (uint256, address, bytes)[]) payable", "function initNexusWithSingleValidator(address, bytes, (address, address[], uint8)) payable", "function initNexusWithSingleValidatorNoRegistry(address, bytes) payable", "function installModule(uint256, address, bytes) payable", "function isModuleInstalled(uint256, address, bytes) view returns (bool)", "function uninstallModule(uint256, address, bytes) payable"];
22
+ readonly nexusLegacy: readonly ["function accountId() pure returns (string)", "function addDeposit() payable", "function checkERC7739Support(bytes32, bytes) view returns (bytes4)", "function eip712Domain() view returns (bytes1, string, string, uint256, address, bytes32, uint256[])", "function emergencyUninstallHook((address, uint256, bytes, uint256), bytes) payable", "function entryPoint() view returns (address)", "function execute(bytes32, bytes) payable", "function executeComposable((address, uint256, bytes4, (uint8, bytes, (uint8, bytes)[])[], (uint8, bytes)[])[]) payable", "function executeFromExecutor(bytes32, bytes) payable returns (bytes[])", "function executeUserOp((address, uint256, bytes, bytes, bytes32, uint256, bytes32, bytes, bytes), bytes32) payable", "function getActiveHook() view returns (address)", "function getDeposit() view returns (uint256)", "function getExecutorsPaginated(address, uint256) view returns (address[], address)", "function getFallbackHandlerBySelector(bytes4) view returns (bytes1, address)", "function getImplementation() view returns (address)", "function getRegistry() view returns (address)", "function getValidatorsPaginated(address, uint256) view returns (address[], address)", "function initializeAccount(bytes) payable", "function installModule(uint256, address, bytes) payable", "function isInitialized() view returns (bool)", "function isModuleInstalled(uint256, address, bytes) view returns (bool)", "function isValidSignature(bytes32, bytes) view returns (bytes4)", "function nonce(uint192) view returns (uint256)", "function proxiableUUID() view returns (bytes32)", "function setRegistry(address, address[], uint8) payable", "function supportsExecutionMode(bytes32) view returns (bool)", "function supportsModule(uint256) view returns (bool)", "function uninstallModule(uint256, address, bytes) payable", "function upgradeToAndCall(address, bytes) payable", "function validateUserOp((address, uint256, bytes, bytes, bytes32, uint256, bytes32, bytes, bytes), bytes32, uint256) returns (uint256)", "function withdrawDepositTo(address, uint256) payable"];
21
23
  readonly oftFeeAdapter: readonly ["function ADAPTER_TAG() pure returns (bytes12)", "function ARBITER() view returns (address)", "function _ROUTER() view returns (address)", "function handleFill_oftFee_sendNative(address, uint256) payable returns (bytes4)", "function semVer() view returns (bytes6)", "function semVerUnpacked() view returns (uint256, uint256, uint256)", "function settlementLayerSpender() view returns (address)", "function supportsInterface(bytes4) pure returns (bool)", "function version() view returns (bytes)"];
22
24
  readonly oftProxy: readonly ["function OFT_ADAPTER() view returns (address)", "function OFT_TOKEN() view returns (address)", "function SLIPPAGE_TOLERANCE_BASIS_POINTS() view returns (uint256)", "function sendMax((uint32, bytes32), (uint256, uint256), uint256) payable"];
23
25
  readonly paymaster: readonly ["function INTENT_EXECUTOR() view returns (address)", "function callbackAllowMaxAmount(address, uint256) payable", "function settleGasRefund(address, address, uint256, address)", "function settleGasRefund_requireCallback(address, address, uint256, address)"];
@@ -279,6 +279,21 @@ const abiSignatures = {
279
279
  "function unlockStake(address)",
280
280
  "function withdrawStake(address, address)"
281
281
  ],
282
+ "nexusAccountFactoryLegacy": [
283
+ "function ACCOUNT_IMPLEMENTATION() view returns (address)",
284
+ "function addStake(address, uint32) payable",
285
+ "function cancelOwnershipHandover() payable",
286
+ "function completeOwnershipHandover(address) payable",
287
+ "function computeAccountAddress(bytes, bytes32) view returns (address)",
288
+ "function createAccount(bytes, bytes32) payable returns (address)",
289
+ "function owner() view returns (address)",
290
+ "function ownershipHandoverExpiresAt(address) view returns (uint256)",
291
+ "function renounceOwnership() payable",
292
+ "function requestOwnershipHandover() payable",
293
+ "function transferOwnership(address) payable",
294
+ "function unlockStake(address)",
295
+ "function withdrawStake(address, address)"
296
+ ],
282
297
  "nexusBootstrap": [
283
298
  "function eip712Domain() view returns (bytes1, string, string, uint256, address, bytes32, uint256[])",
284
299
  "function getActiveHook() view returns (address)",
@@ -299,6 +314,39 @@ const abiSignatures = {
299
314
  "function isModuleInstalled(uint256, address, bytes) view returns (bool)",
300
315
  "function uninstallModule(uint256, address, bytes) payable"
301
316
  ],
317
+ "nexusLegacy": [
318
+ "function accountId() pure returns (string)",
319
+ "function addDeposit() payable",
320
+ "function checkERC7739Support(bytes32, bytes) view returns (bytes4)",
321
+ "function eip712Domain() view returns (bytes1, string, string, uint256, address, bytes32, uint256[])",
322
+ "function emergencyUninstallHook((address, uint256, bytes, uint256), bytes) payable",
323
+ "function entryPoint() view returns (address)",
324
+ "function execute(bytes32, bytes) payable",
325
+ "function executeComposable((address, uint256, bytes4, (uint8, bytes, (uint8, bytes)[])[], (uint8, bytes)[])[]) payable",
326
+ "function executeFromExecutor(bytes32, bytes) payable returns (bytes[])",
327
+ "function executeUserOp((address, uint256, bytes, bytes, bytes32, uint256, bytes32, bytes, bytes), bytes32) payable",
328
+ "function getActiveHook() view returns (address)",
329
+ "function getDeposit() view returns (uint256)",
330
+ "function getExecutorsPaginated(address, uint256) view returns (address[], address)",
331
+ "function getFallbackHandlerBySelector(bytes4) view returns (bytes1, address)",
332
+ "function getImplementation() view returns (address)",
333
+ "function getRegistry() view returns (address)",
334
+ "function getValidatorsPaginated(address, uint256) view returns (address[], address)",
335
+ "function initializeAccount(bytes) payable",
336
+ "function installModule(uint256, address, bytes) payable",
337
+ "function isInitialized() view returns (bool)",
338
+ "function isModuleInstalled(uint256, address, bytes) view returns (bool)",
339
+ "function isValidSignature(bytes32, bytes) view returns (bytes4)",
340
+ "function nonce(uint192) view returns (uint256)",
341
+ "function proxiableUUID() view returns (bytes32)",
342
+ "function setRegistry(address, address[], uint8) payable",
343
+ "function supportsExecutionMode(bytes32) view returns (bool)",
344
+ "function supportsModule(uint256) view returns (bool)",
345
+ "function uninstallModule(uint256, address, bytes) payable",
346
+ "function upgradeToAndCall(address, bytes) payable",
347
+ "function validateUserOp((address, uint256, bytes, bytes, bytes32, uint256, bytes32, bytes, bytes), bytes32, uint256) returns (uint256)",
348
+ "function withdrawDepositTo(address, uint256) payable"
349
+ ],
302
350
  "oftFeeAdapter": [
303
351
  "function ADAPTER_TAG() pure returns (bytes12)",
304
352
  "function ARBITER() view returns (address)",
@@ -1,2 +1,2 @@
1
- declare const PACKAGE_VERSION = "2.6.0";
1
+ declare const PACKAGE_VERSION = "2.8.0";
2
2
  export { PACKAGE_VERSION };
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PACKAGE_VERSION = void 0;
4
4
  // Auto-generated by scripts/generate.ts. Do not edit manually.
5
- const PACKAGE_VERSION = "2.6.0";
5
+ const PACKAGE_VERSION = "2.8.0";
6
6
  exports.PACKAGE_VERSION = PACKAGE_VERSION;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rhinestone/shared-configs",
3
- "version": "2.6.0",
3
+ "version": "2.8.0",
4
4
  "description": "Reusable configuration files for Rhinestone services",
5
5
  "author": {
6
6
  "name": "Rhinestone",