@talismn/balances 0.0.0-pr705-20230418063922 → 0.0.0-pr707-20230418101721

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.
@@ -4,11 +4,13 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var dexie = require('dexie');
6
6
  var types = require('@polkadot/types');
7
- var anylogger = require('anylogger');
8
7
  var util = require('@talismn/util');
8
+ var groupBy = require('lodash/groupBy');
9
+ var anylogger = require('anylogger');
9
10
 
10
11
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
11
12
 
13
+ var groupBy__default = /*#__PURE__*/_interopDefault(groupBy);
12
14
  var anylogger__default = /*#__PURE__*/_interopDefault(anylogger);
13
15
 
14
16
  // TODO: Document default balances module purpose/usage
@@ -67,7 +69,7 @@ const db = new TalismanBalancesDatabase();
67
69
 
68
70
  var packageJson = {
69
71
  name: "@talismn/balances",
70
- version: "0.0.0-pr705-20230418063922",
72
+ version: "0.0.0-pr707-20230418101721",
71
73
  author: "Talisman",
72
74
  homepage: "https://talisman.xyz",
73
75
  license: "UNLICENSED",
@@ -94,26 +96,28 @@ var packageJson = {
94
96
  clean: "rm -rf dist && rm -rf .turbo rm -rf node_modules"
95
97
  },
96
98
  dependencies: {
97
- "@talismn/chain-connector": "workspace:^",
98
- "@talismn/chain-connector-evm": "workspace:^",
99
- "@talismn/chaindata-provider": "workspace:^",
100
- "@talismn/token-rates": "workspace:^",
101
- "@talismn/util": "workspace:^",
99
+ "@talismn/chain-connector": "workspace:*",
100
+ "@talismn/chain-connector-evm": "workspace:*",
101
+ "@talismn/chaindata-provider": "workspace:*",
102
+ "@talismn/token-rates": "workspace:*",
103
+ "@talismn/util": "workspace:*",
102
104
  anylogger: "^1.0.11",
103
- dexie: "^3.2.3"
105
+ dexie: "^3.2.3",
106
+ lodash: "4.17.21"
104
107
  },
105
108
  devDependencies: {
106
- "@polkadot/types": "^9.10.5",
107
- "@talismn/eslint-config": "workspace:^",
108
- "@talismn/tsconfig": "workspace:^",
109
+ "@polkadot/types": "^10.1.4",
110
+ "@talismn/eslint-config": "workspace:*",
111
+ "@talismn/tsconfig": "workspace:*",
109
112
  "@types/jest": "^27.5.1",
113
+ "@types/lodash": "^4.14.180",
110
114
  eslint: "^8.4.0",
111
115
  jest: "^28.1.0",
112
116
  "ts-jest": "^28.0.2",
113
117
  typescript: "^4.6.4"
114
118
  },
115
119
  peerDependencies: {
116
- "@polkadot/types": "9.x"
120
+ "@polkadot/types": "10.x"
117
121
  },
118
122
  preconstruct: {
119
123
  entrypoints: [
@@ -146,8 +150,14 @@ const createTypeRegistryCache = () => {
146
150
  if (cached) return cached;
147
151
  const typeRegistry = new types.TypeRegistry();
148
152
  if (typeof metadataRpc === "string") {
149
- const metadata = new types.Metadata(typeRegistry, metadataRpc);
150
- metadata.registry.setMetadata(metadata);
153
+ try {
154
+ const metadata = new types.Metadata(typeRegistry, metadataRpc);
155
+ metadata.registry.setMetadata(metadata);
156
+ } catch (cause) {
157
+ log.warn(new Error(`Failed to set metadata for chain ${chainId}`, {
158
+ cause
159
+ }), cause);
160
+ }
151
161
  }
152
162
  typeRegistryCache.set(chainId, typeRegistry);
153
163
  return typeRegistry;
@@ -286,11 +296,77 @@ class StorageHelper {
286
296
  }
287
297
  }
288
298
 
299
+ /**
300
+ * Pass some these into an `RpcStateQueryHelper` in order to easily batch multiple state queries into the one rpc call.
301
+ */
302
+
303
+ /**
304
+ * Used by a variety of balance modules to help batch multiple state queries into the one rpc call.
305
+ */
306
+ class RpcStateQueryHelper {
307
+ #chainConnector;
308
+ #queries;
309
+ constructor(chainConnector, queries) {
310
+ this.#chainConnector = chainConnector;
311
+ this.#queries = queries;
312
+ }
313
+ async subscribe(callback, timeout = false, subscribeMethod = "state_subscribeStorage", responseMethod = "state_storage", unsubscribeMethod = "state_unsubscribeStorage") {
314
+ const queriesByChain = groupBy__default["default"](this.#queries, "chainId");
315
+ const subscriptions = Object.entries(queriesByChain).map(([chainId, queries]) => {
316
+ const params = [queries.map(({
317
+ stateKey
318
+ }) => stateKey)];
319
+ const unsub = this.#chainConnector.subscribe(chainId, subscribeMethod, responseMethod, params, (error, result) => {
320
+ error ? callback(error) : callback(null, this.#distributeChangesToQueryDecoders.call(this, chainId, result));
321
+ }, timeout);
322
+ return () => unsub.then(unsubscribe => unsubscribe(unsubscribeMethod));
323
+ });
324
+ return () => subscriptions.forEach(unsubscribe => unsubscribe());
325
+ }
326
+ async fetch(method = "state_queryStorageAt") {
327
+ const queriesByChain = groupBy__default["default"](this.#queries, "chainId");
328
+ const resultsByChain = await Promise.all(Object.entries(queriesByChain).map(async ([chainId, queries]) => {
329
+ const params = [queries.map(({
330
+ stateKey
331
+ }) => stateKey)];
332
+ const result = (await this.#chainConnector.send(chainId, method, params))[0];
333
+ return this.#distributeChangesToQueryDecoders.call(this, chainId, result);
334
+ }));
335
+ return resultsByChain.flatMap(result => result);
336
+ }
337
+ #distributeChangesToQueryDecoders(chainId, result) {
338
+ if (typeof result !== "object" || result === null) return [];
339
+ if (!util.hasOwnProperty(result, "changes") || typeof result.changes !== "object") return [];
340
+ if (!Array.isArray(result.changes)) return [];
341
+ return result.changes.flatMap(([reference, change]) => {
342
+ if (typeof reference !== "string") {
343
+ log.warn(`Received non-string reference in RPC result: ${reference}`);
344
+ return [];
345
+ }
346
+ if (typeof change !== "string" && change !== null) {
347
+ log.warn(`Received non-string and non-null change in RPC result: ${reference} | ${change}`);
348
+ return [];
349
+ }
350
+ const query = this.#queries.find(({
351
+ chainId: cId,
352
+ stateKey
353
+ }) => cId === chainId && stateKey === reference);
354
+ if (!query) {
355
+ log.warn(`Failed to find query:\n${reference} in\n${this.#queries.map(({
356
+ stateKey
357
+ }) => stateKey)}`);
358
+ return [];
359
+ }
360
+ return [query.decodeResult(change)];
361
+ });
362
+ }
363
+ }
364
+
289
365
  const BalanceStatusLive = subscriptionId => `live-${subscriptionId}`;
290
366
  function excludeFromTransferableAmount(locks) {
291
367
  if (typeof locks === "string") return BigInt(locks);
292
368
  if (!Array.isArray(locks)) locks = [locks];
293
- return locks.filter(lock => lock.includeInTransferable !== true).map(lock => BigInt(lock.amount)).reduce((max, lock) => util.BigMath.max(max, lock), BigInt("0"));
369
+ return locks.filter(lock => lock.includeInTransferable !== true).map(lock => BigInt(lock.amount)).reduce((max, lock) => util.BigMath.max(max, lock), 0n);
294
370
  }
295
371
  function excludeFromFeePayableLocks(locks) {
296
372
  if (typeof locks === "string") return [];
@@ -301,9 +377,9 @@ function excludeFromFeePayableLocks(locks) {
301
377
  /** A labelled extra amount of a balance */
302
378
 
303
379
  function includeInTotalExtraAmount(extra) {
304
- if (!extra) return BigInt("0");
380
+ if (!extra) return 0n;
305
381
  if (!Array.isArray(extra)) extra = [extra];
306
- return extra.filter(extra => extra.includeInTotal).map(extra => BigInt(extra.amount)).reduce((a, b) => a + b, BigInt("0"));
382
+ return extra.filter(extra => extra.includeInTotal).map(extra => BigInt(extra.amount)).reduce((a, b) => a + b, 0n);
307
383
  }
308
384
 
309
385
  /** Used by plugins to help define their custom `BalanceType` */
@@ -414,6 +490,27 @@ class Balances {
414
490
  return new Balances([...this].filter(filter));
415
491
  };
416
492
 
493
+ /**
494
+ * Filters this collection to exclude token balances where the token has a `mirrorOf` field
495
+ * and another balance exists in this collection for the token specified by the `mirrorOf` field.
496
+ */
497
+ filterMirrorTokens = () => new Balances([...this].filter(filterMirrorTokens));
498
+
499
+ /**
500
+ * Filters this collection to only include balances which are not zero.
501
+ */
502
+ filterNonZero = type => {
503
+ const filter = balance => balance[type].planck > 0n;
504
+ return this.find(filter);
505
+ };
506
+ /**
507
+ * Filters this collection to only include balances which are not zero AND have a fiat conversion rate.
508
+ */
509
+ filterNonZeroFiat = (type, currency) => {
510
+ const filter = balance => (balance[type].fiat(currency) ?? 0) > 0;
511
+ return this.find(filter);
512
+ };
513
+
417
514
  /**
418
515
  * Add some balances to this collection.
419
516
  * Added balances take priority over existing balances.
@@ -536,13 +633,14 @@ class Balance {
536
633
  get id() {
537
634
  const {
538
635
  source,
636
+ subSource,
539
637
  address,
540
638
  chainId,
541
639
  evmNetworkId,
542
640
  tokenId
543
641
  } = this.#storage;
544
642
  const locationId = chainId !== undefined ? chainId : evmNetworkId;
545
- return `${source}-${address}-${locationId}-${tokenId}`;
643
+ return [source, address, locationId, tokenId, subSource].filter(Boolean).join("-");
546
644
  }
547
645
  get source() {
548
646
  return this.#storage.source;
@@ -591,17 +689,43 @@ class Balance {
591
689
  }
592
690
  /** The non-reserved balance of this token. Includes the frozen amount. Is included in the total. */
593
691
  get free() {
594
- return this.#format(typeof this.#storage.free === "string" ? BigInt(this.#storage.free) : Array.isArray(this.#storage.free) ? this.#storage.free.map(reserve => BigInt(reserve.amount)).reduce((a, b) => a + b, BigInt("0")) : BigInt(this.#storage.free?.amount || "0"));
692
+ return this.#format(typeof this.#storage.free === "string" ? BigInt(this.#storage.free) : Array.isArray(this.#storage.free) ? this.#storage.free.map(reserve => BigInt(reserve.amount)).reduce((a, b) => a + b, 0n) : BigInt(this.#storage.free?.amount || "0"));
595
693
  }
596
694
  /** The reserved balance of this token. Is included in the total. */
597
695
  get reserved() {
598
- return this.#format(typeof this.#storage.reserves === "string" ? BigInt(this.#storage.reserves) : Array.isArray(this.#storage.reserves) ? this.#storage.reserves.map(reserve => BigInt(reserve.amount)).reduce((a, b) => a + b, BigInt("0")) : BigInt(this.#storage.reserves?.amount || "0"));
696
+ return this.#format(typeof this.#storage.reserves === "string" ? BigInt(this.#storage.reserves) : Array.isArray(this.#storage.reserves) ? this.#storage.reserves.map(reserve => BigInt(reserve.amount)).reduce((a, b) => a + b, 0n) : BigInt(this.#storage.reserves?.amount || "0"));
697
+ }
698
+ get reserves() {
699
+ return (Array.isArray(this.#storage.reserves) ? this.#storage.reserves : [this.#storage.reserves]).flatMap(reserve => {
700
+ if (reserve === undefined) return [];
701
+ if (typeof reserve === "string") return {
702
+ label: "reserved",
703
+ amount: this.#format(reserve)
704
+ };
705
+ return {
706
+ ...reserve,
707
+ amount: this.#format(reserve.amount)
708
+ };
709
+ });
599
710
  }
600
711
  /** The frozen balance of this token. Is included in the free amount. */
601
712
  get locked() {
602
- return this.#format(typeof this.#storage.locks === "string" ? BigInt(this.#storage.locks) : Array.isArray(this.#storage.locks) ? this.#storage.locks.map(lock => BigInt(lock.amount)).reduce((a, b) => util.BigMath.max(a, b), BigInt("0")) : BigInt(this.#storage.locks?.amount || "0"));
713
+ return this.#format(typeof this.#storage.locks === "string" ? BigInt(this.#storage.locks) : Array.isArray(this.#storage.locks) ? this.#storage.locks.map(lock => BigInt(lock.amount)).reduce((a, b) => util.BigMath.max(a, b), 0n) : BigInt(this.#storage.locks?.amount || "0"));
714
+ }
715
+ get locks() {
716
+ return (Array.isArray(this.#storage.locks) ? this.#storage.locks : [this.#storage.locks]).flatMap(lock => {
717
+ if (lock === undefined) return [];
718
+ if (typeof lock === "string") return {
719
+ label: "other",
720
+ amount: this.#format(lock)
721
+ };
722
+ return {
723
+ ...lock,
724
+ amount: this.#format(lock.amount)
725
+ };
726
+ });
603
727
  }
604
- /** @depreacted - use balance.locked */
728
+ /** @deprecated Use balance.locked */
605
729
  get frozen() {
606
730
  return this.locked;
607
731
  }
@@ -614,7 +738,7 @@ class Balance {
614
738
  const excludeAmount = excludeFromTransferableAmount(this.#storage.locks);
615
739
 
616
740
  // subtract the lock from the free amount (but don't go below 0)
617
- return this.#format(util.BigMath.max(this.free.planck - excludeAmount, BigInt("0")));
741
+ return this.#format(util.BigMath.max(this.free.planck - excludeAmount, 0n));
618
742
  }
619
743
  /** The feePayable balance of this token. Is generally the free amount - the feeFrozen amount. */
620
744
  get feePayable() {
@@ -622,10 +746,10 @@ class Balance {
622
746
  if (!this.#storage.locks) return this.free;
623
747
 
624
748
  // find the largest lock which can't be used to pay tx fees
625
- const excludeAmount = excludeFromFeePayableLocks(this.#storage.locks).map(lock => BigInt(lock.amount)).reduce((max, lock) => util.BigMath.max(max, lock), BigInt("0"));
749
+ const excludeAmount = excludeFromFeePayableLocks(this.#storage.locks).map(lock => BigInt(lock.amount)).reduce((max, lock) => util.BigMath.max(max, lock), 0n);
626
750
 
627
751
  // subtract the lock from the free amount (but don't go below 0)
628
- return this.#format(util.BigMath.max(this.free.planck - excludeAmount, BigInt("0")));
752
+ return this.#format(util.BigMath.max(this.free.planck - excludeAmount, 0n));
629
753
  }
630
754
  }
631
755
  class BalanceFormatter {
@@ -651,6 +775,52 @@ class BalanceFormatter {
651
775
  return parseFloat(this.tokens) * ratio;
652
776
  }
653
777
  }
778
+ class PlanckSumBalancesFormatter {
779
+ #balances;
780
+ constructor(balances) {
781
+ this.#balances = balances;
782
+ }
783
+ #sum = balanceField => {
784
+ // a function to get a planck amount from a balance
785
+ const planck = balance => balance[balanceField].planck ?? 0n;
786
+ return this.#balances.filterMirrorTokens().each.reduce(
787
+ // add the total amount to the planck amount of each balance
788
+ (total, balance) => total + planck(balance),
789
+ // start with a total of 0
790
+ 0n);
791
+ };
792
+
793
+ /**
794
+ * The total balance of these tokens. Includes the free and the reserved amount.
795
+ */
796
+ get total() {
797
+ return this.#sum("total");
798
+ }
799
+ /** The non-reserved balance of these tokens. Includes the frozen amount. Is included in the total. */
800
+ get free() {
801
+ return this.#sum("free");
802
+ }
803
+ /** The reserved balance of these tokens. Is included in the total. */
804
+ get reserved() {
805
+ return this.#sum("reserved");
806
+ }
807
+ /** The frozen balance of these tokens. Is included in the free amount. */
808
+ get locked() {
809
+ return this.#sum("locked");
810
+ }
811
+ /** @deprecated Use balances.locked */
812
+ get frozen() {
813
+ return this.locked;
814
+ }
815
+ /** The transferable balance of these tokens. Is generally the free amount - the miscFrozen amount. */
816
+ get transferable() {
817
+ return this.#sum("transferable");
818
+ }
819
+ /** The feePayable balance of these tokens. Is generally the free amount - the feeFrozen amount. */
820
+ get feePayable() {
821
+ return this.#sum("feePayable");
822
+ }
823
+ }
654
824
  class FiatSumBalancesFormatter {
655
825
  #balances;
656
826
  #currency;
@@ -660,15 +830,10 @@ class FiatSumBalancesFormatter {
660
830
  }
661
831
  #sum = balanceField => {
662
832
  // a function to get a fiat amount from a balance
663
- const fiat = balance => balance[balanceField].fiat(this.#currency) || 0;
664
-
665
- // a function to add two amounts
666
- const sum = (a, b) => a + b;
667
- return [...this.#balances].filter(filterMirrorTokens).reduce((total, balance) => sum(
668
- // add the total amount...
669
- total,
670
- // ...to the fiat amount of each balance
671
- fiat(balance)),
833
+ const fiat = balance => balance[balanceField].fiat(this.#currency) ?? 0;
834
+ return this.#balances.filterMirrorTokens().each.reduce(
835
+ // add the total amount to the fiat amount of each balance
836
+ (total, balance) => total + fiat(balance),
672
837
  // start with a total of 0
673
838
  0);
674
839
  };
@@ -691,7 +856,7 @@ class FiatSumBalancesFormatter {
691
856
  get locked() {
692
857
  return this.#sum("locked");
693
858
  }
694
- /** @deprecated - use balances.locked */
859
+ /** @deprecated Use balances.locked */
695
860
  get frozen() {
696
861
  return this.locked;
697
862
  }
@@ -709,6 +874,9 @@ class SumBalancesFormatter {
709
874
  constructor(balances) {
710
875
  this.#balances = balances;
711
876
  }
877
+ get planck() {
878
+ return new PlanckSumBalancesFormatter(this.#balances);
879
+ }
712
880
  fiat(currency) {
713
881
  return new FiatSumBalancesFormatter(this.#balances, currency);
714
882
  }
@@ -720,6 +888,8 @@ exports.BalanceStatusLive = BalanceStatusLive;
720
888
  exports.Balances = Balances;
721
889
  exports.DefaultBalanceModule = DefaultBalanceModule;
722
890
  exports.FiatSumBalancesFormatter = FiatSumBalancesFormatter;
891
+ exports.PlanckSumBalancesFormatter = PlanckSumBalancesFormatter;
892
+ exports.RpcStateQueryHelper = RpcStateQueryHelper;
723
893
  exports.StorageHelper = StorageHelper;
724
894
  exports.SumBalancesFormatter = SumBalancesFormatter;
725
895
  exports.TalismanBalancesDatabase = TalismanBalancesDatabase;