@talismn/balances 0.4.0 → 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.
- package/CHANGELOG.md +21 -0
- package/dist/declarations/src/helpers.d.ts +62 -4
- package/dist/declarations/src/types/balances.d.ts +48 -2
- package/dist/declarations/src/types/balancetypes.d.ts +9 -1
- package/dist/talismn-balances.cjs.dev.js +322 -38
- package/dist/talismn-balances.cjs.prod.js +322 -38
- package/dist/talismn-balances.esm.js +314 -39
- package/package.json +14 -12
@@ -1,7 +1,8 @@
|
|
1
1
|
import { Dexie } from 'dexie';
|
2
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
6
|
|
6
7
|
// TODO: Document default balances module purpose/usage
|
7
8
|
const DefaultBalanceModule = type => ({
|
@@ -59,7 +60,7 @@ const db = new TalismanBalancesDatabase();
|
|
59
60
|
|
60
61
|
var packageJson = {
|
61
62
|
name: "@talismn/balances",
|
62
|
-
version: "0.4.
|
63
|
+
version: "0.4.1",
|
63
64
|
author: "Talisman",
|
64
65
|
homepage: "https://talisman.xyz",
|
65
66
|
license: "UNLICENSED",
|
@@ -82,30 +83,32 @@ var packageJson = {
|
|
82
83
|
},
|
83
84
|
scripts: {
|
84
85
|
test: "jest",
|
85
|
-
lint: "eslint
|
86
|
+
lint: "eslint src --max-warnings 0",
|
86
87
|
clean: "rm -rf dist && rm -rf .turbo rm -rf node_modules"
|
87
88
|
},
|
88
89
|
dependencies: {
|
89
|
-
"@talismn/chain-connector": "workspace
|
90
|
-
"@talismn/chain-connector-evm": "workspace
|
91
|
-
"@talismn/chaindata-provider": "workspace
|
92
|
-
"@talismn/token-rates": "workspace
|
93
|
-
"@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:*",
|
94
95
|
anylogger: "^1.0.11",
|
95
|
-
dexie: "^3.2.3"
|
96
|
+
dexie: "^3.2.3",
|
97
|
+
lodash: "4.17.21"
|
96
98
|
},
|
97
99
|
devDependencies: {
|
98
|
-
"@polkadot/types": "^
|
99
|
-
"@talismn/eslint-config": "workspace
|
100
|
-
"@talismn/tsconfig": "workspace
|
100
|
+
"@polkadot/types": "^10.1.4",
|
101
|
+
"@talismn/eslint-config": "workspace:*",
|
102
|
+
"@talismn/tsconfig": "workspace:*",
|
101
103
|
"@types/jest": "^27.5.1",
|
104
|
+
"@types/lodash": "^4.14.180",
|
102
105
|
eslint: "^8.4.0",
|
103
106
|
jest: "^28.1.0",
|
104
107
|
"ts-jest": "^28.0.2",
|
105
108
|
typescript: "^4.6.4"
|
106
109
|
},
|
107
110
|
peerDependencies: {
|
108
|
-
"@polkadot/types": "
|
111
|
+
"@polkadot/types": "10.x"
|
109
112
|
},
|
110
113
|
preconstruct: {
|
111
114
|
entrypoints: [
|
@@ -123,6 +126,11 @@ var packageJson = {
|
|
123
126
|
|
124
127
|
var log = anylogger(packageJson.name);
|
125
128
|
|
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
|
+
|
126
134
|
async function balances(balanceModule, addressesByToken, callback) {
|
127
135
|
// subscription request
|
128
136
|
if (callback !== undefined) return await balanceModule.subscribeBalances(addressesByToken, callback);
|
@@ -138,8 +146,14 @@ const createTypeRegistryCache = () => {
|
|
138
146
|
if (cached) return cached;
|
139
147
|
const typeRegistry = new TypeRegistry();
|
140
148
|
if (typeof metadataRpc === "string") {
|
141
|
-
|
142
|
-
|
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
|
+
}
|
143
157
|
}
|
144
158
|
typeRegistryCache.set(chainId, typeRegistry);
|
145
159
|
return typeRegistry;
|
@@ -148,11 +162,78 @@ const createTypeRegistryCache = () => {
|
|
148
162
|
getOrCreateTypeRegistry
|
149
163
|
};
|
150
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
|
+
};
|
151
190
|
const filterMirrorTokens = (balance, i, balances) => {
|
152
|
-
// TODO: implement a mirrorOf property, which should be set from chaindata
|
153
191
|
const mirrorOf = balance.token?.mirrorOf;
|
154
192
|
return !mirrorOf || !balances.find(b => b.tokenId === mirrorOf);
|
155
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
|
+
});
|
156
237
|
|
157
238
|
/**
|
158
239
|
* Used by a variety of balance modules to help encode and decode substrate state calls.
|
@@ -163,7 +244,11 @@ class StorageHelper {
|
|
163
244
|
#module;
|
164
245
|
#method;
|
165
246
|
#parameters;
|
247
|
+
|
248
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
166
249
|
tags = null;
|
250
|
+
|
251
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
167
252
|
constructor(registry, module, method, ...parameters) {
|
168
253
|
this.#registry = registry;
|
169
254
|
this.#module = module;
|
@@ -197,6 +282,8 @@ class StorageHelper {
|
|
197
282
|
get parameters() {
|
198
283
|
return this.#parameters;
|
199
284
|
}
|
285
|
+
|
286
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
200
287
|
tag(tags) {
|
201
288
|
this.tags = tags;
|
202
289
|
return this;
|
@@ -235,10 +322,106 @@ class StorageHelper {
|
|
235
322
|
}
|
236
323
|
}
|
237
324
|
|
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
|
+
}
|
389
|
+
}
|
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
|
+
|
238
421
|
function excludeFromTransferableAmount(locks) {
|
239
422
|
if (typeof locks === "string") return BigInt(locks);
|
240
423
|
if (!Array.isArray(locks)) locks = [locks];
|
241
|
-
return locks.filter(lock => lock.includeInTransferable !== true).map(lock => BigInt(lock.amount)).reduce((max, lock) => BigMath.max(max, lock),
|
424
|
+
return locks.filter(lock => lock.includeInTransferable !== true).map(lock => BigInt(lock.amount)).reduce((max, lock) => BigMath.max(max, lock), 0n);
|
242
425
|
}
|
243
426
|
function excludeFromFeePayableLocks(locks) {
|
244
427
|
if (typeof locks === "string") return [];
|
@@ -249,9 +432,9 @@ function excludeFromFeePayableLocks(locks) {
|
|
249
432
|
/** A labelled extra amount of a balance */
|
250
433
|
|
251
434
|
function includeInTotalExtraAmount(extra) {
|
252
|
-
if (!extra) return
|
435
|
+
if (!extra) return 0n;
|
253
436
|
if (!Array.isArray(extra)) extra = [extra];
|
254
|
-
return extra.filter(extra => extra.includeInTotal).map(extra => BigInt(extra.amount)).reduce((a, b) => a + b,
|
437
|
+
return extra.filter(extra => extra.includeInTotal).map(extra => BigInt(extra.amount)).reduce((a, b) => a + b, 0n);
|
255
438
|
}
|
256
439
|
|
257
440
|
/** Used by plugins to help define their custom `BalanceType` */
|
@@ -262,7 +445,7 @@ function includeInTotalExtraAmount(extra) {
|
|
262
445
|
*/
|
263
446
|
|
264
447
|
/** A utility type used to extract the underlying `BalanceType` of a specific source from a generalised `BalanceJson` */
|
265
|
-
|
448
|
+
/** TODO: Remove this in favour of a frontend-friendly `ChaindataProvider` */
|
266
449
|
/**
|
267
450
|
* A collection of balances.
|
268
451
|
*/
|
@@ -362,6 +545,27 @@ class Balances {
|
|
362
545
|
return new Balances([...this].filter(filter));
|
363
546
|
};
|
364
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
|
+
|
365
569
|
/**
|
366
570
|
* Add some balances to this collection.
|
367
571
|
* Added balances take priority over existing balances.
|
@@ -484,13 +688,14 @@ class Balance {
|
|
484
688
|
get id() {
|
485
689
|
const {
|
486
690
|
source,
|
691
|
+
subSource,
|
487
692
|
address,
|
488
693
|
chainId,
|
489
694
|
evmNetworkId,
|
490
695
|
tokenId
|
491
696
|
} = this.#storage;
|
492
697
|
const locationId = chainId !== undefined ? chainId : evmNetworkId;
|
493
|
-
return
|
698
|
+
return [source, address, locationId, tokenId, subSource].filter(Boolean).join("-");
|
494
699
|
}
|
495
700
|
get source() {
|
496
701
|
return this.#storage.source;
|
@@ -539,17 +744,43 @@ class Balance {
|
|
539
744
|
}
|
540
745
|
/** The non-reserved balance of this token. Includes the frozen amount. Is included in the total. */
|
541
746
|
get free() {
|
542
|
-
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,
|
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"));
|
543
748
|
}
|
544
749
|
/** The reserved balance of this token. Is included in the total. */
|
545
750
|
get reserved() {
|
546
|
-
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,
|
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
|
+
});
|
547
765
|
}
|
548
766
|
/** The frozen balance of this token. Is included in the free amount. */
|
549
767
|
get locked() {
|
550
|
-
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),
|
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
|
+
});
|
551
782
|
}
|
552
|
-
/** @
|
783
|
+
/** @deprecated Use balance.locked */
|
553
784
|
get frozen() {
|
554
785
|
return this.locked;
|
555
786
|
}
|
@@ -562,7 +793,7 @@ class Balance {
|
|
562
793
|
const excludeAmount = excludeFromTransferableAmount(this.#storage.locks);
|
563
794
|
|
564
795
|
// subtract the lock from the free amount (but don't go below 0)
|
565
|
-
return this.#format(BigMath.max(this.free.planck - excludeAmount,
|
796
|
+
return this.#format(BigMath.max(this.free.planck - excludeAmount, 0n));
|
566
797
|
}
|
567
798
|
/** The feePayable balance of this token. Is generally the free amount - the feeFrozen amount. */
|
568
799
|
get feePayable() {
|
@@ -570,10 +801,10 @@ class Balance {
|
|
570
801
|
if (!this.#storage.locks) return this.free;
|
571
802
|
|
572
803
|
// find the largest lock which can't be used to pay tx fees
|
573
|
-
const excludeAmount = excludeFromFeePayableLocks(this.#storage.locks).map(lock => BigInt(lock.amount)).reduce((max, lock) => BigMath.max(max, lock),
|
804
|
+
const excludeAmount = excludeFromFeePayableLocks(this.#storage.locks).map(lock => BigInt(lock.amount)).reduce((max, lock) => BigMath.max(max, lock), 0n);
|
574
805
|
|
575
806
|
// subtract the lock from the free amount (but don't go below 0)
|
576
|
-
return this.#format(BigMath.max(this.free.planck - excludeAmount,
|
807
|
+
return this.#format(BigMath.max(this.free.planck - excludeAmount, 0n));
|
577
808
|
}
|
578
809
|
}
|
579
810
|
class BalanceFormatter {
|
@@ -599,6 +830,52 @@ class BalanceFormatter {
|
|
599
830
|
return parseFloat(this.tokens) * ratio;
|
600
831
|
}
|
601
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
|
+
}
|
602
879
|
class FiatSumBalancesFormatter {
|
603
880
|
#balances;
|
604
881
|
#currency;
|
@@ -608,15 +885,10 @@ class FiatSumBalancesFormatter {
|
|
608
885
|
}
|
609
886
|
#sum = balanceField => {
|
610
887
|
// a function to get a fiat amount from a balance
|
611
|
-
const fiat = balance => balance[balanceField].fiat(this.#currency)
|
612
|
-
|
613
|
-
//
|
614
|
-
|
615
|
-
return [...this.#balances].filter(filterMirrorTokens).reduce((total, balance) => sum(
|
616
|
-
// add the total amount...
|
617
|
-
total,
|
618
|
-
// ...to the fiat amount of each balance
|
619
|
-
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),
|
620
892
|
// start with a total of 0
|
621
893
|
0);
|
622
894
|
};
|
@@ -639,7 +911,7 @@ class FiatSumBalancesFormatter {
|
|
639
911
|
get locked() {
|
640
912
|
return this.#sum("locked");
|
641
913
|
}
|
642
|
-
/** @deprecated
|
914
|
+
/** @deprecated Use balances.locked */
|
643
915
|
get frozen() {
|
644
916
|
return this.locked;
|
645
917
|
}
|
@@ -657,9 +929,12 @@ class SumBalancesFormatter {
|
|
657
929
|
constructor(balances) {
|
658
930
|
this.#balances = balances;
|
659
931
|
}
|
932
|
+
get planck() {
|
933
|
+
return new PlanckSumBalancesFormatter(this.#balances);
|
934
|
+
}
|
660
935
|
fiat(currency) {
|
661
936
|
return new FiatSumBalancesFormatter(this.#balances, currency);
|
662
937
|
}
|
663
938
|
}
|
664
939
|
|
665
|
-
export { Balance, BalanceFormatter, Balances, DefaultBalanceModule, FiatSumBalancesFormatter, StorageHelper, SumBalancesFormatter, TalismanBalancesDatabase, balances, createTypeRegistryCache, 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 };
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@talismn/balances",
|
3
|
-
"version": "0.4.
|
3
|
+
"version": "0.4.1",
|
4
4
|
"author": "Talisman",
|
5
5
|
"homepage": "https://talisman.xyz",
|
6
6
|
"license": "UNLICENSED",
|
@@ -23,30 +23,32 @@
|
|
23
23
|
},
|
24
24
|
"scripts": {
|
25
25
|
"test": "jest",
|
26
|
-
"lint": "eslint
|
26
|
+
"lint": "eslint src --max-warnings 0",
|
27
27
|
"clean": "rm -rf dist && rm -rf .turbo rm -rf node_modules"
|
28
28
|
},
|
29
29
|
"dependencies": {
|
30
|
-
"@talismn/chain-connector": "
|
31
|
-
"@talismn/chain-connector-evm": "
|
32
|
-
"@talismn/chaindata-provider": "
|
33
|
-
"@talismn/token-rates": "
|
34
|
-
"@talismn/util": "
|
30
|
+
"@talismn/chain-connector": "0.4.4",
|
31
|
+
"@talismn/chain-connector-evm": "0.4.4",
|
32
|
+
"@talismn/chaindata-provider": "0.4.4",
|
33
|
+
"@talismn/token-rates": "0.1.16",
|
34
|
+
"@talismn/util": "0.1.9",
|
35
35
|
"anylogger": "^1.0.11",
|
36
|
-
"dexie": "^3.2.3"
|
36
|
+
"dexie": "^3.2.3",
|
37
|
+
"lodash": "4.17.21"
|
37
38
|
},
|
38
39
|
"devDependencies": {
|
39
|
-
"@polkadot/types": "^
|
40
|
-
"@talismn/eslint-config": "
|
41
|
-
"@talismn/tsconfig": "
|
40
|
+
"@polkadot/types": "^10.1.4",
|
41
|
+
"@talismn/eslint-config": "0.0.2",
|
42
|
+
"@talismn/tsconfig": "0.0.2",
|
42
43
|
"@types/jest": "^27.5.1",
|
44
|
+
"@types/lodash": "^4.14.180",
|
43
45
|
"eslint": "^8.4.0",
|
44
46
|
"jest": "^28.1.0",
|
45
47
|
"ts-jest": "^28.0.2",
|
46
48
|
"typescript": "^4.6.4"
|
47
49
|
},
|
48
50
|
"peerDependencies": {
|
49
|
-
"@polkadot/types": "
|
51
|
+
"@polkadot/types": "10.x"
|
50
52
|
},
|
51
53
|
"preconstruct": {
|
52
54
|
"entrypoints": [
|