@keplr-wallet/chain-validator 0.11.18-alpha.1

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,1172 @@
1
+ import assert from "assert";
2
+ import {
3
+ Bech32ConfigSchema,
4
+ ChainInfoSchema,
5
+ CurrencySchema,
6
+ CW20CurrencySchema,
7
+ FeeCurrencySchema,
8
+ Secret20CurrencySchema,
9
+ } from "./schema";
10
+ import {
11
+ AppCurrency,
12
+ ChainInfo,
13
+ Currency,
14
+ CW20Currency,
15
+ FeeCurrency,
16
+ Secret20Currency,
17
+ } from "@keplr-wallet/types";
18
+ import { Bech32Config } from "@keplr-wallet/types";
19
+ import Joi from "joi";
20
+ import { Mutable } from "utility-types";
21
+
22
+ const AppCurrencySchemaTest = Joi.array().items(
23
+ CurrencySchema,
24
+ CW20CurrencySchema
25
+ );
26
+
27
+ /* eslint-disable @typescript-eslint/ban-ts-comment */
28
+
29
+ describe("Test chain info schema", () => {
30
+ it("test currency schema", async () => {
31
+ await assert.doesNotReject(async () => {
32
+ const currency: Currency = {
33
+ coinDenom: "TEST",
34
+ coinMinimalDenom: "utest",
35
+ coinDecimals: 6,
36
+ };
37
+
38
+ await CurrencySchema.validateAsync(currency);
39
+ });
40
+
41
+ await assert.doesNotReject(async () => {
42
+ const currency: Currency = {
43
+ coinDenom: "TEST",
44
+ coinMinimalDenom: "utest",
45
+ coinDecimals: 18,
46
+ };
47
+
48
+ await CurrencySchema.validateAsync(currency);
49
+ });
50
+
51
+ await assert.doesNotReject(async () => {
52
+ const currency: Currency = {
53
+ coinDenom: "TEST",
54
+ coinMinimalDenom: "utest",
55
+ coinDecimals: 0,
56
+ };
57
+
58
+ await CurrencySchema.validateAsync(currency);
59
+ });
60
+
61
+ await assert.doesNotReject(async () => {
62
+ const currency: Currency = {
63
+ coinDenom: "TEST",
64
+ coinMinimalDenom: "utest",
65
+ coinDecimals: 6,
66
+ coinGeckoId: "test",
67
+ };
68
+
69
+ await CurrencySchema.validateAsync(currency);
70
+ });
71
+
72
+ await assert.doesNotReject(async () => {
73
+ const currency: Currency = {
74
+ coinDenom: "TEST",
75
+ coinMinimalDenom: "utest",
76
+ coinDecimals: 6,
77
+ coinGeckoId: "test",
78
+ coinImageUrl: "http://test.com/test.jpg",
79
+ };
80
+
81
+ await CurrencySchema.validateAsync(currency);
82
+ });
83
+
84
+ await assert.rejects(async () => {
85
+ const currency: Currency = {
86
+ coinDenom: "TEST",
87
+ coinMinimalDenom: "utest",
88
+ coinDecimals: 6,
89
+ coinGeckoId: "test",
90
+ coinImageUrl: "",
91
+ };
92
+
93
+ await CurrencySchema.validateAsync(currency);
94
+ }, "Should throw error if coin image url is empty string");
95
+
96
+ await assert.rejects(async () => {
97
+ const currency: Currency = {
98
+ coinDenom: "TEST",
99
+ coinMinimalDenom: "utest",
100
+ coinDecimals: 6,
101
+ coinGeckoId: "test",
102
+ coinImageUrl: "test",
103
+ };
104
+
105
+ await CurrencySchema.validateAsync(currency);
106
+ }, "Should throw error if coin image url is not url");
107
+
108
+ await assert.rejects(async () => {
109
+ // @ts-ignore
110
+ const currency: Currency = {
111
+ // coinDenom: "TEST",
112
+ coinMinimalDenom: "utest",
113
+ coinDecimals: 6,
114
+ coinGeckoId: "test",
115
+ };
116
+
117
+ await CurrencySchema.validateAsync(currency);
118
+ }, "Should throw error when coin denom is missing");
119
+
120
+ await assert.rejects(async () => {
121
+ // @ts-ignore
122
+ const currency: Currency = {
123
+ coinDenom: "TEST",
124
+ // coinMinimalDenom: "utest",
125
+ coinDecimals: 6,
126
+ };
127
+
128
+ await CurrencySchema.validateAsync(currency);
129
+ }, "Should throw error when coin minimal denom is missing");
130
+
131
+ await assert.rejects(async () => {
132
+ // @ts-ignore
133
+ const currency: Currency = {
134
+ coinDenom: "TEST",
135
+ coinMinimalDenom: "utest",
136
+ // coinDecimals: 6,
137
+ };
138
+
139
+ await CurrencySchema.validateAsync(currency);
140
+ }, "Should throw error when coin decimals is missing");
141
+
142
+ await assert.rejects(async () => {
143
+ const currency: Currency = {
144
+ coinDenom: "TEST",
145
+ coinMinimalDenom: "utest",
146
+ // @ts-ignore
147
+ coinDecimals: "should number",
148
+ };
149
+
150
+ await CurrencySchema.validateAsync(currency);
151
+ }, "Should throw error when coin decimals is not number");
152
+
153
+ await assert.rejects(async () => {
154
+ const currency: Currency = {
155
+ coinDenom: "TEST",
156
+ coinMinimalDenom: "utest",
157
+ coinDecimals: 6,
158
+ // @ts-ignore
159
+ coinGeckoId: 45,
160
+ };
161
+
162
+ await CurrencySchema.validateAsync(currency);
163
+ }, "Should throw error when coingecko id is not string");
164
+
165
+ await assert.rejects(async () => {
166
+ const currency: Currency = {
167
+ coinDenom: "TEST",
168
+ coinMinimalDenom: "utest",
169
+ coinDecimals: 19,
170
+ };
171
+
172
+ await CurrencySchema.validateAsync(currency);
173
+ }, "Should throw error when coin decimal is too big");
174
+
175
+ await assert.rejects(async () => {
176
+ const currency: Currency = {
177
+ coinDenom: "TEST",
178
+ coinMinimalDenom: "utest",
179
+ coinDecimals: -1,
180
+ };
181
+
182
+ await CurrencySchema.validateAsync(currency);
183
+ }, "Should throw error when coin decimal is negative");
184
+
185
+ await assert.rejects(async () => {
186
+ const currency: Currency = {
187
+ coinDenom: "TEST",
188
+ coinMinimalDenom: "utest",
189
+ coinDecimals: 1.5,
190
+ };
191
+
192
+ await CurrencySchema.validateAsync(currency);
193
+ }, "Should throw error when coin decimal is not integer");
194
+
195
+ await assert.doesNotReject(async () => {
196
+ let currency: CW20Currency = {
197
+ type: "cw20",
198
+ contractAddress: "this should be validated in the keeper",
199
+ coinDenom: "TEST",
200
+ coinMinimalDenom: "utest",
201
+ coinDecimals: 0,
202
+ };
203
+
204
+ currency = await CW20CurrencySchema.validateAsync(currency);
205
+ if (
206
+ currency.coinMinimalDenom !==
207
+ "cw20:this should be validated in the keeper:utest"
208
+ ) {
209
+ throw new Error(
210
+ "actual denom doens't start with `type:contract-address:`"
211
+ );
212
+ }
213
+ });
214
+
215
+ await assert.doesNotReject(async () => {
216
+ let currency: CW20Currency = {
217
+ type: "cw20",
218
+ contractAddress: "this should be validated in the keeper",
219
+ coinDenom: "TEST",
220
+ coinMinimalDenom: "cw20:this should be validated in the keeper:utest",
221
+ coinDecimals: 0,
222
+ };
223
+
224
+ currency = await CW20CurrencySchema.validateAsync(currency);
225
+ if (
226
+ currency.coinMinimalDenom !==
227
+ "cw20:this should be validated in the keeper:utest"
228
+ ) {
229
+ throw new Error(
230
+ "actual denom doens't start with `type:contract-address:`"
231
+ );
232
+ }
233
+ });
234
+
235
+ await assert.rejects(async () => {
236
+ const currency: CW20Currency = {
237
+ // @ts-ignore
238
+ type: "?",
239
+ contractAddress: "this should be validated in the keeper",
240
+ coinDenom: "TEST",
241
+ coinMinimalDenom: "utest",
242
+ coinDecimals: 0,
243
+ };
244
+
245
+ await CW20CurrencySchema.validateAsync(currency);
246
+ }, "Should throw error when type is not cw20");
247
+
248
+ await assert.rejects(async () => {
249
+ // @ts-ignore
250
+ const currency: CW20Currency = {
251
+ contractAddress: "this should be validated in the keeper",
252
+ coinDenom: "TEST",
253
+ coinMinimalDenom: "utest",
254
+ coinDecimals: 0,
255
+ };
256
+
257
+ await CW20CurrencySchema.validateAsync(currency);
258
+ }, "Should throw error when type is missing");
259
+
260
+ await assert.rejects(async () => {
261
+ // @ts-ignore
262
+ const currency: CW20Currency = {
263
+ type: "cw20",
264
+ coinDenom: "TEST",
265
+ coinMinimalDenom: "utest",
266
+ coinDecimals: 0,
267
+ };
268
+
269
+ await CW20CurrencySchema.validateAsync(currency);
270
+ }, "Should throw error when contract address is missing");
271
+
272
+ await assert.doesNotReject(async () => {
273
+ let currency: Secret20Currency = {
274
+ type: "secret20",
275
+ contractAddress: "this should be validated in the keeper",
276
+ viewingKey: "Test viewingKey",
277
+ coinDenom: "TEST",
278
+ coinMinimalDenom: "utest",
279
+ coinDecimals: 0,
280
+ };
281
+
282
+ currency = await Secret20CurrencySchema.validateAsync(currency);
283
+ if (
284
+ currency.coinMinimalDenom !==
285
+ "secret20:this should be validated in the keeper:utest"
286
+ ) {
287
+ throw new Error(
288
+ "actual denom doens't start with `type:contract-address:`"
289
+ );
290
+ }
291
+ });
292
+
293
+ await assert.doesNotReject(async () => {
294
+ let currency: Secret20Currency = {
295
+ type: "secret20",
296
+ contractAddress: "this should be validated in the keeper",
297
+ viewingKey: "Test viewingKey",
298
+ coinDenom: "TEST",
299
+ coinMinimalDenom:
300
+ "secret20:this should be validated in the keeper:utest",
301
+ coinDecimals: 0,
302
+ };
303
+
304
+ currency = await Secret20CurrencySchema.validateAsync(currency);
305
+ if (
306
+ currency.coinMinimalDenom !==
307
+ "secret20:this should be validated in the keeper:utest"
308
+ ) {
309
+ throw new Error(
310
+ "actual denom doens't start with `type:contract-address:`"
311
+ );
312
+ }
313
+ });
314
+
315
+ await assert.rejects(async () => {
316
+ const currency: Secret20Currency = {
317
+ // @ts-ignore
318
+ type: "?",
319
+ contractAddress: "this should be validated in the keeper",
320
+ coinDenom: "TEST",
321
+ coinMinimalDenom: "utest",
322
+ coinDecimals: 0,
323
+ };
324
+
325
+ await Secret20CurrencySchema.validateAsync(currency);
326
+ }, "Should throw error when type is not secret20");
327
+
328
+ await assert.rejects(async () => {
329
+ // @ts-ignore
330
+ const currency: Secret20Currency = {
331
+ contractAddress: "this should be validated in the keeper",
332
+ coinDenom: "TEST",
333
+ coinMinimalDenom: "utest",
334
+ coinDecimals: 0,
335
+ };
336
+
337
+ await Secret20CurrencySchema.validateAsync(currency);
338
+ }, "Should throw error when type is missing");
339
+
340
+ await assert.rejects(async () => {
341
+ // @ts-ignore
342
+ const currency: Secret20Currency = {
343
+ type: "secret20",
344
+ coinDenom: "TEST",
345
+ coinMinimalDenom: "utest",
346
+ coinDecimals: 0,
347
+ };
348
+
349
+ await Secret20CurrencySchema.validateAsync(currency);
350
+ }, "Should throw error when contract address is missing");
351
+
352
+ await assert.doesNotReject(async () => {
353
+ let currency: AppCurrency = {
354
+ type: "cw20",
355
+ contractAddress: "this should be validated in the keeper",
356
+ coinDenom: "TEST",
357
+ coinMinimalDenom: "utest",
358
+ coinDecimals: 0,
359
+ };
360
+
361
+ const currencies = await AppCurrencySchemaTest.validateAsync([currency]);
362
+ if (
363
+ currencies[0].coinMinimalDenom !==
364
+ "cw20:this should be validated in the keeper:utest"
365
+ ) {
366
+ throw new Error(
367
+ "actual denom doens't start with `cw20:contract-address:`"
368
+ );
369
+ }
370
+
371
+ currency = {
372
+ coinDenom: "TEST",
373
+ coinMinimalDenom: "utest",
374
+ coinDecimals: 6,
375
+ coinGeckoId: "test",
376
+ };
377
+
378
+ await AppCurrencySchemaTest.validateAsync([currency]);
379
+ });
380
+
381
+ await assert.rejects(async () => {
382
+ // @ts-ignore
383
+ const currency: CW20Currency = {
384
+ type: "cw20",
385
+ coinDenom: "TEST",
386
+ coinMinimalDenom: "utest",
387
+ coinDecimals: 0,
388
+ };
389
+
390
+ await AppCurrencySchemaTest.validateAsync([currency]);
391
+ }, "Should throw error when contract address is missing");
392
+
393
+ await assert.rejects(async () => {
394
+ const currency: Currency = {
395
+ coinDenom: "TEST",
396
+ coinMinimalDenom: "utest",
397
+ coinDecimals: 1.5,
398
+ };
399
+
400
+ await AppCurrencySchemaTest.validateAsync([currency]);
401
+ }, "Should throw error when coin decimal is not integer");
402
+ });
403
+
404
+ it("test fee currency schema", async () => {
405
+ await assert.doesNotReject(async () => {
406
+ const currency: FeeCurrency = {
407
+ coinDenom: "TEST",
408
+ coinMinimalDenom: "utest",
409
+ coinDecimals: 0,
410
+ };
411
+
412
+ await FeeCurrencySchema.validateAsync(currency);
413
+ });
414
+
415
+ await assert.doesNotReject(async () => {
416
+ let currency: FeeCurrency = {
417
+ coinDenom: "TEST",
418
+ coinMinimalDenom: "utest",
419
+ coinDecimals: 0,
420
+ gasPriceStep: {
421
+ low: 0.1,
422
+ average: 0.2,
423
+ high: 0.3,
424
+ },
425
+ };
426
+
427
+ await FeeCurrencySchema.validateAsync(currency);
428
+
429
+ currency = {
430
+ coinDenom: "TEST",
431
+ coinMinimalDenom: "utest",
432
+ coinDecimals: 0,
433
+ gasPriceStep: {
434
+ low: 0.2,
435
+ average: 0.2,
436
+ high: 0.3,
437
+ },
438
+ };
439
+
440
+ await FeeCurrencySchema.validateAsync(currency);
441
+
442
+ currency = {
443
+ coinDenom: "TEST",
444
+ coinMinimalDenom: "utest",
445
+ coinDecimals: 0,
446
+ gasPriceStep: {
447
+ low: 0.2,
448
+ average: 0.3,
449
+ high: 0.3,
450
+ },
451
+ };
452
+
453
+ await FeeCurrencySchema.validateAsync(currency);
454
+
455
+ currency = {
456
+ coinDenom: "TEST",
457
+ coinMinimalDenom: "utest",
458
+ coinDecimals: 0,
459
+ gasPriceStep: {
460
+ low: 0.3,
461
+ average: 0.3,
462
+ high: 0.3,
463
+ },
464
+ };
465
+
466
+ await FeeCurrencySchema.validateAsync(currency);
467
+
468
+ currency = {
469
+ coinDenom: "TEST",
470
+ coinMinimalDenom: "utest",
471
+ coinDecimals: 0,
472
+ gasPriceStep: {
473
+ low: 0,
474
+ average: 0,
475
+ high: 0,
476
+ },
477
+ };
478
+
479
+ await FeeCurrencySchema.validateAsync(currency);
480
+ });
481
+
482
+ await assert.rejects(async () => {
483
+ const currency: FeeCurrency = {
484
+ coinDenom: "TEST",
485
+ coinMinimalDenom: "utest",
486
+ coinDecimals: 0,
487
+ // @ts-ignore
488
+ gasPriceStep: {
489
+ low: 0.1,
490
+ },
491
+ };
492
+
493
+ await FeeCurrencySchema.validateAsync(currency);
494
+ }, "should reject if gas price step is incomplete");
495
+
496
+ await assert.rejects(async () => {
497
+ const currency: FeeCurrency = {
498
+ coinDenom: "TEST",
499
+ coinMinimalDenom: "utest",
500
+ coinDecimals: 0,
501
+ gasPriceStep: {
502
+ low: 0.3,
503
+ average: 0.2,
504
+ high: 0.3,
505
+ },
506
+ };
507
+
508
+ await FeeCurrencySchema.validateAsync(currency);
509
+ }, "should reject if low in gas price step is greater than average");
510
+
511
+ await assert.rejects(async () => {
512
+ const currency: FeeCurrency = {
513
+ coinDenom: "TEST",
514
+ coinMinimalDenom: "utest",
515
+ coinDecimals: 0,
516
+ gasPriceStep: {
517
+ low: 0.1,
518
+ average: 0.3,
519
+ high: 0.2,
520
+ },
521
+ };
522
+
523
+ await FeeCurrencySchema.validateAsync(currency);
524
+ }, "should reject if average in gas price step is greater than high");
525
+
526
+ await assert.rejects(async () => {
527
+ const currency: FeeCurrency = {
528
+ type: "cw20",
529
+ contractAddress:
530
+ "tokens like CW20/IBC etc... can not be fee currency yet",
531
+ coinDenom: "TEST",
532
+ coinMinimalDenom: "utest",
533
+ coinDecimals: 0,
534
+ };
535
+
536
+ await FeeCurrencySchema.validateAsync(currency);
537
+ });
538
+ });
539
+
540
+ it("test bech32 config schema", async () => {
541
+ await assert.doesNotReject(async () => {
542
+ const bech32Config: Bech32Config = {
543
+ bech32PrefixAccAddr: "test",
544
+ bech32PrefixAccPub: "test",
545
+ bech32PrefixValAddr: "test",
546
+ bech32PrefixValPub: "test",
547
+ bech32PrefixConsAddr: "test",
548
+ bech32PrefixConsPub: "test",
549
+ };
550
+
551
+ await Bech32ConfigSchema.validateAsync(bech32Config);
552
+ });
553
+
554
+ const validateNullField = async <K extends keyof Bech32Config>(
555
+ field: K
556
+ ) => {
557
+ const bech32Config: Bech32Config = {
558
+ bech32PrefixAccAddr: "test",
559
+ bech32PrefixAccPub: "test",
560
+ bech32PrefixValAddr: "test",
561
+ bech32PrefixValPub: "test",
562
+ bech32PrefixConsAddr: "test",
563
+ bech32PrefixConsPub: "test",
564
+ };
565
+
566
+ // @ts-ignore
567
+ bech32Config[field] = undefined;
568
+
569
+ await Bech32ConfigSchema.validateAsync(bech32Config);
570
+ };
571
+
572
+ const validateNonStringField = async <K extends keyof Bech32Config>(
573
+ field: K
574
+ ) => {
575
+ const bech32Config: Bech32Config = {
576
+ bech32PrefixAccAddr: "test",
577
+ bech32PrefixAccPub: "test",
578
+ bech32PrefixValAddr: "test",
579
+ bech32PrefixValPub: "test",
580
+ bech32PrefixConsAddr: "test",
581
+ bech32PrefixConsPub: "test",
582
+ };
583
+
584
+ // @ts-ignore
585
+ bech32Config[field] = 123;
586
+
587
+ await Bech32ConfigSchema.validateAsync(bech32Config);
588
+ };
589
+
590
+ await assert.rejects(async () => {
591
+ await validateNullField("bech32PrefixAccAddr");
592
+ });
593
+
594
+ await assert.rejects(async () => {
595
+ await validateNullField("bech32PrefixAccPub");
596
+ });
597
+
598
+ await assert.rejects(async () => {
599
+ await validateNullField("bech32PrefixValAddr");
600
+ });
601
+
602
+ await assert.rejects(async () => {
603
+ await validateNullField("bech32PrefixValPub");
604
+ });
605
+
606
+ await assert.rejects(async () => {
607
+ await validateNullField("bech32PrefixConsAddr");
608
+ });
609
+
610
+ await assert.rejects(async () => {
611
+ await validateNullField("bech32PrefixConsPub");
612
+ });
613
+
614
+ await assert.rejects(async () => {
615
+ await validateNonStringField("bech32PrefixAccAddr");
616
+ });
617
+
618
+ await assert.rejects(async () => {
619
+ await validateNonStringField("bech32PrefixAccPub");
620
+ });
621
+
622
+ await assert.rejects(async () => {
623
+ await validateNonStringField("bech32PrefixValAddr");
624
+ });
625
+
626
+ await assert.rejects(async () => {
627
+ await validateNonStringField("bech32PrefixValPub");
628
+ });
629
+
630
+ await assert.rejects(async () => {
631
+ await validateNonStringField("bech32PrefixConsAddr");
632
+ });
633
+
634
+ await assert.rejects(async () => {
635
+ await validateNonStringField("bech32PrefixConsPub");
636
+ });
637
+ });
638
+
639
+ it("test chain info schema", async () => {
640
+ const generatePlainChainInfo = (): Mutable<ChainInfo> => {
641
+ return {
642
+ rpc: "http://test.com",
643
+ rest: "http://test.com",
644
+ chainId: "test-1",
645
+ chainName: "Test",
646
+ stakeCurrency: {
647
+ coinDenom: "TEST",
648
+ coinMinimalDenom: "utest",
649
+ coinDecimals: 6,
650
+ },
651
+ bip44: {
652
+ coinType: 118,
653
+ },
654
+ bech32Config: {
655
+ bech32PrefixAccAddr: "test",
656
+ bech32PrefixAccPub: "test",
657
+ bech32PrefixValAddr: "test",
658
+ bech32PrefixValPub: "test",
659
+ bech32PrefixConsAddr: "test",
660
+ bech32PrefixConsPub: "test",
661
+ },
662
+ currencies: [
663
+ {
664
+ coinDenom: "TEST",
665
+ coinMinimalDenom: "utest",
666
+ coinDecimals: 6,
667
+ },
668
+ ],
669
+ feeCurrencies: [
670
+ {
671
+ coinDenom: "TEST",
672
+ coinMinimalDenom: "utest",
673
+ coinDecimals: 6,
674
+ gasPriceStep: {
675
+ low: 0.1,
676
+ average: 0.2,
677
+ high: 0.3,
678
+ },
679
+ },
680
+ ],
681
+ chainSymbolImageUrl: "https://test.com/image.png",
682
+ };
683
+ };
684
+
685
+ await assert.doesNotReject(async () => {
686
+ const chainInfo = generatePlainChainInfo();
687
+
688
+ await ChainInfoSchema.validateAsync(chainInfo);
689
+ });
690
+
691
+ await assert.doesNotReject(async () => {
692
+ const plainChainInfo = generatePlainChainInfo();
693
+ const chainInfoWithUnknownField = {
694
+ ...plainChainInfo,
695
+ unknownField: "unknown",
696
+ };
697
+
698
+ // Should not reject the chain info with unknown field
699
+ const validated = await ChainInfoSchema.validateAsync(
700
+ chainInfoWithUnknownField,
701
+ {
702
+ stripUnknown: true,
703
+ }
704
+ );
705
+
706
+ // But, after being validated, the unknown field should be stripped.
707
+ assert.strictEqual(validated["unknownField"], undefined);
708
+ });
709
+
710
+ await assert.doesNotReject(async () => {
711
+ const chainInfo = generatePlainChainInfo();
712
+
713
+ await ChainInfoSchema.validateAsync({
714
+ ...chainInfo,
715
+ alternativeBIP44s: [],
716
+ });
717
+
718
+ await ChainInfoSchema.validateAsync({
719
+ ...chainInfo,
720
+ alternativeBIP44s: [
721
+ {
722
+ coinType: 119,
723
+ },
724
+ ],
725
+ });
726
+
727
+ await ChainInfoSchema.validateAsync({
728
+ ...chainInfo,
729
+ alternativeBIP44s: [
730
+ {
731
+ coinType: 119,
732
+ },
733
+ {
734
+ coinType: 120,
735
+ },
736
+ ],
737
+ });
738
+ });
739
+
740
+ await assert.rejects(async () => {
741
+ const chainInfo = generatePlainChainInfo();
742
+
743
+ await ChainInfoSchema.validateAsync({
744
+ ...chainInfo,
745
+ chainSymbolImageUrl: "not url",
746
+ });
747
+ });
748
+
749
+ await assert.rejects(async () => {
750
+ const chainInfo = generatePlainChainInfo();
751
+
752
+ await ChainInfoSchema.validateAsync({
753
+ ...chainInfo,
754
+ alternativeBIP44s: [
755
+ {
756
+ // Duplicated with chainInfo.bip44.coinType
757
+ coinType: 118,
758
+ },
759
+ {
760
+ coinType: 120,
761
+ },
762
+ ],
763
+ });
764
+ }, "should reject if duplication exists in bip44");
765
+
766
+ await assert.rejects(async () => {
767
+ const chainInfo = generatePlainChainInfo();
768
+
769
+ await ChainInfoSchema.validateAsync({
770
+ ...chainInfo,
771
+ alternativeBIP44s: [
772
+ {
773
+ coinType: 119,
774
+ },
775
+ {
776
+ coinType: 119,
777
+ },
778
+ ],
779
+ });
780
+ }, "should reject if duplication exists in bip44");
781
+
782
+ await assert.doesNotReject(async () => {
783
+ const chainInfo = generatePlainChainInfo();
784
+ chainInfo.currencies = [
785
+ {
786
+ coinDenom: "TEST",
787
+ coinMinimalDenom: "utest",
788
+ coinDecimals: 6,
789
+ },
790
+ {
791
+ coinDenom: "TEST2",
792
+ coinMinimalDenom: "utest2",
793
+ coinDecimals: 6,
794
+ },
795
+ ];
796
+ chainInfo.feeCurrencies = [
797
+ {
798
+ coinDenom: "TEST",
799
+ coinMinimalDenom: "utest",
800
+ coinDecimals: 6,
801
+ },
802
+ {
803
+ coinDenom: "TEST2",
804
+ coinMinimalDenom: "utest2",
805
+ coinDecimals: 6,
806
+ },
807
+ ];
808
+
809
+ await ChainInfoSchema.validateAsync(chainInfo);
810
+ }, "should permit multiple currencies/feeCurrencies");
811
+
812
+ await assert.rejects(async () => {
813
+ const chainInfo = generatePlainChainInfo();
814
+ chainInfo.currencies = [
815
+ {
816
+ coinDenom: "TEST",
817
+ coinMinimalDenom: "utest",
818
+ coinDecimals: 6,
819
+ },
820
+ {
821
+ coinDenom: "TEST2",
822
+ coinMinimalDenom: "utest",
823
+ coinDecimals: 6,
824
+ },
825
+ ];
826
+
827
+ await ChainInfoSchema.validateAsync(chainInfo);
828
+ }, "should reject if duplication exists in currencies");
829
+
830
+ await assert.rejects(async () => {
831
+ const chainInfo = generatePlainChainInfo();
832
+ chainInfo.feeCurrencies = [
833
+ {
834
+ coinDenom: "TEST",
835
+ coinMinimalDenom: "utest",
836
+ coinDecimals: 6,
837
+ },
838
+ {
839
+ coinDenom: "TEST2",
840
+ coinMinimalDenom: "utest",
841
+ coinDecimals: 6,
842
+ },
843
+ ];
844
+
845
+ await ChainInfoSchema.validateAsync(chainInfo);
846
+ }, "should reject if duplication exists in feeCurrencies");
847
+
848
+ await assert.doesNotReject(async () => {
849
+ const chainInfo = generatePlainChainInfo();
850
+ // @ts-ignore
851
+ chainInfo.feeCurrencies[0].gasPriceStep = undefined;
852
+
853
+ await ChainInfoSchema.validateAsync(chainInfo);
854
+ }, "gas price step in fee currencies should be nullable");
855
+
856
+ await assert.doesNotReject(async () => {
857
+ let chainInfo = generatePlainChainInfo();
858
+ chainInfo["currencies"] = [
859
+ {
860
+ coinDenom: "TEST",
861
+ coinMinimalDenom: "utest",
862
+ coinDecimals: 6,
863
+ },
864
+ {
865
+ type: "cw20",
866
+ contractAddress: "this should be validated in the keeper",
867
+ coinDenom: "TEST",
868
+ coinMinimalDenom: "utest",
869
+ coinDecimals: 6,
870
+ },
871
+ ];
872
+
873
+ chainInfo = await ChainInfoSchema.validateAsync(chainInfo);
874
+ if (chainInfo.currencies[0].coinMinimalDenom !== "utest") {
875
+ throw new Error("native currency's actual denom should not be changed");
876
+ }
877
+ if (
878
+ chainInfo.currencies[1].coinMinimalDenom !==
879
+ "cw20:this should be validated in the keeper:utest"
880
+ ) {
881
+ throw new Error(
882
+ "actual denom doens't start with `cw20:contract-address:`"
883
+ );
884
+ }
885
+ });
886
+
887
+ await assert.rejects(async () => {
888
+ const chainInfo = generatePlainChainInfo();
889
+ chainInfo["feeCurrencies"] = [
890
+ {
891
+ type: "cw20",
892
+ contractAddress:
893
+ "tokens like CW20/IBC etc... can not be fee currency yet",
894
+ coinDenom: "TEST",
895
+ coinMinimalDenom: "utest",
896
+ coinDecimals: 0,
897
+ },
898
+ ];
899
+
900
+ await ChainInfoSchema.validateAsync(chainInfo);
901
+ }, "Should throw if fee currencies includes invalids");
902
+
903
+ await assert.rejects(async () => {
904
+ const chainInfo = generatePlainChainInfo();
905
+ chainInfo["rpc"] = "asd";
906
+
907
+ await ChainInfoSchema.validateAsync(chainInfo);
908
+ }, "Should throw error when rpc is not uri");
909
+
910
+ await assert.rejects(async () => {
911
+ const chainInfo = generatePlainChainInfo();
912
+ chainInfo["rpc"] = "http://test.com?test=1";
913
+
914
+ await ChainInfoSchema.validateAsync(chainInfo);
915
+ }, "Should throw error when rpc has query string");
916
+
917
+ await assert.rejects(async () => {
918
+ const chainInfo = generatePlainChainInfo();
919
+ // @ts-ignore
920
+ chainInfo["rpc"] = undefined;
921
+
922
+ await ChainInfoSchema.validateAsync(chainInfo);
923
+ }, "Should throw error when rpc is undefined");
924
+
925
+ await assert.rejects(async () => {
926
+ const chainInfo = generatePlainChainInfo();
927
+ chainInfo["rest"] = "asd";
928
+
929
+ await ChainInfoSchema.validateAsync(chainInfo);
930
+ }, "Should throw error when rest is not uri");
931
+
932
+ await assert.rejects(async () => {
933
+ const chainInfo = generatePlainChainInfo();
934
+ chainInfo["rest"] = "http://test.com?test=1";
935
+
936
+ await ChainInfoSchema.validateAsync(chainInfo);
937
+ }, "Should throw error when rest has query string");
938
+
939
+ await assert.rejects(async () => {
940
+ const chainInfo = generatePlainChainInfo();
941
+ // @ts-ignore
942
+ chainInfo["rest"] = undefined;
943
+
944
+ await ChainInfoSchema.validateAsync(chainInfo);
945
+ }, "Should throw error when rest is undefined");
946
+
947
+ await assert.rejects(async () => {
948
+ const chainInfo = generatePlainChainInfo();
949
+ // @ts-ignore
950
+ chainInfo["chainId"] = undefined;
951
+
952
+ await ChainInfoSchema.validateAsync(chainInfo);
953
+ }, "Should throw error when chain id is undefined");
954
+
955
+ await assert.rejects(async () => {
956
+ const chainInfo = generatePlainChainInfo();
957
+ chainInfo["chainId"] = "";
958
+
959
+ await ChainInfoSchema.validateAsync(chainInfo);
960
+ }, "Should throw error when chain id is empty string");
961
+
962
+ await assert.rejects(async () => {
963
+ const chainInfo = generatePlainChainInfo();
964
+ // @ts-ignore
965
+ chainInfo["chainName"] = undefined;
966
+
967
+ await ChainInfoSchema.validateAsync(chainInfo);
968
+ }, "Should throw error when chain name is undefined");
969
+
970
+ await assert.rejects(async () => {
971
+ const chainInfo = generatePlainChainInfo();
972
+ chainInfo["chainName"] = "";
973
+
974
+ await ChainInfoSchema.validateAsync(chainInfo);
975
+ }, "Should throw error when chain name is empty string");
976
+
977
+ await assert.rejects(async () => {
978
+ const chainInfo = generatePlainChainInfo();
979
+ // @ts-ignore
980
+ chainInfo["stakeCurrency"] = undefined;
981
+
982
+ await ChainInfoSchema.validateAsync(chainInfo);
983
+ }, "Should throw error when stake currency is undefined");
984
+
985
+ await assert.rejects(async () => {
986
+ const chainInfo = generatePlainChainInfo();
987
+ // @ts-ignore
988
+ chainInfo["stakeCurrency"] = "should-throw-error";
989
+
990
+ await ChainInfoSchema.validateAsync(chainInfo);
991
+ }, "Should throw error when stake currency is non object");
992
+
993
+ await assert.rejects(async () => {
994
+ const chainInfo = generatePlainChainInfo();
995
+ // @ts-ignore
996
+ chainInfo["stakeCurrency"] = {
997
+ // coinDenom: "TEST",
998
+ coinMinimalDenom: "utest",
999
+ coinDecimals: 6,
1000
+ };
1001
+
1002
+ await ChainInfoSchema.validateAsync(chainInfo);
1003
+ }, "Should throw error when stake currency is invalid");
1004
+
1005
+ await assert.rejects(async () => {
1006
+ const chainInfo = generatePlainChainInfo();
1007
+ // @ts-ignore
1008
+ chainInfo["bip44"] = undefined;
1009
+
1010
+ await ChainInfoSchema.validateAsync(chainInfo);
1011
+ }, "Should throw error when bip44 is undefined");
1012
+
1013
+ await assert.rejects(async () => {
1014
+ const chainInfo = generatePlainChainInfo();
1015
+ // @ts-ignore
1016
+ chainInfo["bip44"] = {};
1017
+
1018
+ await ChainInfoSchema.validateAsync(chainInfo);
1019
+ }, "Should throw error when bip44 has no coinType");
1020
+
1021
+ await assert.doesNotReject(async () => {
1022
+ const chainInfo = generatePlainChainInfo();
1023
+ chainInfo["bip44"] = { coinType: 0 };
1024
+
1025
+ await ChainInfoSchema.validateAsync(chainInfo);
1026
+ }, "BIP44 coinType can be 0");
1027
+
1028
+ await assert.rejects(async () => {
1029
+ const chainInfo = generatePlainChainInfo();
1030
+ chainInfo["bip44"] = { coinType: -1 };
1031
+
1032
+ await ChainInfoSchema.validateAsync(chainInfo);
1033
+ }, "Should throw error when bip44 has negative coinType");
1034
+
1035
+ await assert.rejects(async () => {
1036
+ const chainInfo = generatePlainChainInfo();
1037
+ chainInfo["bip44"] = { coinType: 1.1 };
1038
+
1039
+ await ChainInfoSchema.validateAsync(chainInfo);
1040
+ }, "Should throw error when bip44 has non integer coinType");
1041
+
1042
+ await assert.rejects(async () => {
1043
+ const chainInfo = generatePlainChainInfo();
1044
+ // @ts-ignore
1045
+ chainInfo["bip44"] = {};
1046
+
1047
+ await ChainInfoSchema.validateAsync(chainInfo);
1048
+ }, "Should throw error when bip44 is not instance of BIP44");
1049
+
1050
+ await assert.rejects(async () => {
1051
+ const chainInfo = generatePlainChainInfo();
1052
+ // @ts-ignore
1053
+ chainInfo["bech32Config"] = "should-throw-error";
1054
+
1055
+ await ChainInfoSchema.validateAsync(chainInfo);
1056
+ }, "Should throw error when bech32config is non object");
1057
+
1058
+ await assert.rejects(async () => {
1059
+ const chainInfo = generatePlainChainInfo();
1060
+ // @ts-ignore
1061
+ chainInfo["bech32Config"] = {
1062
+ bech32PrefixAccAddr: "test",
1063
+ };
1064
+
1065
+ await ChainInfoSchema.validateAsync(chainInfo);
1066
+ }, "Should throw error when bech32Config is invalid");
1067
+
1068
+ await assert.rejects(async () => {
1069
+ const chainInfo = generatePlainChainInfo();
1070
+ // @ts-ignore
1071
+ chainInfo["currencies"] = undefined;
1072
+
1073
+ await ChainInfoSchema.validateAsync(chainInfo);
1074
+ }, "Should throw error when currencies is undefined");
1075
+
1076
+ await assert.rejects(async () => {
1077
+ const chainInfo = generatePlainChainInfo();
1078
+ chainInfo["currencies"] = [];
1079
+
1080
+ await ChainInfoSchema.validateAsync(chainInfo);
1081
+ }, "Should throw error when currencies has no item");
1082
+
1083
+ await assert.rejects(async () => {
1084
+ const chainInfo = generatePlainChainInfo();
1085
+ chainInfo["currencies"] = [
1086
+ {
1087
+ coinDenom: "TEST",
1088
+ coinMinimalDenom: "utest",
1089
+ coinDecimals: 6,
1090
+ },
1091
+ // @ts-ignore
1092
+ {
1093
+ // coinDenom: "TEST",
1094
+ coinMinimalDenom: "utest",
1095
+ coinDecimals: 6,
1096
+ },
1097
+ ];
1098
+
1099
+ await ChainInfoSchema.validateAsync(chainInfo);
1100
+ }, "Should throw error when currencies has invalid item");
1101
+
1102
+ await assert.rejects(async () => {
1103
+ const chainInfo = generatePlainChainInfo();
1104
+ // @ts-ignore
1105
+ chainInfo["feeCurrencies"] = undefined;
1106
+
1107
+ await ChainInfoSchema.validateAsync(chainInfo);
1108
+ }, "Should throw error when fee currencies is undefined");
1109
+
1110
+ await assert.rejects(async () => {
1111
+ const chainInfo = generatePlainChainInfo();
1112
+ chainInfo["feeCurrencies"] = [];
1113
+
1114
+ await ChainInfoSchema.validateAsync(chainInfo);
1115
+ }, "Should throw error when fee currencies has no item");
1116
+
1117
+ await assert.rejects(async () => {
1118
+ const chainInfo = generatePlainChainInfo();
1119
+ chainInfo["feeCurrencies"] = [
1120
+ {
1121
+ coinDenom: "TEST",
1122
+ coinMinimalDenom: "utest",
1123
+ coinDecimals: 6,
1124
+ },
1125
+ // @ts-ignore
1126
+ {
1127
+ // coinDenom: "TEST",
1128
+ coinMinimalDenom: "utest",
1129
+ coinDecimals: 6,
1130
+ },
1131
+ ];
1132
+
1133
+ await ChainInfoSchema.validateAsync(chainInfo);
1134
+ }, "Should throw error when fee currencies has invalid item");
1135
+
1136
+ const stargate = "stargate";
1137
+ const cosmwasm = "cosmwasm";
1138
+ const secretwasm = "secretwasm";
1139
+
1140
+ await assert.doesNotReject(async () => {
1141
+ const chainInfo = generatePlainChainInfo();
1142
+ chainInfo["features"] = [stargate, cosmwasm];
1143
+
1144
+ await ChainInfoSchema.validateAsync(chainInfo);
1145
+
1146
+ chainInfo["features"] = [stargate, secretwasm];
1147
+
1148
+ await ChainInfoSchema.validateAsync(chainInfo);
1149
+ });
1150
+
1151
+ await assert.rejects(async () => {
1152
+ const chainInfo = generatePlainChainInfo();
1153
+ chainInfo["features"] = ["unknown"];
1154
+
1155
+ await ChainInfoSchema.validateAsync(chainInfo);
1156
+ }, "Should throw error when the features include the unknown feature");
1157
+
1158
+ await assert.rejects(async () => {
1159
+ const chainInfo = generatePlainChainInfo();
1160
+ chainInfo["features"] = [stargate, stargate];
1161
+
1162
+ await ChainInfoSchema.validateAsync(chainInfo);
1163
+ }, "Should throw error when the features include the duplicated feature");
1164
+
1165
+ await assert.rejects(async () => {
1166
+ const chainInfo = generatePlainChainInfo();
1167
+ chainInfo["features"] = [cosmwasm, secretwasm];
1168
+
1169
+ await ChainInfoSchema.validateAsync(chainInfo);
1170
+ }, "Should throw error when the features has cosmwasm and secretwasm at the same time");
1171
+ });
1172
+ });