@talismn/balances 0.2.3 → 0.3.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 +31 -0
- package/dist/{BalanceModule.d.ts → declarations/src/BalanceModule.d.ts} +7 -7
- package/dist/{TalismanBalancesDatabase.d.ts → declarations/src/TalismanBalancesDatabase.d.ts} +0 -0
- package/dist/{helpers.d.ts → declarations/src/helpers.d.ts} +17 -1
- package/dist/{index.d.ts → declarations/src/index.d.ts} +0 -0
- package/dist/{log.d.ts → declarations/src/log.d.ts} +0 -0
- package/dist/{plugins.d.ts → declarations/src/plugins.d.ts} +0 -0
- package/dist/declarations/src/types/addresses.d.ts +4 -0
- package/dist/{types → declarations/src/types}/balances.d.ts +4 -4
- package/dist/{types → declarations/src/types}/balancetypes.d.ts +12 -12
- package/dist/{types → declarations/src/types}/index.d.ts +0 -0
- package/dist/{types → declarations/src/types}/subscriptions.d.ts +1 -1
- package/dist/talismn-balances.cjs.d.ts +1 -0
- package/dist/talismn-balances.cjs.dev.js +705 -0
- package/dist/talismn-balances.cjs.js +7 -0
- package/dist/talismn-balances.cjs.prod.js +705 -0
- package/dist/talismn-balances.esm.js +683 -0
- package/package.json +20 -15
- package/plugins/dist/talismn-balances-plugins.cjs.d.ts +1 -0
- package/plugins/dist/talismn-balances-plugins.cjs.dev.js +2 -0
- package/plugins/dist/talismn-balances-plugins.cjs.js +7 -0
- package/plugins/dist/talismn-balances-plugins.cjs.prod.js +2 -0
- package/plugins/dist/talismn-balances-plugins.esm.js +1 -0
- package/plugins/package.json +2 -3
- package/dist/BalanceModule.js +0 -29
- package/dist/TalismanBalancesDatabase.js +0 -23
- package/dist/helpers.js +0 -11
- package/dist/index.js +0 -31
- package/dist/log.js +0 -10
- package/dist/plugins.js +0 -2
- package/dist/types/addresses.d.ts +0 -4
- package/dist/types/addresses.js +0 -2
- package/dist/types/balances.js +0 -470
- package/dist/types/balancetypes.js +0 -34
- package/dist/types/index.js +0 -20
- package/dist/types/subscriptions.js +0 -2
@@ -0,0 +1,683 @@
|
|
1
|
+
import { Dexie } from 'dexie';
|
2
|
+
import { decorateStorage, StorageKey } from '@polkadot/types';
|
3
|
+
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
|
+
|
12
|
+
// TODO: Document default balances module purpose/usage
|
13
|
+
const DefaultBalanceModule = type => ({
|
14
|
+
get type() {
|
15
|
+
return type;
|
16
|
+
},
|
17
|
+
async fetchSubstrateChainMeta() {
|
18
|
+
return null;
|
19
|
+
},
|
20
|
+
async fetchEvmChainMeta() {
|
21
|
+
return null;
|
22
|
+
},
|
23
|
+
async fetchSubstrateChainTokens() {
|
24
|
+
return Promise.resolve({});
|
25
|
+
},
|
26
|
+
async fetchEvmChainTokens() {
|
27
|
+
return Promise.resolve({});
|
28
|
+
},
|
29
|
+
async subscribeBalances(_chainConnectors, _chaindataProvider, _addressesByToken, callback) {
|
30
|
+
callback(new Error("Balance subscriptions are not implemented in this module."));
|
31
|
+
return () => {};
|
32
|
+
},
|
33
|
+
async fetchBalances() {
|
34
|
+
throw new Error("Balance fetching is not implemented in this module.");
|
35
|
+
}
|
36
|
+
});
|
37
|
+
|
38
|
+
//
|
39
|
+
// internal
|
40
|
+
//
|
41
|
+
|
42
|
+
class TalismanBalancesDatabase extends Dexie {
|
43
|
+
constructor() {
|
44
|
+
super("TalismanBalances");
|
45
|
+
|
46
|
+
// https://dexie.org/docs/Tutorial/Design#database-versioning
|
47
|
+
this.version(1).stores({
|
48
|
+
// You only need to specify properties that you wish to index.
|
49
|
+
// The object store will allow any properties on your stored objects but you can only query them by indexed properties
|
50
|
+
// https://dexie.org/docs/API-Reference#declare-database
|
51
|
+
//
|
52
|
+
// Never index properties containing images, movies or large (huge) strings. Store them in IndexedDB, yes! but just don’t index them!
|
53
|
+
// https://dexie.org/docs/Version/Version.stores()#warning
|
54
|
+
balances: "id, source, status, address, tokenId"
|
55
|
+
});
|
56
|
+
|
57
|
+
// this.on("ready", async () => {})
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
const db = new TalismanBalancesDatabase();
|
62
|
+
|
63
|
+
var packageJson = {
|
64
|
+
name: "@talismn/balances",
|
65
|
+
version: "0.3.1",
|
66
|
+
author: "Talisman",
|
67
|
+
homepage: "https://talisman.xyz",
|
68
|
+
license: "UNLICENSED",
|
69
|
+
publishConfig: {
|
70
|
+
access: "public"
|
71
|
+
},
|
72
|
+
repository: {
|
73
|
+
directory: "packages/balances",
|
74
|
+
type: "git",
|
75
|
+
url: "https://github.com/talismansociety/talisman.git"
|
76
|
+
},
|
77
|
+
main: "dist/talismn-balances.cjs.js",
|
78
|
+
module: "dist/talismn-balances.esm.js",
|
79
|
+
files: [
|
80
|
+
"/dist",
|
81
|
+
"/plugins"
|
82
|
+
],
|
83
|
+
engines: {
|
84
|
+
node: ">=14"
|
85
|
+
},
|
86
|
+
scripts: {
|
87
|
+
test: "jest",
|
88
|
+
lint: "eslint . --max-warnings 0",
|
89
|
+
clean: "rm -rf dist && rm -rf .turbo rm -rf node_modules"
|
90
|
+
},
|
91
|
+
dependencies: {
|
92
|
+
"@polkadot/types": "9.10.5",
|
93
|
+
"@talismn/chain-connector": "workspace:^",
|
94
|
+
"@talismn/chain-connector-evm": "workspace:^",
|
95
|
+
"@talismn/chaindata-provider": "workspace:^",
|
96
|
+
"@talismn/token-rates": "workspace:^",
|
97
|
+
"@talismn/util": "workspace:^",
|
98
|
+
anylogger: "^1.0.11",
|
99
|
+
dexie: "^3.2.2",
|
100
|
+
lodash: "^4.17.21",
|
101
|
+
"typescript-memoize": "^1.1.0"
|
102
|
+
},
|
103
|
+
devDependencies: {
|
104
|
+
"@talismn/eslint-config": "workspace:^",
|
105
|
+
"@talismn/tsconfig": "workspace:^",
|
106
|
+
"@types/jest": "^27.5.1",
|
107
|
+
eslint: "^8.4.0",
|
108
|
+
jest: "^28.1.0",
|
109
|
+
"ts-jest": "^28.0.2",
|
110
|
+
typescript: "^4.6.4"
|
111
|
+
},
|
112
|
+
preconstruct: {
|
113
|
+
entrypoints: [
|
114
|
+
"index.ts",
|
115
|
+
"plugins.ts"
|
116
|
+
]
|
117
|
+
},
|
118
|
+
eslintConfig: {
|
119
|
+
root: true,
|
120
|
+
"extends": [
|
121
|
+
"@talismn/eslint-config/base"
|
122
|
+
]
|
123
|
+
}
|
124
|
+
};
|
125
|
+
|
126
|
+
var log = anylogger(packageJson.name);
|
127
|
+
|
128
|
+
async function balances(balanceModule, chainConnectors, chaindataProvider, addressesByToken, callback) {
|
129
|
+
// subscription request
|
130
|
+
if (callback !== undefined) return await balanceModule.subscribeBalances(chainConnectors, chaindataProvider, addressesByToken, callback);
|
131
|
+
|
132
|
+
// one-off request
|
133
|
+
return await balanceModule.fetchBalances(chainConnectors, chaindataProvider, addressesByToken);
|
134
|
+
}
|
135
|
+
const filterMirrorTokens = (balance, i, balances) => {
|
136
|
+
// TODO implement a mirrorOf property, which should be set from chaindata
|
137
|
+
const mirrorOf = balance.token?.mirrorOf;
|
138
|
+
return !mirrorOf || !balances.find(b => b.tokenId === mirrorOf);
|
139
|
+
};
|
140
|
+
|
141
|
+
/**
|
142
|
+
* Used by a variety of balance modules to help encode and decode substrate state calls.
|
143
|
+
*/
|
144
|
+
class StorageHelper {
|
145
|
+
#registry;
|
146
|
+
#storageKey;
|
147
|
+
#module;
|
148
|
+
#method;
|
149
|
+
#parameters;
|
150
|
+
tags = null;
|
151
|
+
constructor(registry, module, method, ...parameters) {
|
152
|
+
this.#registry = registry;
|
153
|
+
this.#module = module;
|
154
|
+
this.#method = method;
|
155
|
+
this.#parameters = parameters;
|
156
|
+
const _metadataVersion = 0; // is not used inside the decorateStorage function
|
157
|
+
let query;
|
158
|
+
try {
|
159
|
+
query = decorateStorage(registry, registry.metadata, _metadataVersion);
|
160
|
+
} catch (error) {
|
161
|
+
log.debug(`Failed to decorate storage: ${error.message}`);
|
162
|
+
this.#storageKey = null;
|
163
|
+
}
|
164
|
+
try {
|
165
|
+
if (!query) throw new Error(`decoratedStorage unavailable`);
|
166
|
+
this.#storageKey = new StorageKey(registry, parameters ? [query[module][method], parameters] : query[module][method]);
|
167
|
+
} catch (error) {
|
168
|
+
log.debug(`Failed to create storageKey ${module || "unknown"}.${method || "unknown"}: ${error.message}`);
|
169
|
+
this.#storageKey = null;
|
170
|
+
}
|
171
|
+
}
|
172
|
+
get stateKey() {
|
173
|
+
return this.#storageKey?.toHex();
|
174
|
+
}
|
175
|
+
get module() {
|
176
|
+
return this.#module;
|
177
|
+
}
|
178
|
+
get method() {
|
179
|
+
return this.#method;
|
180
|
+
}
|
181
|
+
get parameters() {
|
182
|
+
return this.#parameters;
|
183
|
+
}
|
184
|
+
tag(tags) {
|
185
|
+
this.tags = tags;
|
186
|
+
return this;
|
187
|
+
}
|
188
|
+
decode(input) {
|
189
|
+
if (!this.#storageKey) return;
|
190
|
+
return this.#decodeStorageScaleResponse(this.#registry, this.#storageKey, input);
|
191
|
+
}
|
192
|
+
#decodeStorageScaleResponse(typeRegistry, storageKey, input) {
|
193
|
+
if (input === undefined || input === null) return;
|
194
|
+
const type = storageKey.outputType || "Raw";
|
195
|
+
const meta = storageKey.meta || {
|
196
|
+
fallback: undefined,
|
197
|
+
modifier: {
|
198
|
+
isOptional: true
|
199
|
+
},
|
200
|
+
type: {
|
201
|
+
asMap: {
|
202
|
+
linked: {
|
203
|
+
isTrue: false
|
204
|
+
}
|
205
|
+
},
|
206
|
+
isMap: false
|
207
|
+
}
|
208
|
+
};
|
209
|
+
try {
|
210
|
+
return typeRegistry.createTypeUnsafe(type, [meta.modifier.isOptional ? typeRegistry.createTypeUnsafe(type, [input], {
|
211
|
+
isPedantic: true
|
212
|
+
}) : input], {
|
213
|
+
isOptional: meta.modifier.isOptional,
|
214
|
+
isPedantic: !meta.modifier.isOptional
|
215
|
+
});
|
216
|
+
} catch (error) {
|
217
|
+
throw new Error(`Unable to decode storage ${storageKey.section || "unknown"}.${storageKey.method || "unknown"}: ${error.message}`);
|
218
|
+
}
|
219
|
+
}
|
220
|
+
}
|
221
|
+
|
222
|
+
function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
|
223
|
+
var desc = {};
|
224
|
+
Object.keys(descriptor).forEach(function (key) {
|
225
|
+
desc[key] = descriptor[key];
|
226
|
+
});
|
227
|
+
desc.enumerable = !!desc.enumerable;
|
228
|
+
desc.configurable = !!desc.configurable;
|
229
|
+
if ('value' in desc || desc.initializer) {
|
230
|
+
desc.writable = true;
|
231
|
+
}
|
232
|
+
desc = decorators.slice().reverse().reduce(function (desc, decorator) {
|
233
|
+
return decorator(target, property, desc) || desc;
|
234
|
+
}, desc);
|
235
|
+
if (context && desc.initializer !== void 0) {
|
236
|
+
desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
|
237
|
+
desc.initializer = undefined;
|
238
|
+
}
|
239
|
+
if (desc.initializer === void 0) {
|
240
|
+
Object.defineProperty(target, property, desc);
|
241
|
+
desc = null;
|
242
|
+
}
|
243
|
+
return desc;
|
244
|
+
}
|
245
|
+
|
246
|
+
function excludeFromTransferableAmount(locks) {
|
247
|
+
if (typeof locks === "string") return BigInt(locks);
|
248
|
+
if (!Array.isArray(locks)) locks = [locks];
|
249
|
+
return locks.filter(lock => lock.includeInTransferable !== true).map(lock => BigInt(lock.amount)).reduce((max, lock) => BigMath.max(max, lock), BigInt("0"));
|
250
|
+
}
|
251
|
+
function excludeFromFeePayableLocks(locks) {
|
252
|
+
if (typeof locks === "string") return [];
|
253
|
+
if (!Array.isArray(locks)) locks = [locks];
|
254
|
+
return locks.filter(lock => lock.excludeFromFeePayable);
|
255
|
+
}
|
256
|
+
|
257
|
+
/** A labelled extra amount of a balance */
|
258
|
+
|
259
|
+
function includeInTotalExtraAmount(extra) {
|
260
|
+
if (!extra) return BigInt("0");
|
261
|
+
if (!Array.isArray(extra)) extra = [extra];
|
262
|
+
return extra.filter(extra => extra.includeInTotal).map(extra => BigInt(extra.amount)).reduce((a, b) => a + b, BigInt("0"));
|
263
|
+
}
|
264
|
+
|
265
|
+
/** Used by plugins to help define their custom `BalanceType` */
|
266
|
+
|
267
|
+
var _dec, _dec2, _dec3, _class, _dec4, _dec5, _dec6, _dec7, _dec8, _dec9, _dec10, _class2, _dec11, _class3, _dec12, _dec13, _dec14, _dec15, _dec16, _dec17, _dec18, _class4;
|
268
|
+
|
269
|
+
/**
|
270
|
+
* Have the importing library define its Token and BalanceJson enums (as a sum type of all plugins) and pass them into some
|
271
|
+
* internal global typescript context, which is then picked up on by this module.
|
272
|
+
*/
|
273
|
+
|
274
|
+
/** A utility type used to extract the underlying `BalanceType` of a specific source from a generalised `BalanceJson` */
|
275
|
+
|
276
|
+
/**
|
277
|
+
* A collection of balances.
|
278
|
+
*/
|
279
|
+
let Balances = (_dec = Memoize(), _dec2 = Memoize(), _dec3 = Memoize(), (_class = class Balances {
|
280
|
+
//
|
281
|
+
// Properties
|
282
|
+
//
|
283
|
+
|
284
|
+
#balances = {};
|
285
|
+
|
286
|
+
//
|
287
|
+
// Methods
|
288
|
+
//
|
289
|
+
|
290
|
+
constructor(balances, hydrate) {
|
291
|
+
// handle Balances (convert to Balance[])
|
292
|
+
if (balances instanceof Balances) return new Balances([...balances], hydrate);
|
293
|
+
|
294
|
+
// handle Balance (convert to Balance[])
|
295
|
+
if (balances instanceof Balance) return new Balances([balances], hydrate);
|
296
|
+
|
297
|
+
// handle BalanceJsonList (the only remaining non-array type of balances) (convert to BalanceJson[])
|
298
|
+
if (!Array.isArray(balances)) return new Balances(Object.values(balances), hydrate);
|
299
|
+
|
300
|
+
// handle no balances
|
301
|
+
if (balances.length === 0) return this;
|
302
|
+
|
303
|
+
// handle BalanceJson[]
|
304
|
+
if (!isArrayOf(balances, Balance)) return new Balances(balances.map(storage => new Balance(storage)), hydrate);
|
305
|
+
|
306
|
+
// handle Balance[]
|
307
|
+
this.#balances = Object.fromEntries(balances.map(balance => [balance.id, balance]));
|
308
|
+
if (hydrate !== undefined) this.hydrate(hydrate);
|
309
|
+
}
|
310
|
+
|
311
|
+
/**
|
312
|
+
* Calling toJSON on a collection of balances will return the underlying BalanceJsonList.
|
313
|
+
*/
|
314
|
+
toJSON = () => Object.fromEntries(Object.entries(this.#balances).map(([id, balance]) => {
|
315
|
+
try {
|
316
|
+
return [id, balance.toJSON()];
|
317
|
+
} catch (error) {
|
318
|
+
log.error("Failed to convert balance to JSON", error, {
|
319
|
+
id,
|
320
|
+
balance
|
321
|
+
});
|
322
|
+
return null;
|
323
|
+
}
|
324
|
+
}).filter(Array.isArray));
|
325
|
+
|
326
|
+
/**
|
327
|
+
* Allows the collection to be iterated over.
|
328
|
+
*
|
329
|
+
* @example
|
330
|
+
* [...balances].forEach(balance => { // do something // })
|
331
|
+
*
|
332
|
+
* @example
|
333
|
+
* for (const balance of balances) {
|
334
|
+
* // do something
|
335
|
+
* }
|
336
|
+
*/
|
337
|
+
[Symbol.iterator] = () =>
|
338
|
+
// Create an array of the balances in this collection and return the result of its iterator.
|
339
|
+
Object.values(this.#balances)[Symbol.iterator]();
|
340
|
+
|
341
|
+
/**
|
342
|
+
* Hydrates all balances in this collection.
|
343
|
+
*
|
344
|
+
* @param sources - The sources to hydrate from.
|
345
|
+
*/
|
346
|
+
hydrate = sources => {
|
347
|
+
Object.values(this.#balances).map(balance => balance.hydrate(sources));
|
348
|
+
};
|
349
|
+
|
350
|
+
/**
|
351
|
+
* Retrieve a balance from this collection by id.
|
352
|
+
*
|
353
|
+
* @param id - The id of the balance to fetch.
|
354
|
+
* @returns The balance if one exists, or none.
|
355
|
+
*/
|
356
|
+
get = id => this.#balances[id] || null;
|
357
|
+
|
358
|
+
/**
|
359
|
+
* Retrieve balances from this collection by search query.
|
360
|
+
*
|
361
|
+
* @param query - The search query.
|
362
|
+
* @returns All balances which match the query.
|
363
|
+
*/
|
364
|
+
find = query => {
|
365
|
+
// construct filter
|
366
|
+
const orQueries = (Array.isArray(query) ? query : [query]).map(query => typeof query === "function" ? query : Object.entries(query));
|
367
|
+
|
368
|
+
// filter balances
|
369
|
+
const filter = balance => orQueries.some(query => typeof query === "function" ? query(balance) : query.every(([key, value]) => balance[key] === value));
|
370
|
+
|
371
|
+
// return filter matches
|
372
|
+
return new Balances([...this].filter(filter));
|
373
|
+
};
|
374
|
+
|
375
|
+
/**
|
376
|
+
* Add some balances to this collection.
|
377
|
+
* Added balances take priority over existing balances.
|
378
|
+
* The aggregation of the two collections is returned.
|
379
|
+
* The original collection is not mutated.
|
380
|
+
*
|
381
|
+
* @param balances - Either a balance or collection of balances to add.
|
382
|
+
* @returns The new collection of balances.
|
383
|
+
*/
|
384
|
+
add = balances => {
|
385
|
+
// handle single balance
|
386
|
+
if (balances instanceof Balance) return this.add(new Balances(balances));
|
387
|
+
|
388
|
+
// merge balances
|
389
|
+
const mergedBalances = {
|
390
|
+
...this.#balances
|
391
|
+
};
|
392
|
+
[...balances].forEach(balance => mergedBalances[balance.id] = balance);
|
393
|
+
|
394
|
+
// return new balances
|
395
|
+
return new Balances(Object.values(mergedBalances));
|
396
|
+
};
|
397
|
+
|
398
|
+
/**
|
399
|
+
* Remove balances from this collection by id.
|
400
|
+
* A new collection without these balances is returned.
|
401
|
+
* The original collection is not mutated.
|
402
|
+
*
|
403
|
+
* @param ids - The id(s) of the balances to remove.
|
404
|
+
* @returns The new collection of balances.
|
405
|
+
*/
|
406
|
+
remove = ids => {
|
407
|
+
// handle single id
|
408
|
+
if (!Array.isArray(ids)) return this.remove([ids]);
|
409
|
+
|
410
|
+
// merge balances
|
411
|
+
const removedBalances = {
|
412
|
+
...this.#balances
|
413
|
+
};
|
414
|
+
ids.forEach(id => delete removedBalances[id]);
|
415
|
+
|
416
|
+
// return new balances
|
417
|
+
return new Balances(Object.values(removedBalances));
|
418
|
+
};
|
419
|
+
|
420
|
+
// TODO: Add some more useful aggregator methods
|
421
|
+
|
422
|
+
/**
|
423
|
+
* Get an array of balances in this collection, sorted by chain sortIndex.
|
424
|
+
*
|
425
|
+
* @returns A sorted array of the balances in this collection.
|
426
|
+
*/
|
427
|
+
get sorted() {
|
428
|
+
return [...this].sort((a, b) => ((a.chain || a.evmNetwork)?.sortIndex || Number.MAX_SAFE_INTEGER) - ((b.chain || b.evmNetwork)?.sortIndex || Number.MAX_SAFE_INTEGER));
|
429
|
+
}
|
430
|
+
|
431
|
+
/**
|
432
|
+
* Get the number of balances in this collection.
|
433
|
+
*
|
434
|
+
* @returns The number of balances in this collection.
|
435
|
+
*/
|
436
|
+
get count() {
|
437
|
+
return [...this].length;
|
438
|
+
}
|
439
|
+
|
440
|
+
/**
|
441
|
+
* Get the summed value of balances in this collection.
|
442
|
+
* TODO: Sum up token amounts AND fiat amounts
|
443
|
+
*
|
444
|
+
* @example
|
445
|
+
* // Get the sum of all transferable balances in usd.
|
446
|
+
* balances.sum.fiat('usd').transferable
|
447
|
+
*/
|
448
|
+
get sum() {
|
449
|
+
return new SumBalancesFormatter(this);
|
450
|
+
}
|
451
|
+
}, (_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));
|
452
|
+
|
453
|
+
/**
|
454
|
+
* An individual balance.
|
455
|
+
*/
|
456
|
+
let Balance = (_dec4 = Memoize(), _dec5 = Memoize(), _dec6 = Memoize(), _dec7 = Memoize(), _dec8 = Memoize(), _dec9 = Memoize(), _dec10 = Memoize(), (_class2 = class Balance {
|
457
|
+
//
|
458
|
+
// Properties
|
459
|
+
//
|
460
|
+
|
461
|
+
/** The underlying data for this balance */
|
462
|
+
#storage;
|
463
|
+
#db = null;
|
464
|
+
|
465
|
+
//
|
466
|
+
// Methods
|
467
|
+
//
|
468
|
+
|
469
|
+
constructor(storage, hydrate) {
|
470
|
+
this.#format = memoize(this.#format);
|
471
|
+
this.#storage = storage;
|
472
|
+
if (hydrate !== undefined) this.hydrate(hydrate);
|
473
|
+
}
|
474
|
+
toJSON = () => this.#storage;
|
475
|
+
isSource = source => this.#storage.source === source;
|
476
|
+
// // TODO: Fix this method, the types don't work with our plugin architecture.
|
477
|
+
// // Specifically, the `BalanceJson` type is compiled down to `IBalance` in the following way:
|
478
|
+
// //
|
479
|
+
// // toJSON: () => BalanceJson // works
|
480
|
+
// // isSource: (source: BalanceSource) => boolean // works
|
481
|
+
// // asSource: <P extends string>(source: P) => NarrowBalanceType<IBalance, P> | null // Doesn't work! IBalance should just be BalanceJson!
|
482
|
+
// //
|
483
|
+
// // `IBalance` won't match the type of `BalanceSource` after `PluginBalanceTypes` has been extended by balance plugins.
|
484
|
+
// // As a result, typescript will think that the returned #storage is not a BalanceJson.
|
485
|
+
// asSource = <P extends BalanceSource>(source: P): NarrowBalanceType<BalanceJson, P> | null => {
|
486
|
+
// if (this.#storage.source === source) return this.#storage as NarrowBalanceType<BalanceJson, P>
|
487
|
+
// return null
|
488
|
+
// }
|
489
|
+
|
490
|
+
hydrate = hydrate => {
|
491
|
+
if (hydrate !== undefined) this.#db = hydrate;
|
492
|
+
};
|
493
|
+
#format = balance => new BalanceFormatter(typeof balance === "bigint" ? balance.toString() : balance, this.decimals || undefined, this.#db?.tokenRates && this.#db.tokenRates[this.tokenId]);
|
494
|
+
|
495
|
+
//
|
496
|
+
// Accessors
|
497
|
+
//
|
498
|
+
|
499
|
+
get id() {
|
500
|
+
const {
|
501
|
+
source,
|
502
|
+
address,
|
503
|
+
chainId,
|
504
|
+
evmNetworkId,
|
505
|
+
tokenId
|
506
|
+
} = this.#storage;
|
507
|
+
const locationId = chainId !== undefined ? chainId : evmNetworkId;
|
508
|
+
return `${source}-${address}-${locationId}-${tokenId}`;
|
509
|
+
}
|
510
|
+
get source() {
|
511
|
+
return this.#storage.source;
|
512
|
+
}
|
513
|
+
get status() {
|
514
|
+
return this.#storage.status;
|
515
|
+
}
|
516
|
+
get address() {
|
517
|
+
return this.#storage.address;
|
518
|
+
}
|
519
|
+
get chainId() {
|
520
|
+
return this.#storage.chainId;
|
521
|
+
}
|
522
|
+
get chain() {
|
523
|
+
return this.#db?.chains && this.chainId && this.#db?.chains[this.chainId] || null;
|
524
|
+
}
|
525
|
+
get evmNetworkId() {
|
526
|
+
return this.#storage.evmNetworkId;
|
527
|
+
}
|
528
|
+
get evmNetwork() {
|
529
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
530
|
+
return this.#db?.evmNetworks && this.#db?.evmNetworks[this.evmNetworkId] || null;
|
531
|
+
}
|
532
|
+
get tokenId() {
|
533
|
+
return this.#storage.tokenId;
|
534
|
+
}
|
535
|
+
get token() {
|
536
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
537
|
+
return this.#db?.tokens && this.#db?.tokens[this.tokenId] || null;
|
538
|
+
}
|
539
|
+
get decimals() {
|
540
|
+
return this.token?.decimals || null;
|
541
|
+
}
|
542
|
+
get rates() {
|
543
|
+
return this.#db?.tokenRates && this.#db.tokenRates[this.tokenId] || null;
|
544
|
+
}
|
545
|
+
|
546
|
+
/**
|
547
|
+
* The total balance of this token.
|
548
|
+
* Includes the free and the reserved amount.
|
549
|
+
* The balance will be reaped if this goes below the existential deposit.
|
550
|
+
*/
|
551
|
+
get total() {
|
552
|
+
const extra = includeInTotalExtraAmount(this.#storage.extra);
|
553
|
+
return this.#format(this.free.planck + this.reserved.planck + extra);
|
554
|
+
}
|
555
|
+
/** The non-reserved balance of this token. Includes the frozen amount. Is included in the total. */
|
556
|
+
get free() {
|
557
|
+
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"));
|
558
|
+
}
|
559
|
+
/** The reserved balance of this token. Is included in the total. */
|
560
|
+
get reserved() {
|
561
|
+
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"));
|
562
|
+
}
|
563
|
+
/** The frozen balance of this token. Is included in the free amount. */
|
564
|
+
get locked() {
|
565
|
+
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"));
|
566
|
+
}
|
567
|
+
/** @depreacted - use balance.locked */
|
568
|
+
get frozen() {
|
569
|
+
return this.locked;
|
570
|
+
}
|
571
|
+
/** The transferable balance of this token. Is generally the free amount - the miscFrozen amount. */
|
572
|
+
get transferable() {
|
573
|
+
// if no locks exist, transferable is equal to the free amount
|
574
|
+
if (!this.#storage.locks) return this.free;
|
575
|
+
|
576
|
+
// find the largest lock (but ignore any locks which are marked as `includeInTransferable`)
|
577
|
+
const excludeAmount = excludeFromTransferableAmount(this.#storage.locks);
|
578
|
+
|
579
|
+
// subtract the lock from the free amount (but don't go below 0)
|
580
|
+
return this.#format(BigMath.max(this.free.planck - excludeAmount, BigInt("0")));
|
581
|
+
}
|
582
|
+
/** The feePayable balance of this token. Is generally the free amount - the feeFrozen amount. */
|
583
|
+
get feePayable() {
|
584
|
+
// if no locks exist, feePayable is equal to the free amount
|
585
|
+
if (!this.#storage.locks) return this.free;
|
586
|
+
|
587
|
+
// find the largest lock which can't be used to pay tx fees
|
588
|
+
const excludeAmount = excludeFromFeePayableLocks(this.#storage.locks).map(lock => BigInt(lock.amount)).reduce((max, lock) => BigMath.max(max, lock), BigInt("0"));
|
589
|
+
|
590
|
+
// subtract the lock from the free amount (but don't go below 0)
|
591
|
+
return this.#format(BigMath.max(this.free.planck - excludeAmount, BigInt("0")));
|
592
|
+
}
|
593
|
+
}, (_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));
|
594
|
+
let BalanceFormatter = (_dec11 = Memoize(), (_class3 = class BalanceFormatter {
|
595
|
+
#planck;
|
596
|
+
#decimals;
|
597
|
+
#fiatRatios;
|
598
|
+
constructor(planck, decimals, fiatRatios) {
|
599
|
+
this.#planck = typeof planck === "bigint" ? planck.toString() : planck ?? "0";
|
600
|
+
this.#decimals = decimals || 0;
|
601
|
+
this.#fiatRatios = fiatRatios || null;
|
602
|
+
this.fiat = memoize(this.fiat);
|
603
|
+
}
|
604
|
+
toJSON = () => this.#planck;
|
605
|
+
get planck() {
|
606
|
+
return BigInt(this.#planck);
|
607
|
+
}
|
608
|
+
get tokens() {
|
609
|
+
return planckToTokens(this.#planck, this.#decimals);
|
610
|
+
}
|
611
|
+
fiat(currency) {
|
612
|
+
if (!this.#fiatRatios) return null;
|
613
|
+
const ratio = this.#fiatRatios[currency];
|
614
|
+
if (!ratio) return null;
|
615
|
+
return parseFloat(this.tokens) * ratio;
|
616
|
+
}
|
617
|
+
}, (_applyDecoratedDescriptor(_class3.prototype, "tokens", [_dec11], Object.getOwnPropertyDescriptor(_class3.prototype, "tokens"), _class3.prototype)), _class3));
|
618
|
+
let FiatSumBalancesFormatter = (_dec12 = Memoize(), _dec13 = Memoize(), _dec14 = Memoize(), _dec15 = Memoize(), _dec16 = Memoize(), _dec17 = Memoize(), _dec18 = Memoize(), (_class4 = class FiatSumBalancesFormatter {
|
619
|
+
#balances;
|
620
|
+
#currency;
|
621
|
+
constructor(balances, currency) {
|
622
|
+
this.#balances = balances;
|
623
|
+
this.#currency = currency;
|
624
|
+
this.#sum = memoize(this.#sum);
|
625
|
+
}
|
626
|
+
#sum = balanceField => {
|
627
|
+
// a function to get a fiat amount from a balance
|
628
|
+
const fiat = balance => balance[balanceField].fiat(this.#currency) || 0;
|
629
|
+
|
630
|
+
// a function to add two amounts
|
631
|
+
const sum = (a, b) => a + b;
|
632
|
+
return [...this.#balances].filter(filterMirrorTokens).reduce((total, balance) => sum(
|
633
|
+
// add the total amount...
|
634
|
+
total,
|
635
|
+
// ...to the fiat amount of each balance
|
636
|
+
fiat(balance)),
|
637
|
+
// start with a total of 0
|
638
|
+
0);
|
639
|
+
};
|
640
|
+
|
641
|
+
/**
|
642
|
+
* The total balance of these tokens. Includes the free and the reserved amount.
|
643
|
+
*/
|
644
|
+
get total() {
|
645
|
+
return this.#sum("total");
|
646
|
+
}
|
647
|
+
/** The non-reserved balance of these tokens. Includes the frozen amount. Is included in the total. */
|
648
|
+
get free() {
|
649
|
+
return this.#sum("free");
|
650
|
+
}
|
651
|
+
/** The reserved balance of these tokens. Is included in the total. */
|
652
|
+
get reserved() {
|
653
|
+
return this.#sum("reserved");
|
654
|
+
}
|
655
|
+
/** The frozen balance of these tokens. Is included in the free amount. */
|
656
|
+
get locked() {
|
657
|
+
return this.#sum("locked");
|
658
|
+
}
|
659
|
+
/** @deprecated - use balances.locked */
|
660
|
+
get frozen() {
|
661
|
+
return this.locked;
|
662
|
+
}
|
663
|
+
/** The transferable balance of these tokens. Is generally the free amount - the miscFrozen amount. */
|
664
|
+
get transferable() {
|
665
|
+
return this.#sum("transferable");
|
666
|
+
}
|
667
|
+
/** The feePayable balance of these tokens. Is generally the free amount - the feeFrozen amount. */
|
668
|
+
get feePayable() {
|
669
|
+
return this.#sum("feePayable");
|
670
|
+
}
|
671
|
+
}, (_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));
|
672
|
+
class SumBalancesFormatter {
|
673
|
+
#balances;
|
674
|
+
constructor(balances) {
|
675
|
+
this.#balances = balances;
|
676
|
+
this.fiat = memoize(this.fiat);
|
677
|
+
}
|
678
|
+
fiat(currency) {
|
679
|
+
return new FiatSumBalancesFormatter(this.#balances, currency);
|
680
|
+
}
|
681
|
+
}
|
682
|
+
|
683
|
+
export { Balance, BalanceFormatter, Balances, DefaultBalanceModule, FiatSumBalancesFormatter, StorageHelper, SumBalancesFormatter, TalismanBalancesDatabase, balances, db, excludeFromFeePayableLocks, excludeFromTransferableAmount, filterMirrorTokens, includeInTotalExtraAmount };
|