@rhinestone/shared-configs 1.7.16 → 1.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.
- package/dist/configs/chains.json +50 -1
- package/dist/scripts/__tests__/validation.test.js +215 -10
- package/dist/scripts/generate.js +31 -5
- package/dist/scripts/validation.d.ts +78 -2
- package/dist/scripts/validation.d.ts.map +1 -1
- package/dist/scripts/validation.js +439 -1
- package/dist/src/__tests__/chainFactsClient.test.d.ts +2 -0
- package/dist/src/__tests__/chainFactsClient.test.d.ts.map +1 -0
- package/dist/src/__tests__/chainFactsClient.test.js +460 -0
- package/dist/src/chainFactsClient.d.ts +57 -0
- package/dist/src/chainFactsClient.d.ts.map +1 -0
- package/dist/src/chainFactsClient.js +295 -0
- package/dist/src/chains.d.ts +5 -1
- package/dist/src/chains.d.ts.map +1 -1
- package/dist/src/chains.js +50 -1
- package/dist/src/generated/abis.d.ts +4 -0
- package/dist/src/generated/abis.d.ts.map +1 -1
- package/dist/src/generated/abis.js +82 -0
- package/dist/src/generated/chainFactsKey.d.ts +5 -0
- package/dist/src/generated/chainFactsKey.d.ts.map +1 -0
- package/dist/src/generated/chainFactsKey.js +19 -0
- package/dist/src/generated/networks.d.ts +1281 -1281
- package/dist/src/generated/networks.d.ts.map +1 -1
- package/dist/src/generated/packageVersion.d.ts +3 -0
- package/dist/src/generated/packageVersion.d.ts.map +1 -0
- package/dist/src/generated/packageVersion.js +6 -0
- package/dist/src/index.d.ts +6 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +6 -1
- package/dist/src/types.d.ts +37 -1
- package/dist/src/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/configs/chains.json
CHANGED
|
@@ -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",
|
|
@@ -15,6 +16,7 @@
|
|
|
15
16
|
"RHINO",
|
|
16
17
|
"CCTP"
|
|
17
18
|
],
|
|
19
|
+
"stack": "vanilla",
|
|
18
20
|
"swapQuoterConfig": {},
|
|
19
21
|
"swapQuoters": [
|
|
20
22
|
"1inch",
|
|
@@ -72,6 +74,7 @@
|
|
|
72
74
|
"decimals": 18,
|
|
73
75
|
"symbol": "ETH"
|
|
74
76
|
},
|
|
77
|
+
"network": "mainnet",
|
|
75
78
|
"settlementLayers": [
|
|
76
79
|
"ACROSS",
|
|
77
80
|
"ECO",
|
|
@@ -81,6 +84,7 @@
|
|
|
81
84
|
"RHINO",
|
|
82
85
|
"CCTP"
|
|
83
86
|
],
|
|
87
|
+
"stack": "op-stack",
|
|
84
88
|
"swapQuoterConfig": {},
|
|
85
89
|
"swapQuoters": [
|
|
86
90
|
"1inch",
|
|
@@ -146,6 +150,7 @@
|
|
|
146
150
|
"decimals": 18,
|
|
147
151
|
"symbol": "BNB"
|
|
148
152
|
},
|
|
153
|
+
"network": "mainnet",
|
|
149
154
|
"settlementLayers": [
|
|
150
155
|
"ACROSS",
|
|
151
156
|
"ECO",
|
|
@@ -153,6 +158,7 @@
|
|
|
153
158
|
"RHINO",
|
|
154
159
|
"CCTP"
|
|
155
160
|
],
|
|
161
|
+
"stack": "vanilla",
|
|
156
162
|
"swapQuoters": [
|
|
157
163
|
"1inch",
|
|
158
164
|
"0x",
|
|
@@ -200,11 +206,13 @@
|
|
|
200
206
|
"decimals": 18,
|
|
201
207
|
"symbol": "XDAI"
|
|
202
208
|
},
|
|
209
|
+
"network": "mainnet",
|
|
203
210
|
"settlementLayers": [
|
|
204
211
|
"RELAY",
|
|
205
212
|
"NEAR",
|
|
206
213
|
"RHINO"
|
|
207
214
|
],
|
|
215
|
+
"stack": "vanilla",
|
|
208
216
|
"swapQuoters": [
|
|
209
217
|
"1inch",
|
|
210
218
|
"velora"
|
|
@@ -233,6 +241,7 @@
|
|
|
233
241
|
"decimals": 18,
|
|
234
242
|
"symbol": "ETH"
|
|
235
243
|
},
|
|
244
|
+
"network": "mainnet",
|
|
236
245
|
"settlementLayers": [
|
|
237
246
|
"ACROSS",
|
|
238
247
|
"ECO",
|
|
@@ -241,6 +250,7 @@
|
|
|
241
250
|
"RHINO",
|
|
242
251
|
"CCTP"
|
|
243
252
|
],
|
|
253
|
+
"stack": "op-stack",
|
|
244
254
|
"swapQuoterConfig": {},
|
|
245
255
|
"swapQuoters": [
|
|
246
256
|
"1inch",
|
|
@@ -298,6 +308,7 @@
|
|
|
298
308
|
"decimals": 18,
|
|
299
309
|
"symbol": "POL"
|
|
300
310
|
},
|
|
311
|
+
"network": "mainnet",
|
|
301
312
|
"settlementLayers": [
|
|
302
313
|
"ACROSS",
|
|
303
314
|
"ECO",
|
|
@@ -307,6 +318,7 @@
|
|
|
307
318
|
"RHINO",
|
|
308
319
|
"CCTP"
|
|
309
320
|
],
|
|
321
|
+
"stack": "vanilla",
|
|
310
322
|
"swapQuoterConfig": {},
|
|
311
323
|
"swapQuoters": [
|
|
312
324
|
"1inch",
|
|
@@ -356,11 +368,13 @@
|
|
|
356
368
|
"decimals": 18,
|
|
357
369
|
"symbol": "MON"
|
|
358
370
|
},
|
|
371
|
+
"network": "mainnet",
|
|
359
372
|
"settlementLayers": [
|
|
360
373
|
"ACROSS",
|
|
361
374
|
"RELAY",
|
|
362
375
|
"CCTP"
|
|
363
376
|
],
|
|
377
|
+
"stack": "vanilla",
|
|
364
378
|
"swapQuoters": [
|
|
365
379
|
"0x"
|
|
366
380
|
],
|
|
@@ -411,12 +425,14 @@
|
|
|
411
425
|
"decimals": 18,
|
|
412
426
|
"symbol": "S"
|
|
413
427
|
},
|
|
428
|
+
"network": "mainnet",
|
|
414
429
|
"settlementLayers": [
|
|
415
430
|
"ECO",
|
|
416
431
|
"RELAY",
|
|
417
432
|
"RHINO",
|
|
418
433
|
"CCTP"
|
|
419
434
|
],
|
|
435
|
+
"stack": "vanilla",
|
|
420
436
|
"swapQuoterConfig": {},
|
|
421
437
|
"swapQuoters": [
|
|
422
438
|
"1inch",
|
|
@@ -447,12 +463,14 @@
|
|
|
447
463
|
"decimals": 18,
|
|
448
464
|
"symbol": "HYPE"
|
|
449
465
|
},
|
|
466
|
+
"network": "mainnet",
|
|
450
467
|
"settlementLayers": [
|
|
451
468
|
"ACROSS",
|
|
452
469
|
"ECO",
|
|
453
470
|
"RELAY",
|
|
454
471
|
"CCTP"
|
|
455
472
|
],
|
|
473
|
+
"stack": "vanilla",
|
|
456
474
|
"swapQuoters": [
|
|
457
475
|
"0x"
|
|
458
476
|
],
|
|
@@ -490,7 +508,9 @@
|
|
|
490
508
|
"decimals": 18,
|
|
491
509
|
"symbol": "HYPE"
|
|
492
510
|
},
|
|
511
|
+
"network": "mainnet",
|
|
493
512
|
"settlementLayers": [],
|
|
513
|
+
"stack": "vanilla",
|
|
494
514
|
"swapQuoters": [],
|
|
495
515
|
"tokens": [
|
|
496
516
|
{
|
|
@@ -517,10 +537,12 @@
|
|
|
517
537
|
"decimals": 18,
|
|
518
538
|
"symbol": "ETH"
|
|
519
539
|
},
|
|
540
|
+
"network": "mainnet",
|
|
520
541
|
"settlementLayers": [
|
|
521
542
|
"ACROSS",
|
|
522
543
|
"RELAY"
|
|
523
544
|
],
|
|
545
|
+
"stack": "op-stack",
|
|
524
546
|
"swapQuoters": [],
|
|
525
547
|
"tokens": [
|
|
526
548
|
{
|
|
@@ -571,10 +593,12 @@
|
|
|
571
593
|
"decimals": 18,
|
|
572
594
|
"symbol": "ETH"
|
|
573
595
|
},
|
|
596
|
+
"network": "mainnet",
|
|
574
597
|
"settlementLayers": [
|
|
575
598
|
"ACROSS",
|
|
576
599
|
"RELAY"
|
|
577
600
|
],
|
|
601
|
+
"stack": "vanilla",
|
|
578
602
|
"swapQuoters": [
|
|
579
603
|
"1inch",
|
|
580
604
|
"0x"
|
|
@@ -620,6 +644,7 @@
|
|
|
620
644
|
"decimals": 18,
|
|
621
645
|
"symbol": "ETH"
|
|
622
646
|
},
|
|
647
|
+
"network": "mainnet",
|
|
623
648
|
"settlementLayers": [
|
|
624
649
|
"ACROSS",
|
|
625
650
|
"ECO",
|
|
@@ -628,6 +653,7 @@
|
|
|
628
653
|
"RHINO",
|
|
629
654
|
"CCTP"
|
|
630
655
|
],
|
|
656
|
+
"stack": "op-stack",
|
|
631
657
|
"swapQuoterConfig": {},
|
|
632
658
|
"swapQuoters": [
|
|
633
659
|
"1inch",
|
|
@@ -675,6 +701,7 @@
|
|
|
675
701
|
"decimals": 18,
|
|
676
702
|
"symbol": "XPL"
|
|
677
703
|
},
|
|
704
|
+
"network": "mainnet",
|
|
678
705
|
"settlementLayers": [
|
|
679
706
|
"ACROSS",
|
|
680
707
|
"ECO",
|
|
@@ -682,9 +709,11 @@
|
|
|
682
709
|
"OFT",
|
|
683
710
|
"RHINO"
|
|
684
711
|
],
|
|
712
|
+
"stack": "vanilla",
|
|
685
713
|
"swapQuoterConfig": {},
|
|
686
714
|
"swapQuoters": [
|
|
687
|
-
"0x"
|
|
715
|
+
"0x",
|
|
716
|
+
"fynd"
|
|
688
717
|
],
|
|
689
718
|
"tokens": [
|
|
690
719
|
{
|
|
@@ -711,9 +740,11 @@
|
|
|
711
740
|
"decimals": 18,
|
|
712
741
|
"symbol": "XPL"
|
|
713
742
|
},
|
|
743
|
+
"network": "testnet",
|
|
714
744
|
"settlementLayers": [
|
|
715
745
|
"ECO"
|
|
716
746
|
],
|
|
747
|
+
"stack": "vanilla",
|
|
717
748
|
"swapQuoters": [],
|
|
718
749
|
"tokens": [
|
|
719
750
|
{
|
|
@@ -748,6 +779,7 @@
|
|
|
748
779
|
"decimals": 18,
|
|
749
780
|
"symbol": "ETH"
|
|
750
781
|
},
|
|
782
|
+
"network": "mainnet",
|
|
751
783
|
"settlementLayers": [
|
|
752
784
|
"ACROSS",
|
|
753
785
|
"ECO",
|
|
@@ -757,6 +789,7 @@
|
|
|
757
789
|
"RHINO",
|
|
758
790
|
"CCTP"
|
|
759
791
|
],
|
|
792
|
+
"stack": "vanilla",
|
|
760
793
|
"swapQuoterConfig": {},
|
|
761
794
|
"swapQuoters": [
|
|
762
795
|
"1inch",
|
|
@@ -814,6 +847,7 @@
|
|
|
814
847
|
"decimals": 18,
|
|
815
848
|
"symbol": "AVAX"
|
|
816
849
|
},
|
|
850
|
+
"network": "mainnet",
|
|
817
851
|
"settlementLayers": [
|
|
818
852
|
"ACROSS",
|
|
819
853
|
"RELAY",
|
|
@@ -821,6 +855,7 @@
|
|
|
821
855
|
"RHINO",
|
|
822
856
|
"CCTP"
|
|
823
857
|
],
|
|
858
|
+
"stack": "vanilla",
|
|
824
859
|
"swapQuoters": [
|
|
825
860
|
"1inch",
|
|
826
861
|
"0x",
|
|
@@ -883,11 +918,13 @@
|
|
|
883
918
|
"decimals": 18,
|
|
884
919
|
"symbol": "ETH"
|
|
885
920
|
},
|
|
921
|
+
"network": "testnet",
|
|
886
922
|
"settlementLayers": [
|
|
887
923
|
"ACROSS",
|
|
888
924
|
"ECO",
|
|
889
925
|
"CCTP"
|
|
890
926
|
],
|
|
927
|
+
"stack": "op-stack",
|
|
891
928
|
"swapQuoters": [],
|
|
892
929
|
"tokens": [
|
|
893
930
|
{
|
|
@@ -940,11 +977,13 @@
|
|
|
940
977
|
"decimals": 18,
|
|
941
978
|
"symbol": "ETH"
|
|
942
979
|
},
|
|
980
|
+
"network": "testnet",
|
|
943
981
|
"settlementLayers": [
|
|
944
982
|
"ACROSS",
|
|
945
983
|
"ECO",
|
|
946
984
|
"CCTP"
|
|
947
985
|
],
|
|
986
|
+
"stack": "vanilla",
|
|
948
987
|
"swapQuoters": [],
|
|
949
988
|
"tokens": [
|
|
950
989
|
{
|
|
@@ -987,10 +1026,12 @@
|
|
|
987
1026
|
"decimals": 18,
|
|
988
1027
|
"symbol": "ETH"
|
|
989
1028
|
},
|
|
1029
|
+
"network": "mainnet",
|
|
990
1030
|
"settlementLayers": [
|
|
991
1031
|
"RELAY",
|
|
992
1032
|
"RHINO"
|
|
993
1033
|
],
|
|
1034
|
+
"stack": "vanilla",
|
|
994
1035
|
"swapQuoters": [],
|
|
995
1036
|
"tokens": [
|
|
996
1037
|
{
|
|
@@ -1043,11 +1084,13 @@
|
|
|
1043
1084
|
"decimals": 18,
|
|
1044
1085
|
"symbol": "ETH"
|
|
1045
1086
|
},
|
|
1087
|
+
"network": "testnet",
|
|
1046
1088
|
"settlementLayers": [
|
|
1047
1089
|
"ACROSS",
|
|
1048
1090
|
"ECO",
|
|
1049
1091
|
"CCTP"
|
|
1050
1092
|
],
|
|
1093
|
+
"stack": "vanilla",
|
|
1051
1094
|
"swapQuoters": [],
|
|
1052
1095
|
"tokens": [
|
|
1053
1096
|
{
|
|
@@ -1090,11 +1133,13 @@
|
|
|
1090
1133
|
"decimals": 18,
|
|
1091
1134
|
"symbol": "ETH"
|
|
1092
1135
|
},
|
|
1136
|
+
"network": "testnet",
|
|
1093
1137
|
"settlementLayers": [
|
|
1094
1138
|
"ACROSS",
|
|
1095
1139
|
"ECO",
|
|
1096
1140
|
"CCTP"
|
|
1097
1141
|
],
|
|
1142
|
+
"stack": "op-stack",
|
|
1098
1143
|
"swapQuoters": [],
|
|
1099
1144
|
"tokens": [
|
|
1100
1145
|
{
|
|
@@ -1138,12 +1183,14 @@
|
|
|
1138
1183
|
"decimals": 6,
|
|
1139
1184
|
"symbol": "TRX"
|
|
1140
1185
|
},
|
|
1186
|
+
"network": "mainnet",
|
|
1141
1187
|
"settlementLayers": [
|
|
1142
1188
|
"RELAY",
|
|
1143
1189
|
"OFT",
|
|
1144
1190
|
"NEAR",
|
|
1145
1191
|
"RHINO"
|
|
1146
1192
|
],
|
|
1193
|
+
"stack": "vanilla",
|
|
1147
1194
|
"swapQuoters": [],
|
|
1148
1195
|
"tokens": [
|
|
1149
1196
|
{
|
|
@@ -1177,6 +1224,7 @@
|
|
|
1177
1224
|
"decimals": 9,
|
|
1178
1225
|
"symbol": "SOL"
|
|
1179
1226
|
},
|
|
1227
|
+
"network": "mainnet",
|
|
1180
1228
|
"settlementLayers": [
|
|
1181
1229
|
"RELAY",
|
|
1182
1230
|
"OFT",
|
|
@@ -1184,6 +1232,7 @@
|
|
|
1184
1232
|
"RHINO",
|
|
1185
1233
|
"CCTP"
|
|
1186
1234
|
],
|
|
1235
|
+
"stack": "vanilla",
|
|
1187
1236
|
"swapQuoters": [],
|
|
1188
1237
|
"tokens": [
|
|
1189
1238
|
{
|
|
@@ -2,18 +2,75 @@
|
|
|
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
|
-
|
|
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
|
+
stack: "vanilla",
|
|
14
|
+
nativeToken,
|
|
15
|
+
wrappedNativeToken: { ...nativeToken, symbol: "WETH" },
|
|
16
|
+
tokens: [{ ...nativeToken, balanceSlot: null, approvalSlot: null }],
|
|
17
|
+
settlementLayers: ["ACROSS", "ECO", "RELAY"],
|
|
18
|
+
swapQuoters: ["0x"],
|
|
19
|
+
...overrides,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function errorsFor(chain) {
|
|
23
|
+
return (0, validation_1.validateChainConfig)({ "1": chain }).issues.filter((i) => i.severity === "error");
|
|
24
|
+
}
|
|
25
|
+
(0, bun_test_1.describe)("validateChainConfig — structure", () => {
|
|
26
|
+
// The real generated registry is the thing this actually has to accept; if
|
|
27
|
+
// the checks drift stricter than the generator, the build breaks on good data.
|
|
28
|
+
(0, bun_test_1.it)("accepts the real generated chain registry", () => {
|
|
29
|
+
const result = (0, validation_1.validateChainConfig)(index_1.chainRegistry);
|
|
30
|
+
const errors = result.issues.filter((i) => i.severity === "error");
|
|
31
|
+
(0, bun_test_1.expect)(errors).toEqual([]);
|
|
32
|
+
(0, bun_test_1.expect)(result.hasErrors).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
(0, bun_test_1.it)("rejects a key that is not a canonical chain id", () => {
|
|
35
|
+
const result = (0, validation_1.validateChainConfig)({ "01": validChain() });
|
|
36
|
+
(0, bun_test_1.expect)(result.hasErrors).toBe(true);
|
|
37
|
+
(0, bun_test_1.expect)(result.issues[0].message).toContain("canonical chain id");
|
|
38
|
+
});
|
|
39
|
+
bun_test_1.it.each([
|
|
40
|
+
["a missing name", { name: undefined }],
|
|
41
|
+
["an unknown vmType", { vmType: "wasm" }],
|
|
42
|
+
["a non-object nativeToken", { nativeToken: "0x0" }],
|
|
43
|
+
["a nativeToken missing decimals", { nativeToken: { address: "0x0", symbol: "ETH" } }],
|
|
44
|
+
["tokens not an array", { tokens: {} }],
|
|
45
|
+
["a token missing its slots", { tokens: [nativeToken] }],
|
|
46
|
+
["a token with a bad pegGroup", {
|
|
47
|
+
tokens: [{ ...nativeToken, balanceSlot: null, approvalSlot: null, pegGroup: "GBP" }],
|
|
48
|
+
}],
|
|
49
|
+
["an unknown settlement layer", { settlementLayers: ["ACROSS", "TELEPORT"] }],
|
|
50
|
+
["an unknown swap quoter", { swapQuoters: ["mystery-dex"] }],
|
|
51
|
+
["a malformed swapQuoterConfig", { swapQuoterConfig: { "0x": { slug: 5 } } }],
|
|
52
|
+
["a swapQuoterConfig for an unknown quoter", { swapQuoterConfig: { nope: {} } }],
|
|
53
|
+
["a non-boolean virtual flag", { virtual: "true" }],
|
|
54
|
+
["a missing network", { network: undefined }],
|
|
55
|
+
["an unknown network", { network: "devnet" }],
|
|
56
|
+
])("rejects %s", (_label, overrides) => {
|
|
57
|
+
(0, bun_test_1.expect)(errorsFor(validChain(overrides)).length).toBeGreaterThan(0);
|
|
58
|
+
});
|
|
59
|
+
(0, bun_test_1.it)("names the offending value so the build failure is actionable", () => {
|
|
60
|
+
const [error] = errorsFor(validChain({ settlementLayers: ["TELEPORT"] }));
|
|
61
|
+
(0, bun_test_1.expect)(error.message).toContain("TELEPORT");
|
|
62
|
+
(0, bun_test_1.expect)(error.message).toContain("src/types.ts");
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
(0, bun_test_1.describe)("validateChainConfig — reachability", () => {
|
|
6
66
|
(0, bun_test_1.it)("returns no issues for chains with multiple settlement layers", () => {
|
|
7
|
-
const
|
|
8
|
-
"1": { name: "Ethereum", settlementLayers: ["ACROSS", "ECO", "RELAY"], tokens: [] },
|
|
9
|
-
};
|
|
10
|
-
const result = (0, validation_1.validateChainConfig)(chains);
|
|
67
|
+
const result = (0, validation_1.validateChainConfig)({ "1": validChain() });
|
|
11
68
|
(0, bun_test_1.expect)(result.issues).toHaveLength(0);
|
|
12
69
|
(0, bun_test_1.expect)(result.hasErrors).toBe(false);
|
|
13
70
|
});
|
|
14
71
|
(0, bun_test_1.it)("returns error for chain with zero settlement layers", () => {
|
|
15
72
|
const chains = {
|
|
16
|
-
"100": { name: "Gnosis", settlementLayers: []
|
|
73
|
+
"100": validChain({ name: "Gnosis", settlementLayers: [] }),
|
|
17
74
|
};
|
|
18
75
|
const result = (0, validation_1.validateChainConfig)(chains);
|
|
19
76
|
(0, bun_test_1.expect)(result.issues).toHaveLength(1);
|
|
@@ -24,7 +81,7 @@ const validation_1 = require("../validation");
|
|
|
24
81
|
});
|
|
25
82
|
(0, bun_test_1.it)("returns warning for chain with single settlement layer", () => {
|
|
26
83
|
const chains = {
|
|
27
|
-
"100": { name: "Gnosis", settlementLayers: ["RELAY"]
|
|
84
|
+
"100": validChain({ name: "Gnosis", settlementLayers: ["RELAY"] }),
|
|
28
85
|
};
|
|
29
86
|
const result = (0, validation_1.validateChainConfig)(chains);
|
|
30
87
|
(0, bun_test_1.expect)(result.issues).toHaveLength(1);
|
|
@@ -32,11 +89,18 @@ const validation_1 = require("../validation");
|
|
|
32
89
|
(0, bun_test_1.expect)(result.issues[0].message).toContain("RELAY");
|
|
33
90
|
(0, bun_test_1.expect)(result.hasErrors).toBe(false);
|
|
34
91
|
});
|
|
92
|
+
(0, bun_test_1.it)("skips the reachability check for virtual chains", () => {
|
|
93
|
+
const chains = {
|
|
94
|
+
"1337": validChain({ name: "HyperCore", virtual: true, settlementLayers: [] }),
|
|
95
|
+
};
|
|
96
|
+
const result = (0, validation_1.validateChainConfig)(chains);
|
|
97
|
+
(0, bun_test_1.expect)(result.issues).toHaveLength(0);
|
|
98
|
+
});
|
|
35
99
|
(0, bun_test_1.it)("handles mixed chains correctly", () => {
|
|
36
100
|
const chains = {
|
|
37
|
-
"1":
|
|
38
|
-
"100": { name: "Gnosis", settlementLayers: ["RELAY"]
|
|
39
|
-
"999": { name: "Broken", settlementLayers: []
|
|
101
|
+
"1": validChain(),
|
|
102
|
+
"100": validChain({ name: "Gnosis", settlementLayers: ["RELAY"] }),
|
|
103
|
+
"999": validChain({ name: "Broken", settlementLayers: [] }),
|
|
40
104
|
};
|
|
41
105
|
const result = (0, validation_1.validateChainConfig)(chains);
|
|
42
106
|
(0, bun_test_1.expect)(result.issues).toHaveLength(2);
|
|
@@ -91,3 +155,144 @@ const validation_1 = require("../validation");
|
|
|
91
155
|
(0, bun_test_1.expect)(output).toContain("Gnosis (100)");
|
|
92
156
|
});
|
|
93
157
|
});
|
|
158
|
+
(0, bun_test_1.describe)("classifyChainNetworks", () => {
|
|
159
|
+
const providers = { providers: ["DRPC"] };
|
|
160
|
+
(0, bun_test_1.it)("stamps the network from whichever map holds the chain id", () => {
|
|
161
|
+
const { chains, issues } = (0, validation_1.classifyChainNetworks)({ "1": validChain(), "11155111": validChain({ name: "Sepolia" }) }, { "1": providers }, { "11155111": providers });
|
|
162
|
+
(0, bun_test_1.expect)(chains["1"].network).toBe("mainnet");
|
|
163
|
+
(0, bun_test_1.expect)(chains["11155111"].network).toBe("testnet");
|
|
164
|
+
(0, bun_test_1.expect)(issues).toEqual([]);
|
|
165
|
+
});
|
|
166
|
+
(0, bun_test_1.it)("overwrites any network the jsonnet happens to carry, so the maps stay the one source", () => {
|
|
167
|
+
const { chains } = (0, validation_1.classifyChainNetworks)({ "1": validChain({ network: "testnet" }) }, { "1": providers }, {});
|
|
168
|
+
(0, bun_test_1.expect)(chains["1"].network).toBe("mainnet");
|
|
169
|
+
});
|
|
170
|
+
// The silent-miss case this guard exists for: an unclassified chain would
|
|
171
|
+
// otherwise reach the signed artifact with no way for a consumer to place it.
|
|
172
|
+
(0, bun_test_1.it)("errors when a chain is in neither network map", () => {
|
|
173
|
+
const { chains, issues } = (0, validation_1.classifyChainNetworks)({ "1": validChain() }, {}, {});
|
|
174
|
+
(0, bun_test_1.expect)(issues).toHaveLength(1);
|
|
175
|
+
(0, bun_test_1.expect)(issues[0].severity).toBe("error");
|
|
176
|
+
(0, bun_test_1.expect)(issues[0].chainId).toBe("1");
|
|
177
|
+
(0, bun_test_1.expect)(issues[0].message).toContain("neither");
|
|
178
|
+
(0, bun_test_1.expect)(chains["1"].network).toBeUndefined();
|
|
179
|
+
});
|
|
180
|
+
(0, bun_test_1.it)("errors when a chain is in both network maps", () => {
|
|
181
|
+
const { issues } = (0, validation_1.classifyChainNetworks)({ "1": validChain() }, { "1": providers }, { "1": providers });
|
|
182
|
+
(0, bun_test_1.expect)(issues).toHaveLength(1);
|
|
183
|
+
(0, bun_test_1.expect)(issues[0].severity).toBe("error");
|
|
184
|
+
(0, bun_test_1.expect)(issues[0].message).toContain("both");
|
|
185
|
+
});
|
|
186
|
+
(0, bun_test_1.it)("warns when a network map lists a chain the registry does not define", () => {
|
|
187
|
+
const { issues } = (0, validation_1.classifyChainNetworks)({ "1": validChain() }, { "1": providers, "999999": providers }, {});
|
|
188
|
+
(0, bun_test_1.expect)(issues).toHaveLength(1);
|
|
189
|
+
(0, bun_test_1.expect)(issues[0].severity).toBe("warning");
|
|
190
|
+
(0, bun_test_1.expect)(issues[0].chainId).toBe("999999");
|
|
191
|
+
(0, bun_test_1.expect)(issues[0].message).toContain("absent from the chain registry");
|
|
192
|
+
});
|
|
193
|
+
// The artifact is signed over these exact bytes, so the serialisation has to
|
|
194
|
+
// stay canonical rather than depending on where the field was spliced in.
|
|
195
|
+
(0, bun_test_1.it)("keeps entry keys sorted so the generated JSON stays canonical", () => {
|
|
196
|
+
const { chains } = (0, validation_1.classifyChainNetworks)({ "1": validChain() }, { "1": providers }, {});
|
|
197
|
+
const keys = Object.keys(chains["1"]);
|
|
198
|
+
(0, bun_test_1.expect)(keys).toEqual([...keys].sort());
|
|
199
|
+
(0, bun_test_1.expect)(keys).toContain("network");
|
|
200
|
+
});
|
|
201
|
+
(0, bun_test_1.it)("classifies the real registry with no issues", () => {
|
|
202
|
+
// Round-trips the shipped registry through its own maps: every real chain
|
|
203
|
+
// must land in exactly one, which is what makes the field derivable at all.
|
|
204
|
+
const mainnets = Object.fromEntries(Object.entries(index_1.chainRegistry)
|
|
205
|
+
.filter(([, c]) => c.network === "mainnet")
|
|
206
|
+
.map(([id]) => [id, providers]));
|
|
207
|
+
const testnets = Object.fromEntries(Object.entries(index_1.chainRegistry)
|
|
208
|
+
.filter(([, c]) => c.network === "testnet")
|
|
209
|
+
.map(([id]) => [id, providers]));
|
|
210
|
+
const { chains, issues } = (0, validation_1.classifyChainNetworks)(index_1.chainRegistry, mainnets, testnets);
|
|
211
|
+
(0, bun_test_1.expect)(issues).toEqual([]);
|
|
212
|
+
(0, bun_test_1.expect)(Object.keys(mainnets).length).toBeGreaterThan(0);
|
|
213
|
+
(0, bun_test_1.expect)(Object.keys(testnets).length).toBeGreaterThan(0);
|
|
214
|
+
(0, bun_test_1.expect)(Object.keys(chains)).toHaveLength(Object.keys(index_1.chainRegistry).length);
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
(0, bun_test_1.describe)("classifyChainStacks", () => {
|
|
218
|
+
const nets = (mainnets, testnets = []) => ({ mainnets, testnets });
|
|
219
|
+
// The common case: nothing is authored anywhere. viem already knows what Base
|
|
220
|
+
// is, so the value is read off its definition and cannot drift from it.
|
|
221
|
+
(0, bun_test_1.it)("derives the stack from viem's own chain definition", () => {
|
|
222
|
+
const { chains, issues } = (0, validation_1.classifyChainStacks)({ "8453": validChain({ name: "Base" }), "42161": validChain({ name: "Arbitrum One" }) }, nets([
|
|
223
|
+
{ id: 8453, viemChain: "base" },
|
|
224
|
+
{ id: 42161, viemChain: "arbitrum" },
|
|
225
|
+
]));
|
|
226
|
+
(0, bun_test_1.expect)(chains["8453"].stack).toBe("op-stack");
|
|
227
|
+
// viem's arbitrum carries no formatters — Orbit is genuinely vanilla here.
|
|
228
|
+
(0, bun_test_1.expect)(chains["42161"].stack).toBe("vanilla");
|
|
229
|
+
(0, bun_test_1.expect)(issues).toEqual([]);
|
|
230
|
+
});
|
|
231
|
+
// The whole reason the field exists, and the reason it is not defaulted: this
|
|
232
|
+
// is the shape of a chain added faster than viem ships it, and guessing
|
|
233
|
+
// "vanilla" for an OP-stack L2 would misprice its gas with no error anywhere.
|
|
234
|
+
(0, bun_test_1.it)("refuses to guess for an EVM chain viem does not ship", () => {
|
|
235
|
+
const { chains, issues } = (0, validation_1.classifyChainStacks)({ "1234": validChain({ name: "Newchain" }) }, nets([{ id: 1234 }]));
|
|
236
|
+
(0, bun_test_1.expect)(chains["1234"].stack).toBeUndefined();
|
|
237
|
+
(0, bun_test_1.expect)(issues).toHaveLength(1);
|
|
238
|
+
(0, bun_test_1.expect)(issues[0].severity).toBe("error");
|
|
239
|
+
(0, bun_test_1.expect)(issues[0].message).toContain("author `stack`");
|
|
240
|
+
});
|
|
241
|
+
(0, bun_test_1.it)("takes the authored stack for a chain viem does not ship", () => {
|
|
242
|
+
const { chains, issues } = (0, validation_1.classifyChainStacks)({ "1234": validChain({ name: "Newchain" }) }, nets([{ id: 1234, stack: "op-stack" }]));
|
|
243
|
+
(0, bun_test_1.expect)(chains["1234"].stack).toBe("op-stack");
|
|
244
|
+
(0, bun_test_1.expect)(issues).toEqual([]);
|
|
245
|
+
});
|
|
246
|
+
(0, bun_test_1.it)("rejects an authored value outside the union", () => {
|
|
247
|
+
const { chains, issues } = (0, validation_1.classifyChainStacks)({ "1234": validChain({ name: "Newchain" }) }, nets([{ id: 1234, stack: "orbit" }]));
|
|
248
|
+
(0, bun_test_1.expect)(chains["1234"].stack).toBeUndefined();
|
|
249
|
+
(0, bun_test_1.expect)(issues[0]?.message).toContain('"orbit" is not one of');
|
|
250
|
+
});
|
|
251
|
+
// Authoring may agree with viem, never override it: for a chain viem ships,
|
|
252
|
+
// viem's definition is what the consumer actually uses.
|
|
253
|
+
(0, bun_test_1.it)("rejects an authored stack that contradicts viem", () => {
|
|
254
|
+
const { issues } = (0, validation_1.classifyChainStacks)({ "8453": validChain({ name: "Base" }) }, nets([{ id: 8453, viemChain: "base", stack: "vanilla" }]));
|
|
255
|
+
(0, bun_test_1.expect)(issues[0]?.severity).toBe("error");
|
|
256
|
+
(0, bun_test_1.expect)(issues[0]?.message).toContain("contradicts viem");
|
|
257
|
+
});
|
|
258
|
+
(0, bun_test_1.it)("errors when viemChain names an export viem does not have", () => {
|
|
259
|
+
const { issues } = (0, validation_1.classifyChainStacks)({ "1234": validChain({ name: "Nope" }) }, nets([{ id: 1234, viemChain: "definitelyNotAChain" }]));
|
|
260
|
+
(0, bun_test_1.expect)(issues[0]?.message).toContain("no export");
|
|
261
|
+
});
|
|
262
|
+
// Non-EVM and virtual chains are never built as viem chains, so they must not
|
|
263
|
+
// be forced to declare a stack — that would be authoring noise on 3 of 24
|
|
264
|
+
// entries for a value nothing reads.
|
|
265
|
+
(0, bun_test_1.it)("stamps vanilla for non-EVM and virtual chains without authoring", () => {
|
|
266
|
+
const { chains, issues } = (0, validation_1.classifyChainStacks)({
|
|
267
|
+
"792703809": validChain({ name: "Solana", vmType: "svm" }),
|
|
268
|
+
"1337": validChain({ name: "HyperCore", virtual: true }),
|
|
269
|
+
}, nets([{ id: 792703809 }, { id: 1337 }]));
|
|
270
|
+
(0, bun_test_1.expect)(chains["792703809"].stack).toBe("vanilla");
|
|
271
|
+
(0, bun_test_1.expect)(chains["1337"].stack).toBe("vanilla");
|
|
272
|
+
(0, bun_test_1.expect)(issues).toEqual([]);
|
|
273
|
+
});
|
|
274
|
+
// Same invariant classifyChainNetworks holds for `network`: the field is
|
|
275
|
+
// present if and only if it was derived here, so the structural check in
|
|
276
|
+
// validateChainConfig stays an independent second gate rather than re-reading
|
|
277
|
+
// whatever the jsonnet happened to emit.
|
|
278
|
+
(0, bun_test_1.it)("ignores a stack carried in on the input, including when it then fails", () => {
|
|
279
|
+
const { chains } = (0, validation_1.classifyChainStacks)({ "8453": validChain({ name: "Base", stack: "zksync" }) }, nets([{ id: 8453, viemChain: "base" }]));
|
|
280
|
+
(0, bun_test_1.expect)(chains["8453"].stack).toBe("op-stack");
|
|
281
|
+
const { chains: failed } = (0, validation_1.classifyChainStacks)({ "1234": validChain({ name: "Newchain", stack: "op-stack" }) }, nets([{ id: 1234 }]));
|
|
282
|
+
(0, bun_test_1.expect)(failed["1234"].stack).toBeUndefined();
|
|
283
|
+
});
|
|
284
|
+
(0, bun_test_1.it)("stamps every chain in the real registry", () => {
|
|
285
|
+
const { chains, issues } = (0, validation_1.classifyChainStacks)(index_1.chainRegistry,
|
|
286
|
+
// The real network entries are not exported, so re-derive from the
|
|
287
|
+
// registry: every EVM chain in it is one viem ships today, which is the
|
|
288
|
+
// property that keeps the field authored nowhere.
|
|
289
|
+
nets(Object.keys(index_1.chainRegistry).map((id) => ({
|
|
290
|
+
id: Number(id),
|
|
291
|
+
stack: "vanilla",
|
|
292
|
+
}))));
|
|
293
|
+
(0, bun_test_1.expect)(issues.filter((i) => i.severity === "error")).toEqual([]);
|
|
294
|
+
for (const entry of Object.values(chains)) {
|
|
295
|
+
(0, bun_test_1.expect)(entry.stack).toBeDefined();
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
});
|
package/dist/scripts/generate.js
CHANGED
|
@@ -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, ChainStack, 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,10 @@ 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;",
|
|
117
|
+
" /** Execution stack, for consumers that must synthesise a viem `Chain`. */",
|
|
118
|
+
" stack: ChainStack;",
|
|
115
119
|
" /** CAIP-2 chain identifier; populated for non-eip155 chains only. */",
|
|
116
120
|
" caip2?: string;",
|
|
117
121
|
" /** True for virtual chains (e.g. HyperCore) that settle on another chain. */",
|
|
@@ -354,14 +358,30 @@ async function generate() {
|
|
|
354
358
|
const output = runJsonnet(yeetRoot);
|
|
355
359
|
await (0, promises_1.mkdir)(configsDir, { recursive: true });
|
|
356
360
|
await (0, promises_1.mkdir)(generatedDir, { recursive: true });
|
|
357
|
-
|
|
361
|
+
// Stamp mainnet/testnet onto each entry before anything is written, so the
|
|
362
|
+
// registry that reaches configs/chains.json — and from there the published
|
|
363
|
+
// facts artifact and the read-client's bundled fallback — carries the
|
|
364
|
+
// classification rather than leaving it implicit in the network maps.
|
|
365
|
+
const { chains: networkClassified, issues: networkIssues } = (0, validation_1.classifyChainNetworks)(output.chains, output.mainnets, output.testnets);
|
|
366
|
+
// Then the execution stack, for consumers that have to build a viem `Chain`
|
|
367
|
+
// themselves because the chain postdates their pinned viem.
|
|
368
|
+
const { chains: classifiedChains, issues: stackIssues } = (0, validation_1.classifyChainStacks)(networkClassified, output.networks);
|
|
369
|
+
const classificationIssues = [...networkIssues, ...stackIssues];
|
|
370
|
+
await (0, promises_1.writeFile)(node_path_1.default.join(configsDir, "chains.json"), `${JSON.stringify(classifiedChains, null, 2)}\n`);
|
|
358
371
|
await (0, promises_1.writeFile)(node_path_1.default.join(configsDir, "mainnets.json"), `${JSON.stringify(output.mainnets, null, 2)}\n`);
|
|
359
372
|
await (0, promises_1.writeFile)(node_path_1.default.join(configsDir, "testnets.json"), `${JSON.stringify(output.testnets, null, 2)}\n`);
|
|
360
373
|
await (0, promises_1.writeFile)(node_path_1.default.join(configsDir, "providers.json"), `${JSON.stringify(output.providers, null, 2)}\n`);
|
|
361
374
|
await (0, promises_1.writeFile)(node_path_1.default.join(configsDir, "oft.json"), `${JSON.stringify(output.oft, null, 2)}\n`);
|
|
362
375
|
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
|
-
|
|
376
|
+
// Validate chain configuration. Classification problems are reported in the
|
|
377
|
+
// same pass so one run surfaces everything wrong with the registry, rather than
|
|
378
|
+
// failing on the partition and hiding the rest.
|
|
379
|
+
const structural = (0, validation_1.validateChainConfig)(classifiedChains);
|
|
380
|
+
const validationResult = {
|
|
381
|
+
issues: [...classificationIssues, ...structural.issues],
|
|
382
|
+
hasErrors: structural.hasErrors ||
|
|
383
|
+
classificationIssues.some((issue) => issue.severity === 'error'),
|
|
384
|
+
};
|
|
365
385
|
const validationOutput = (0, validation_1.formatValidationIssues)(validationResult);
|
|
366
386
|
if (validationOutput) {
|
|
367
387
|
console.log('\nChain config validation:');
|
|
@@ -371,7 +391,13 @@ async function generate() {
|
|
|
371
391
|
if (validationResult.hasErrors) {
|
|
372
392
|
throw new Error('Chain configuration has errors — see above');
|
|
373
393
|
}
|
|
374
|
-
await (0, promises_1.writeFile)(node_path_1.default.join(sharedConfigsRoot, "src", "chains.ts"), `${renderChains(
|
|
394
|
+
await (0, promises_1.writeFile)(node_path_1.default.join(sharedConfigsRoot, "src", "chains.ts"), `${renderChains(classifiedChains, output.mainnets, output.testnets)}\n`);
|
|
395
|
+
// Stamp the package version so the read-client knows how fresh its BUNDLED
|
|
396
|
+
// registry is, and can refuse a remote artifact from an older release. The
|
|
397
|
+
// release workflow bumps package.json before building for exactly this
|
|
398
|
+
// reason — see shared-configs-publish.yml.
|
|
399
|
+
const packageVersion = JSON.parse(await (0, promises_1.readFile)(node_path_1.default.join(sharedConfigsRoot, "package.json"), "utf8")).version;
|
|
400
|
+
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
401
|
await (0, promises_1.writeFile)(node_path_1.default.join(generatedDir, "networks.ts"), `${renderNetworks(output.networks)}\n`);
|
|
376
402
|
const prodAddrConfig = runOrchestratorFile(yeetRoot, "prod", output.chainNames);
|
|
377
403
|
const stagingAddrConfig = runOrchestratorFile(yeetRoot, "staging", output.chainNames);
|