@talismn/balances 0.3.3 → 0.4.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.
@@ -1,13 +1,8 @@
1
1
  import { Dexie } from 'dexie';
2
- import { decorateStorage, StorageKey } from '@polkadot/types';
2
+ import { decorateStorage, StorageKey, TypeRegistry, Metadata } from '@polkadot/types';
3
+ import { hasOwnProperty, BigMath, isArrayOf, planckToTokens } from '@talismn/util';
4
+ import groupBy from 'lodash/groupBy';
3
5
  import anylogger from 'anylogger';
4
- import { BigMath, isArrayOf, planckToTokens } from '@talismn/util';
5
- import memoize from 'lodash/memoize';
6
- import { Memoize } from 'typescript-memoize';
7
-
8
- //
9
- // exported
10
- //
11
6
 
12
7
  // TODO: Document default balances module purpose/usage
13
8
  const DefaultBalanceModule = type => ({
@@ -26,12 +21,15 @@ const DefaultBalanceModule = type => ({
26
21
  async fetchEvmChainTokens() {
27
22
  return Promise.resolve({});
28
23
  },
29
- async subscribeBalances(_chainConnectors, _chaindataProvider, _addressesByToken, callback) {
24
+ async subscribeBalances(_, callback) {
30
25
  callback(new Error("Balance subscriptions are not implemented in this module."));
31
26
  return () => {};
32
27
  },
33
28
  async fetchBalances() {
34
29
  throw new Error("Balance fetching is not implemented in this module.");
30
+ },
31
+ async transferToken() {
32
+ throw new Error("Token transfers are not implemented in this module.");
35
33
  }
36
34
  });
37
35
 
@@ -62,7 +60,7 @@ const db = new TalismanBalancesDatabase();
62
60
 
63
61
  var packageJson = {
64
62
  name: "@talismn/balances",
65
- version: "0.3.3",
63
+ version: "0.4.1",
66
64
  author: "Talisman",
67
65
  homepage: "https://talisman.xyz",
68
66
  license: "UNLICENSED",
@@ -81,36 +79,36 @@ var packageJson = {
81
79
  "/plugins"
82
80
  ],
83
81
  engines: {
84
- node: ">=14"
82
+ node: ">=18"
85
83
  },
86
84
  scripts: {
87
85
  test: "jest",
88
- lint: "eslint . --max-warnings 0",
86
+ lint: "eslint src --max-warnings 0",
89
87
  clean: "rm -rf dist && rm -rf .turbo rm -rf node_modules"
90
88
  },
91
89
  dependencies: {
92
- "@talismn/chain-connector": "workspace:^",
93
- "@talismn/chain-connector-evm": "workspace:^",
94
- "@talismn/chaindata-provider": "workspace:^",
95
- "@talismn/token-rates": "workspace:^",
96
- "@talismn/util": "workspace:^",
90
+ "@talismn/chain-connector": "workspace:*",
91
+ "@talismn/chain-connector-evm": "workspace:*",
92
+ "@talismn/chaindata-provider": "workspace:*",
93
+ "@talismn/token-rates": "workspace:*",
94
+ "@talismn/util": "workspace:*",
97
95
  anylogger: "^1.0.11",
98
- dexie: "^3.2.2",
99
- lodash: "^4.17.21",
100
- "typescript-memoize": "^1.1.0"
96
+ dexie: "^3.2.3",
97
+ lodash: "4.17.21"
101
98
  },
102
99
  devDependencies: {
103
- "@polkadot/types": "^9.10.5",
104
- "@talismn/eslint-config": "workspace:^",
105
- "@talismn/tsconfig": "workspace:^",
100
+ "@polkadot/types": "^10.1.4",
101
+ "@talismn/eslint-config": "workspace:*",
102
+ "@talismn/tsconfig": "workspace:*",
106
103
  "@types/jest": "^27.5.1",
104
+ "@types/lodash": "^4.14.180",
107
105
  eslint: "^8.4.0",
108
106
  jest: "^28.1.0",
109
107
  "ts-jest": "^28.0.2",
110
108
  typescript: "^4.6.4"
111
109
  },
112
110
  peerDependencies: {
113
- "@polkadot/types": "9.x"
111
+ "@polkadot/types": "10.x"
114
112
  },
115
113
  preconstruct: {
116
114
  entrypoints: [
@@ -128,18 +126,114 @@ var packageJson = {
128
126
 
129
127
  var log = anylogger(packageJson.name);
130
128
 
131
- async function balances(balanceModule, chainConnectors, chaindataProvider, addressesByToken, callback) {
129
+ /**
130
+ * Wraps a BalanceModule's fetch/subscribe methods with a single `balances` method.
131
+ * This `balances` method will subscribe if a callback parameter is provided, or otherwise fetch.
132
+ */
133
+
134
+ async function balances(balanceModule, addressesByToken, callback) {
132
135
  // subscription request
133
- if (callback !== undefined) return await balanceModule.subscribeBalances(chainConnectors, chaindataProvider, addressesByToken, callback);
136
+ if (callback !== undefined) return await balanceModule.subscribeBalances(addressesByToken, callback);
134
137
 
135
138
  // one-off request
136
- return await balanceModule.fetchBalances(chainConnectors, chaindataProvider, addressesByToken);
139
+ return await balanceModule.fetchBalances(addressesByToken);
137
140
  }
141
+ const createTypeRegistryCache = () => {
142
+ const typeRegistryCache = new Map();
143
+ const getOrCreateTypeRegistry = (chainId, metadataRpc) => {
144
+ // TODO: Delete cache when metadataRpc is different from last time
145
+ const cached = typeRegistryCache.get(chainId);
146
+ if (cached) return cached;
147
+ const typeRegistry = new TypeRegistry();
148
+ if (typeof metadataRpc === "string") {
149
+ try {
150
+ const metadata = new Metadata(typeRegistry, metadataRpc);
151
+ metadata.registry.setMetadata(metadata);
152
+ } catch (cause) {
153
+ log.warn(new Error(`Failed to set metadata for chain ${chainId}`, {
154
+ cause
155
+ }), cause);
156
+ }
157
+ }
158
+ typeRegistryCache.set(chainId, typeRegistry);
159
+ return typeRegistry;
160
+ };
161
+ return {
162
+ getOrCreateTypeRegistry
163
+ };
164
+ };
165
+
166
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
167
+
168
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
169
+
170
+ /**
171
+ * The following `Infer*` collection of generic types can be used when you want to
172
+ * extract one of the generic type arguments from an existing BalanceModule.
173
+ *
174
+ * For example, you might want to write a function which can accept any BalanceModule
175
+ * as an input, and then return the specific TokenType for that module:
176
+ * function getTokens<T extends AnyBalanceModule>(module: T): InferTokenType<T>
177
+ *
178
+ * Or for another example, you might want a function which can take any BalanceModule `type`
179
+ * string as input, and then return some data associated with that module with the correct type:
180
+ * function getChainMeta<T extends AnyBalanceModule>(type: InferModuleType<T>): InferChainMeta<T> | undefined
181
+ */
182
+
183
+ /**
184
+ * Given a `moduleType` and a `chain` from a chaindataProvider, this function will find the chainMeta
185
+ * associated with the given balanceModule for the given chain.
186
+ */
187
+ const findChainMeta = (moduleType, chain) => {
188
+ return (chain?.balanceMetadata ?? []).find(meta => meta.moduleType === moduleType)?.metadata;
189
+ };
138
190
  const filterMirrorTokens = (balance, i, balances) => {
139
- // TODO implement a mirrorOf property, which should be set from chaindata
140
191
  const mirrorOf = balance.token?.mirrorOf;
141
192
  return !mirrorOf || !balances.find(b => b.tokenId === mirrorOf);
142
193
  };
194
+ const getValidSubscriptionIds = () => {
195
+ return new Set(localStorage.getItem("TalismanBalancesSubscriptionIds")?.split(",") ?? []);
196
+ };
197
+ const createSubscriptionId = () => {
198
+ // delete current id (if exists)
199
+ deleteSubscriptionId();
200
+
201
+ // create new id
202
+ const subscriptionId = Date.now().toString();
203
+ sessionStorage.setItem("TalismanBalancesSubscriptionId", subscriptionId);
204
+
205
+ // add to list of current ids
206
+ const subscriptionIds = getValidSubscriptionIds();
207
+ subscriptionIds.add(subscriptionId);
208
+ localStorage.setItem("TalismanBalancesSubscriptionIds", [...subscriptionIds].filter(Boolean).join(","));
209
+ return subscriptionId;
210
+ };
211
+ const deleteSubscriptionId = () => {
212
+ const subscriptionId = sessionStorage.getItem("TalismanBalancesSubscriptionId");
213
+ if (!subscriptionId) return;
214
+ const subscriptionIds = getValidSubscriptionIds();
215
+ subscriptionIds.delete(subscriptionId);
216
+ localStorage.setItem("TalismanBalancesSubscriptionIds", [...subscriptionIds].filter(Boolean).join(","));
217
+ };
218
+
219
+ /**
220
+ * Sets all balance statuses from `live-${string}` to either `live` or `cached`
221
+ */
222
+ const deriveStatuses = (validSubscriptionIds, balances) => balances.map(balance => {
223
+ if (balance.status === "live" || balance.status === "cache" || balance.status === "stale") return balance;
224
+ if (validSubscriptionIds.length < 1) return {
225
+ ...balance,
226
+ status: "cache"
227
+ };
228
+ if (!validSubscriptionIds.includes(balance.status.slice("live-".length))) return {
229
+ ...balance,
230
+ status: "cache"
231
+ };
232
+ return {
233
+ ...balance,
234
+ status: "live"
235
+ };
236
+ });
143
237
 
144
238
  /**
145
239
  * Used by a variety of balance modules to help encode and decode substrate state calls.
@@ -150,7 +244,11 @@ class StorageHelper {
150
244
  #module;
151
245
  #method;
152
246
  #parameters;
247
+
248
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
153
249
  tags = null;
250
+
251
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
154
252
  constructor(registry, module, method, ...parameters) {
155
253
  this.#registry = registry;
156
254
  this.#module = module;
@@ -184,6 +282,8 @@ class StorageHelper {
184
282
  get parameters() {
185
283
  return this.#parameters;
186
284
  }
285
+
286
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
187
287
  tag(tags) {
188
288
  this.tags = tags;
189
289
  return this;
@@ -222,34 +322,106 @@ class StorageHelper {
222
322
  }
223
323
  }
224
324
 
225
- function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
226
- var desc = {};
227
- Object.keys(descriptor).forEach(function (key) {
228
- desc[key] = descriptor[key];
229
- });
230
- desc.enumerable = !!desc.enumerable;
231
- desc.configurable = !!desc.configurable;
232
- if ('value' in desc || desc.initializer) {
233
- desc.writable = true;
234
- }
235
- desc = decorators.slice().reverse().reduce(function (desc, decorator) {
236
- return decorator(target, property, desc) || desc;
237
- }, desc);
238
- if (context && desc.initializer !== void 0) {
239
- desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
240
- desc.initializer = undefined;
241
- }
242
- if (desc.initializer === void 0) {
243
- Object.defineProperty(target, property, desc);
244
- desc = null;
245
- }
246
- return desc;
325
+ /**
326
+ * Pass some these into an `RpcStateQueryHelper` in order to easily batch multiple state queries into the one rpc call.
327
+ */
328
+
329
+ /**
330
+ * Used by a variety of balance modules to help batch multiple state queries into the one rpc call.
331
+ */
332
+ class RpcStateQueryHelper {
333
+ #chainConnector;
334
+ #queries;
335
+ constructor(chainConnector, queries) {
336
+ this.#chainConnector = chainConnector;
337
+ this.#queries = queries;
338
+ }
339
+ async subscribe(callback, timeout = false, subscribeMethod = "state_subscribeStorage", responseMethod = "state_storage", unsubscribeMethod = "state_unsubscribeStorage") {
340
+ const queriesByChain = groupBy(this.#queries, "chainId");
341
+ const subscriptions = Object.entries(queriesByChain).map(([chainId, queries]) => {
342
+ const params = [queries.map(({
343
+ stateKey
344
+ }) => stateKey)];
345
+ const unsub = this.#chainConnector.subscribe(chainId, subscribeMethod, responseMethod, params, (error, result) => {
346
+ error ? callback(error) : callback(null, this.#distributeChangesToQueryDecoders.call(this, chainId, result));
347
+ }, timeout);
348
+ return () => unsub.then(unsubscribe => unsubscribe(unsubscribeMethod));
349
+ });
350
+ return () => subscriptions.forEach(unsubscribe => unsubscribe());
351
+ }
352
+ async fetch(method = "state_queryStorageAt") {
353
+ const queriesByChain = groupBy(this.#queries, "chainId");
354
+ const resultsByChain = await Promise.all(Object.entries(queriesByChain).map(async ([chainId, queries]) => {
355
+ const params = [queries.map(({
356
+ stateKey
357
+ }) => stateKey)];
358
+ const result = (await this.#chainConnector.send(chainId, method, params))[0];
359
+ return this.#distributeChangesToQueryDecoders.call(this, chainId, result);
360
+ }));
361
+ return resultsByChain.flatMap(result => result);
362
+ }
363
+ #distributeChangesToQueryDecoders(chainId, result) {
364
+ if (typeof result !== "object" || result === null) return [];
365
+ if (!hasOwnProperty(result, "changes") || typeof result.changes !== "object") return [];
366
+ if (!Array.isArray(result.changes)) return [];
367
+ return result.changes.flatMap(([reference, change]) => {
368
+ if (typeof reference !== "string") {
369
+ log.warn(`Received non-string reference in RPC result: ${reference}`);
370
+ return [];
371
+ }
372
+ if (typeof change !== "string" && change !== null) {
373
+ log.warn(`Received non-string and non-null change in RPC result: ${reference} | ${change}`);
374
+ return [];
375
+ }
376
+ const query = this.#queries.find(({
377
+ chainId: cId,
378
+ stateKey
379
+ }) => cId === chainId && stateKey === reference);
380
+ if (!query) {
381
+ log.warn(`Failed to find query:\n${reference} in\n${this.#queries.map(({
382
+ stateKey
383
+ }) => stateKey)}`);
384
+ return [];
385
+ }
386
+ return [query.decodeResult(change)];
387
+ });
388
+ }
247
389
  }
248
390
 
391
+ /**
392
+ * `BalanceTypes` is an automatically determined sub-selection of `PluginBalanceTypes`.
393
+ *
394
+ * It is the same list, but with any invalid `BalanceType` definitions filtered out.
395
+ */
396
+
397
+ /**
398
+ * The `BalanceJson` sum type, which is a union of all of the possible `BalanceTypes`.
399
+ *
400
+ * Each variant comes from a plugin in use by the consuming app.
401
+ *
402
+ * For example, in an app with the `substrate-native`, `evm-native`, `substrate-orml` and `evm-erc20` plugins:
403
+ *
404
+ * type BalanceJson = SubNativeBalance | EvmNativeBalance | SubOrmlBalance | EvmErc20Balance
405
+ *
406
+ * If `BalanceTypes` is empty then `BalanceJson` will fall back to the common `IBalance` interface, which every balance must implement.
407
+ */
408
+
409
+ /** A collection of `BalanceJson` objects */
410
+
411
+ const BalanceStatusLive = subscriptionId => `live-${subscriptionId}`;
412
+
413
+ /** `IBalance` is a common interface which all balance types must implement. */
414
+
415
+ /** An unlabelled amount of a balance */
416
+
417
+ /** A labelled amount of a balance */
418
+
419
+ /** A labelled locked amount of a balance */
420
+
249
421
  function excludeFromTransferableAmount(locks) {
250
422
  if (typeof locks === "string") return BigInt(locks);
251
423
  if (!Array.isArray(locks)) locks = [locks];
252
- return locks.filter(lock => lock.includeInTransferable !== true).map(lock => BigInt(lock.amount)).reduce((max, lock) => BigMath.max(max, lock), BigInt("0"));
424
+ return locks.filter(lock => lock.includeInTransferable !== true).map(lock => BigInt(lock.amount)).reduce((max, lock) => BigMath.max(max, lock), 0n);
253
425
  }
254
426
  function excludeFromFeePayableLocks(locks) {
255
427
  if (typeof locks === "string") return [];
@@ -260,31 +432,29 @@ function excludeFromFeePayableLocks(locks) {
260
432
  /** A labelled extra amount of a balance */
261
433
 
262
434
  function includeInTotalExtraAmount(extra) {
263
- if (!extra) return BigInt("0");
435
+ if (!extra) return 0n;
264
436
  if (!Array.isArray(extra)) extra = [extra];
265
- return extra.filter(extra => extra.includeInTotal).map(extra => BigInt(extra.amount)).reduce((a, b) => a + b, BigInt("0"));
437
+ return extra.filter(extra => extra.includeInTotal).map(extra => BigInt(extra.amount)).reduce((a, b) => a + b, 0n);
266
438
  }
267
439
 
268
440
  /** Used by plugins to help define their custom `BalanceType` */
269
441
 
270
- var _dec, _dec2, _dec3, _class, _dec4, _dec5, _dec6, _dec7, _dec8, _dec9, _dec10, _class2, _dec11, _class3, _dec12, _dec13, _dec14, _dec15, _dec16, _dec17, _dec18, _class4;
271
-
272
442
  /**
273
443
  * Have the importing library define its Token and BalanceJson enums (as a sum type of all plugins) and pass them into some
274
444
  * internal global typescript context, which is then picked up on by this module.
275
445
  */
276
446
 
277
447
  /** A utility type used to extract the underlying `BalanceType` of a specific source from a generalised `BalanceJson` */
278
-
448
+ /** TODO: Remove this in favour of a frontend-friendly `ChaindataProvider` */
279
449
  /**
280
450
  * A collection of balances.
281
451
  */
282
- let Balances = (_dec = Memoize(), _dec2 = Memoize(), _dec3 = Memoize(), (_class = class Balances {
452
+ class Balances {
283
453
  //
284
454
  // Properties
285
455
  //
286
456
 
287
- #balances = {};
457
+ #balances = [];
288
458
 
289
459
  //
290
460
  // Methods
@@ -292,7 +462,7 @@ let Balances = (_dec = Memoize(), _dec2 = Memoize(), _dec3 = Memoize(), (_class
292
462
 
293
463
  constructor(balances, hydrate) {
294
464
  // handle Balances (convert to Balance[])
295
- if (balances instanceof Balances) return new Balances([...balances], hydrate);
465
+ if (balances instanceof Balances) return new Balances(balances.each, hydrate);
296
466
 
297
467
  // handle Balance (convert to Balance[])
298
468
  if (balances instanceof Balance) return new Balances([balances], hydrate);
@@ -307,19 +477,19 @@ let Balances = (_dec = Memoize(), _dec2 = Memoize(), _dec3 = Memoize(), (_class
307
477
  if (!isArrayOf(balances, Balance)) return new Balances(balances.map(storage => new Balance(storage)), hydrate);
308
478
 
309
479
  // handle Balance[]
310
- this.#balances = Object.fromEntries(balances.map(balance => [balance.id, balance]));
480
+ this.#balances = balances;
311
481
  if (hydrate !== undefined) this.hydrate(hydrate);
312
482
  }
313
483
 
314
484
  /**
315
485
  * Calling toJSON on a collection of balances will return the underlying BalanceJsonList.
316
486
  */
317
- toJSON = () => Object.fromEntries(Object.entries(this.#balances).map(([id, balance]) => {
487
+ toJSON = () => Object.fromEntries(this.#balances.map(balance => {
318
488
  try {
319
- return [id, balance.toJSON()];
489
+ return [balance.id, balance.toJSON()];
320
490
  } catch (error) {
321
491
  log.error("Failed to convert balance to JSON", error, {
322
- id,
492
+ id: balance.id,
323
493
  balance
324
494
  });
325
495
  return null;
@@ -339,7 +509,7 @@ let Balances = (_dec = Memoize(), _dec2 = Memoize(), _dec3 = Memoize(), (_class
339
509
  */
340
510
  [Symbol.iterator] = () =>
341
511
  // Create an array of the balances in this collection and return the result of its iterator.
342
- Object.values(this.#balances)[Symbol.iterator]();
512
+ this.#balances[Symbol.iterator]();
343
513
 
344
514
  /**
345
515
  * Hydrates all balances in this collection.
@@ -347,7 +517,7 @@ let Balances = (_dec = Memoize(), _dec2 = Memoize(), _dec3 = Memoize(), (_class
347
517
  * @param sources - The sources to hydrate from.
348
518
  */
349
519
  hydrate = sources => {
350
- Object.values(this.#balances).map(balance => balance.hydrate(sources));
520
+ this.#balances.map(balance => balance.hydrate(sources));
351
521
  };
352
522
 
353
523
  /**
@@ -356,7 +526,7 @@ let Balances = (_dec = Memoize(), _dec2 = Memoize(), _dec3 = Memoize(), (_class
356
526
  * @param id - The id of the balance to fetch.
357
527
  * @returns The balance if one exists, or none.
358
528
  */
359
- get = id => this.#balances[id] || null;
529
+ get = id => this.#balances.find(balance => balance.id === id) ?? null;
360
530
 
361
531
  /**
362
532
  * Retrieve balances from this collection by search query.
@@ -375,6 +545,27 @@ let Balances = (_dec = Memoize(), _dec2 = Memoize(), _dec3 = Memoize(), (_class
375
545
  return new Balances([...this].filter(filter));
376
546
  };
377
547
 
548
+ /**
549
+ * Filters this collection to exclude token balances where the token has a `mirrorOf` field
550
+ * and another balance exists in this collection for the token specified by the `mirrorOf` field.
551
+ */
552
+ filterMirrorTokens = () => new Balances([...this].filter(filterMirrorTokens));
553
+
554
+ /**
555
+ * Filters this collection to only include balances which are not zero.
556
+ */
557
+ filterNonZero = type => {
558
+ const filter = balance => balance[type].planck > 0n;
559
+ return this.find(filter);
560
+ };
561
+ /**
562
+ * Filters this collection to only include balances which are not zero AND have a fiat conversion rate.
563
+ */
564
+ filterNonZeroFiat = (type, currency) => {
565
+ const filter = balance => (balance[type].fiat(currency) ?? 0) > 0;
566
+ return this.find(filter);
567
+ };
568
+
378
569
  /**
379
570
  * Add some balances to this collection.
380
571
  * Added balances take priority over existing balances.
@@ -389,10 +580,8 @@ let Balances = (_dec = Memoize(), _dec2 = Memoize(), _dec3 = Memoize(), (_class
389
580
  if (balances instanceof Balance) return this.add(new Balances(balances));
390
581
 
391
582
  // merge balances
392
- const mergedBalances = {
393
- ...this.#balances
394
- };
395
- [...balances].forEach(balance => mergedBalances[balance.id] = balance);
583
+ const mergedBalances = Object.fromEntries(this.#balances.map(balance => [balance.id, balance]));
584
+ balances.each.forEach(balance => mergedBalances[balance.id] = balance);
396
585
 
397
586
  // return new balances
398
587
  return new Balances(Object.values(mergedBalances));
@@ -410,25 +599,23 @@ let Balances = (_dec = Memoize(), _dec2 = Memoize(), _dec3 = Memoize(), (_class
410
599
  // handle single id
411
600
  if (!Array.isArray(ids)) return this.remove([ids]);
412
601
 
413
- // merge balances
414
- const removedBalances = {
415
- ...this.#balances
416
- };
417
- ids.forEach(id => delete removedBalances[id]);
418
-
419
- // return new balances
420
- return new Balances(Object.values(removedBalances));
602
+ // merge and return new balances
603
+ return new Balances(this.#balances.filter(balance => !ids.includes(balance.id)));
421
604
  };
422
605
 
423
606
  // TODO: Add some more useful aggregator methods
424
607
 
608
+ get each() {
609
+ return [...this];
610
+ }
611
+
425
612
  /**
426
613
  * Get an array of balances in this collection, sorted by chain sortIndex.
427
614
  *
428
615
  * @returns A sorted array of the balances in this collection.
429
616
  */
430
617
  get sorted() {
431
- return [...this].sort((a, b) => ((a.chain || a.evmNetwork)?.sortIndex || Number.MAX_SAFE_INTEGER) - ((b.chain || b.evmNetwork)?.sortIndex || Number.MAX_SAFE_INTEGER));
618
+ return [...this].sort((a, b) => ((a.chain || a.evmNetwork)?.sortIndex ?? Number.MAX_SAFE_INTEGER) - ((b.chain || b.evmNetwork)?.sortIndex ?? Number.MAX_SAFE_INTEGER));
432
619
  }
433
620
 
434
621
  /**
@@ -451,12 +638,12 @@ let Balances = (_dec = Memoize(), _dec2 = Memoize(), _dec3 = Memoize(), (_class
451
638
  get sum() {
452
639
  return new SumBalancesFormatter(this);
453
640
  }
454
- }, (_applyDecoratedDescriptor(_class.prototype, "sorted", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "sorted"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "count", [_dec2], Object.getOwnPropertyDescriptor(_class.prototype, "count"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "sum", [_dec3], Object.getOwnPropertyDescriptor(_class.prototype, "sum"), _class.prototype)), _class));
641
+ }
455
642
 
456
643
  /**
457
644
  * An individual balance.
458
645
  */
459
- let Balance = (_dec4 = Memoize(), _dec5 = Memoize(), _dec6 = Memoize(), _dec7 = Memoize(), _dec8 = Memoize(), _dec9 = Memoize(), _dec10 = Memoize(), (_class2 = class Balance {
646
+ class Balance {
460
647
  //
461
648
  // Properties
462
649
  //
@@ -470,7 +657,6 @@ let Balance = (_dec4 = Memoize(), _dec5 = Memoize(), _dec6 = Memoize(), _dec7 =
470
657
  //
471
658
 
472
659
  constructor(storage, hydrate) {
473
- this.#format = memoize(this.#format);
474
660
  this.#storage = storage;
475
661
  if (hydrate !== undefined) this.hydrate(hydrate);
476
662
  }
@@ -502,13 +688,14 @@ let Balance = (_dec4 = Memoize(), _dec5 = Memoize(), _dec6 = Memoize(), _dec7 =
502
688
  get id() {
503
689
  const {
504
690
  source,
691
+ subSource,
505
692
  address,
506
693
  chainId,
507
694
  evmNetworkId,
508
695
  tokenId
509
696
  } = this.#storage;
510
697
  const locationId = chainId !== undefined ? chainId : evmNetworkId;
511
- return `${source}-${address}-${locationId}-${tokenId}`;
698
+ return [source, address, locationId, tokenId, subSource].filter(Boolean).join("-");
512
699
  }
513
700
  get source() {
514
701
  return this.#storage.source;
@@ -557,17 +744,43 @@ let Balance = (_dec4 = Memoize(), _dec5 = Memoize(), _dec6 = Memoize(), _dec7 =
557
744
  }
558
745
  /** The non-reserved balance of this token. Includes the frozen amount. Is included in the total. */
559
746
  get free() {
560
- 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"));
747
+ 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"));
561
748
  }
562
749
  /** The reserved balance of this token. Is included in the total. */
563
750
  get reserved() {
564
- 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"));
751
+ 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"));
752
+ }
753
+ get reserves() {
754
+ return (Array.isArray(this.#storage.reserves) ? this.#storage.reserves : [this.#storage.reserves]).flatMap(reserve => {
755
+ if (reserve === undefined) return [];
756
+ if (typeof reserve === "string") return {
757
+ label: "reserved",
758
+ amount: this.#format(reserve)
759
+ };
760
+ return {
761
+ ...reserve,
762
+ amount: this.#format(reserve.amount)
763
+ };
764
+ });
565
765
  }
566
766
  /** The frozen balance of this token. Is included in the free amount. */
567
767
  get locked() {
568
- 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) => BigMath.max(a, b), BigInt("0")) : BigInt(this.#storage.locks?.amount || "0"));
768
+ 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) => BigMath.max(a, b), 0n) : BigInt(this.#storage.locks?.amount || "0"));
769
+ }
770
+ get locks() {
771
+ return (Array.isArray(this.#storage.locks) ? this.#storage.locks : [this.#storage.locks]).flatMap(lock => {
772
+ if (lock === undefined) return [];
773
+ if (typeof lock === "string") return {
774
+ label: "other",
775
+ amount: this.#format(lock)
776
+ };
777
+ return {
778
+ ...lock,
779
+ amount: this.#format(lock.amount)
780
+ };
781
+ });
569
782
  }
570
- /** @depreacted - use balance.locked */
783
+ /** @deprecated Use balance.locked */
571
784
  get frozen() {
572
785
  return this.locked;
573
786
  }
@@ -580,7 +793,7 @@ let Balance = (_dec4 = Memoize(), _dec5 = Memoize(), _dec6 = Memoize(), _dec7 =
580
793
  const excludeAmount = excludeFromTransferableAmount(this.#storage.locks);
581
794
 
582
795
  // subtract the lock from the free amount (but don't go below 0)
583
- return this.#format(BigMath.max(this.free.planck - excludeAmount, BigInt("0")));
796
+ return this.#format(BigMath.max(this.free.planck - excludeAmount, 0n));
584
797
  }
585
798
  /** The feePayable balance of this token. Is generally the free amount - the feeFrozen amount. */
586
799
  get feePayable() {
@@ -588,13 +801,13 @@ let Balance = (_dec4 = Memoize(), _dec5 = Memoize(), _dec6 = Memoize(), _dec7 =
588
801
  if (!this.#storage.locks) return this.free;
589
802
 
590
803
  // find the largest lock which can't be used to pay tx fees
591
- const excludeAmount = excludeFromFeePayableLocks(this.#storage.locks).map(lock => BigInt(lock.amount)).reduce((max, lock) => BigMath.max(max, lock), BigInt("0"));
804
+ const excludeAmount = excludeFromFeePayableLocks(this.#storage.locks).map(lock => BigInt(lock.amount)).reduce((max, lock) => BigMath.max(max, lock), 0n);
592
805
 
593
806
  // subtract the lock from the free amount (but don't go below 0)
594
- return this.#format(BigMath.max(this.free.planck - excludeAmount, BigInt("0")));
807
+ return this.#format(BigMath.max(this.free.planck - excludeAmount, 0n));
595
808
  }
596
- }, (_applyDecoratedDescriptor(_class2.prototype, "total", [_dec4], Object.getOwnPropertyDescriptor(_class2.prototype, "total"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "free", [_dec5], Object.getOwnPropertyDescriptor(_class2.prototype, "free"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "reserved", [_dec6], Object.getOwnPropertyDescriptor(_class2.prototype, "reserved"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "locked", [_dec7], Object.getOwnPropertyDescriptor(_class2.prototype, "locked"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "frozen", [_dec8], Object.getOwnPropertyDescriptor(_class2.prototype, "frozen"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "transferable", [_dec9], Object.getOwnPropertyDescriptor(_class2.prototype, "transferable"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "feePayable", [_dec10], Object.getOwnPropertyDescriptor(_class2.prototype, "feePayable"), _class2.prototype)), _class2));
597
- let BalanceFormatter = (_dec11 = Memoize(), (_class3 = class BalanceFormatter {
809
+ }
810
+ class BalanceFormatter {
598
811
  #planck;
599
812
  #decimals;
600
813
  #fiatRatios;
@@ -602,7 +815,6 @@ let BalanceFormatter = (_dec11 = Memoize(), (_class3 = class BalanceFormatter {
602
815
  this.#planck = typeof planck === "bigint" ? planck.toString() : planck ?? "0";
603
816
  this.#decimals = decimals || 0;
604
817
  this.#fiatRatios = fiatRatios || null;
605
- this.fiat = memoize(this.fiat);
606
818
  }
607
819
  toJSON = () => this.#planck;
608
820
  get planck() {
@@ -617,26 +829,66 @@ let BalanceFormatter = (_dec11 = Memoize(), (_class3 = class BalanceFormatter {
617
829
  if (!ratio) return null;
618
830
  return parseFloat(this.tokens) * ratio;
619
831
  }
620
- }, (_applyDecoratedDescriptor(_class3.prototype, "tokens", [_dec11], Object.getOwnPropertyDescriptor(_class3.prototype, "tokens"), _class3.prototype)), _class3));
621
- let FiatSumBalancesFormatter = (_dec12 = Memoize(), _dec13 = Memoize(), _dec14 = Memoize(), _dec15 = Memoize(), _dec16 = Memoize(), _dec17 = Memoize(), _dec18 = Memoize(), (_class4 = class FiatSumBalancesFormatter {
832
+ }
833
+ class PlanckSumBalancesFormatter {
834
+ #balances;
835
+ constructor(balances) {
836
+ this.#balances = balances;
837
+ }
838
+ #sum = balanceField => {
839
+ // a function to get a planck amount from a balance
840
+ const planck = balance => balance[balanceField].planck ?? 0n;
841
+ return this.#balances.filterMirrorTokens().each.reduce(
842
+ // add the total amount to the planck amount of each balance
843
+ (total, balance) => total + planck(balance),
844
+ // start with a total of 0
845
+ 0n);
846
+ };
847
+
848
+ /**
849
+ * The total balance of these tokens. Includes the free and the reserved amount.
850
+ */
851
+ get total() {
852
+ return this.#sum("total");
853
+ }
854
+ /** The non-reserved balance of these tokens. Includes the frozen amount. Is included in the total. */
855
+ get free() {
856
+ return this.#sum("free");
857
+ }
858
+ /** The reserved balance of these tokens. Is included in the total. */
859
+ get reserved() {
860
+ return this.#sum("reserved");
861
+ }
862
+ /** The frozen balance of these tokens. Is included in the free amount. */
863
+ get locked() {
864
+ return this.#sum("locked");
865
+ }
866
+ /** @deprecated Use balances.locked */
867
+ get frozen() {
868
+ return this.locked;
869
+ }
870
+ /** The transferable balance of these tokens. Is generally the free amount - the miscFrozen amount. */
871
+ get transferable() {
872
+ return this.#sum("transferable");
873
+ }
874
+ /** The feePayable balance of these tokens. Is generally the free amount - the feeFrozen amount. */
875
+ get feePayable() {
876
+ return this.#sum("feePayable");
877
+ }
878
+ }
879
+ class FiatSumBalancesFormatter {
622
880
  #balances;
623
881
  #currency;
624
882
  constructor(balances, currency) {
625
883
  this.#balances = balances;
626
884
  this.#currency = currency;
627
- this.#sum = memoize(this.#sum);
628
885
  }
629
886
  #sum = balanceField => {
630
887
  // a function to get a fiat amount from a balance
631
- const fiat = balance => balance[balanceField].fiat(this.#currency) || 0;
632
-
633
- // a function to add two amounts
634
- const sum = (a, b) => a + b;
635
- return [...this.#balances].filter(filterMirrorTokens).reduce((total, balance) => sum(
636
- // add the total amount...
637
- total,
638
- // ...to the fiat amount of each balance
639
- fiat(balance)),
888
+ const fiat = balance => balance[balanceField].fiat(this.#currency) ?? 0;
889
+ return this.#balances.filterMirrorTokens().each.reduce(
890
+ // add the total amount to the fiat amount of each balance
891
+ (total, balance) => total + fiat(balance),
640
892
  // start with a total of 0
641
893
  0);
642
894
  };
@@ -659,7 +911,7 @@ let FiatSumBalancesFormatter = (_dec12 = Memoize(), _dec13 = Memoize(), _dec14 =
659
911
  get locked() {
660
912
  return this.#sum("locked");
661
913
  }
662
- /** @deprecated - use balances.locked */
914
+ /** @deprecated Use balances.locked */
663
915
  get frozen() {
664
916
  return this.locked;
665
917
  }
@@ -671,16 +923,18 @@ let FiatSumBalancesFormatter = (_dec12 = Memoize(), _dec13 = Memoize(), _dec14 =
671
923
  get feePayable() {
672
924
  return this.#sum("feePayable");
673
925
  }
674
- }, (_applyDecoratedDescriptor(_class4.prototype, "total", [_dec12], Object.getOwnPropertyDescriptor(_class4.prototype, "total"), _class4.prototype), _applyDecoratedDescriptor(_class4.prototype, "free", [_dec13], Object.getOwnPropertyDescriptor(_class4.prototype, "free"), _class4.prototype), _applyDecoratedDescriptor(_class4.prototype, "reserved", [_dec14], Object.getOwnPropertyDescriptor(_class4.prototype, "reserved"), _class4.prototype), _applyDecoratedDescriptor(_class4.prototype, "locked", [_dec15], Object.getOwnPropertyDescriptor(_class4.prototype, "locked"), _class4.prototype), _applyDecoratedDescriptor(_class4.prototype, "frozen", [_dec16], Object.getOwnPropertyDescriptor(_class4.prototype, "frozen"), _class4.prototype), _applyDecoratedDescriptor(_class4.prototype, "transferable", [_dec17], Object.getOwnPropertyDescriptor(_class4.prototype, "transferable"), _class4.prototype), _applyDecoratedDescriptor(_class4.prototype, "feePayable", [_dec18], Object.getOwnPropertyDescriptor(_class4.prototype, "feePayable"), _class4.prototype)), _class4));
926
+ }
675
927
  class SumBalancesFormatter {
676
928
  #balances;
677
929
  constructor(balances) {
678
930
  this.#balances = balances;
679
- this.fiat = memoize(this.fiat);
931
+ }
932
+ get planck() {
933
+ return new PlanckSumBalancesFormatter(this.#balances);
680
934
  }
681
935
  fiat(currency) {
682
936
  return new FiatSumBalancesFormatter(this.#balances, currency);
683
937
  }
684
938
  }
685
939
 
686
- export { Balance, BalanceFormatter, Balances, DefaultBalanceModule, FiatSumBalancesFormatter, StorageHelper, SumBalancesFormatter, TalismanBalancesDatabase, balances, db, excludeFromFeePayableLocks, excludeFromTransferableAmount, filterMirrorTokens, includeInTotalExtraAmount };
940
+ export { Balance, BalanceFormatter, BalanceStatusLive, Balances, DefaultBalanceModule, FiatSumBalancesFormatter, PlanckSumBalancesFormatter, RpcStateQueryHelper, StorageHelper, SumBalancesFormatter, TalismanBalancesDatabase, balances, createSubscriptionId, createTypeRegistryCache, db, deleteSubscriptionId, deriveStatuses, excludeFromFeePayableLocks, excludeFromTransferableAmount, filterMirrorTokens, findChainMeta, getValidSubscriptionIds, includeInTotalExtraAmount };