@talismn/balances 0.0.0-pr675-20230413170259 → 0.0.0-pr677-20230413171850
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 +8 -5
- package/dist/declarations/src/helpers.d.ts +20 -1
- package/dist/declarations/src/types/balances.d.ts +12 -0
- package/dist/declarations/src/types/balancetypes.d.ts +6 -0
- package/dist/talismn-balances.cjs.dev.js +115 -8
- package/dist/talismn-balances.cjs.prod.js +115 -8
- package/dist/talismn-balances.esm.js +114 -9
- package/package.json +11 -9
package/CHANGELOG.md
CHANGED
@@ -1,16 +1,19 @@
|
|
1
1
|
# @talismn/balances
|
2
2
|
|
3
|
-
## 0.0.0-
|
3
|
+
## 0.0.0-pr677-20230413171850
|
4
4
|
|
5
5
|
### Patch Changes
|
6
6
|
|
7
7
|
- fb8ee962: feat: proxy dapp websocket requests to talisman wallet backend when available
|
8
|
+
- 306e7160: feat: crowdloan and nom pool balances
|
8
9
|
- Updated dependencies [fb8ee962]
|
9
10
|
- Updated dependencies [c898da98]
|
10
|
-
|
11
|
-
- @talismn/chain-connector
|
12
|
-
- @talismn/
|
13
|
-
- @talismn/
|
11
|
+
- Updated dependencies [306e7160]
|
12
|
+
- @talismn/chain-connector@0.0.0-pr677-20230413171850
|
13
|
+
- @talismn/chain-connector-evm@0.0.0-pr677-20230413171850
|
14
|
+
- @talismn/util@0.0.0-pr677-20230413171850
|
15
|
+
- @talismn/chaindata-provider@0.0.0-pr677-20230413171850
|
16
|
+
- @talismn/token-rates@0.0.0-pr677-20230413171850
|
14
17
|
|
15
18
|
## 0.4.0
|
16
19
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import type { Registry } from "@polkadot/types-codec/types";
|
2
|
+
import { ChainConnector } from "@talismn/chain-connector";
|
2
3
|
import { ChainId } from "@talismn/chaindata-provider";
|
3
4
|
import { BalanceModule, DefaultChainMeta, DefaultModuleConfig, DefaultTransferParams, ExtendableChainMeta, ExtendableModuleConfig, ExtendableTokenType, ExtendableTransferParams } from "./BalanceModule";
|
4
5
|
import { AddressesByToken, Balance, BalanceJson, Balances, SubscriptionCallback, UnsubscribeFn } from "./types";
|
@@ -8,8 +9,9 @@ import { AddressesByToken, Balance, BalanceJson, Balances, SubscriptionCallback,
|
|
8
9
|
*/
|
9
10
|
export declare function balances<TModuleType extends string, TTokenType extends ExtendableTokenType, TChainMeta extends ExtendableChainMeta = DefaultChainMeta, TModuleConfig extends ExtendableModuleConfig = DefaultModuleConfig, TTransferParams extends ExtendableTransferParams = DefaultTransferParams>(balanceModule: BalanceModule<TModuleType, TTokenType, TChainMeta, TModuleConfig, TTransferParams>, addressesByToken: AddressesByToken<TTokenType>): Promise<Balances>;
|
10
11
|
export declare function balances<TModuleType extends string, TTokenType extends ExtendableTokenType, TChainMeta extends ExtendableChainMeta = DefaultChainMeta, TModuleConfig extends ExtendableModuleConfig = DefaultModuleConfig, TTransferParams extends ExtendableTransferParams = DefaultTransferParams>(balanceModule: BalanceModule<TModuleType, TTokenType, TChainMeta, TModuleConfig, TTransferParams>, addressesByToken: AddressesByToken<TTokenType>, callback: SubscriptionCallback<Balances>): Promise<UnsubscribeFn>;
|
12
|
+
export type GetOrCreateTypeRegistry = (chainId: ChainId, metadataRpc?: `0x${string}`) => Registry;
|
11
13
|
export declare const createTypeRegistryCache: () => {
|
12
|
-
getOrCreateTypeRegistry:
|
14
|
+
getOrCreateTypeRegistry: GetOrCreateTypeRegistry;
|
13
15
|
};
|
14
16
|
export declare const filterMirrorTokens: (balance: Balance, i: number, balances: Balance[]) => boolean;
|
15
17
|
export declare const getValidSubscriptionIds: () => Set<string>;
|
@@ -33,3 +35,20 @@ export declare class StorageHelper {
|
|
33
35
|
tag(tags: any): this;
|
34
36
|
decode(input?: string | null): import("@polkadot/types-codec/types").Codec | undefined;
|
35
37
|
}
|
38
|
+
/**
|
39
|
+
* Pass some these into an `RpcStateQueryHelper` in order to easily batch multiple state queries into the one rpc call.
|
40
|
+
*/
|
41
|
+
export type RpcStateQuery<T> = {
|
42
|
+
chainId: string;
|
43
|
+
stateKey: string;
|
44
|
+
decodeResult: (change: string | null) => T;
|
45
|
+
};
|
46
|
+
/**
|
47
|
+
* Used by a variety of balance modules to help batch multiple state queries into the one rpc call.
|
48
|
+
*/
|
49
|
+
export declare class RpcStateQueryHelper<T> {
|
50
|
+
#private;
|
51
|
+
constructor(chainConnector: ChainConnector, queries: Array<RpcStateQuery<T>>);
|
52
|
+
subscribe(callback: SubscriptionCallback<T[]>, timeout?: number | false, subscribeMethod?: string, responseMethod?: string, unsubscribeMethod?: string): Promise<UnsubscribeFn>;
|
53
|
+
fetch(method?: string): Promise<T[]>;
|
54
|
+
}
|
@@ -134,8 +134,20 @@ export declare class Balance {
|
|
134
134
|
get free(): BalanceFormatter;
|
135
135
|
/** The reserved balance of this token. Is included in the total. */
|
136
136
|
get reserved(): BalanceFormatter;
|
137
|
+
get reserves(): {
|
138
|
+
amount: BalanceFormatter;
|
139
|
+
label: string;
|
140
|
+
meta?: unknown;
|
141
|
+
}[];
|
137
142
|
/** The frozen balance of this token. Is included in the free amount. */
|
138
143
|
get locked(): BalanceFormatter;
|
144
|
+
get locks(): {
|
145
|
+
amount: BalanceFormatter;
|
146
|
+
label: string;
|
147
|
+
meta?: unknown;
|
148
|
+
includeInTransferable?: boolean | undefined;
|
149
|
+
excludeFromFeePayable?: boolean | undefined;
|
150
|
+
}[];
|
139
151
|
/** @depreacted - use balance.locked */
|
140
152
|
get frozen(): BalanceFormatter;
|
141
153
|
/** The transferable balance of this token. Is generally the free amount - the miscFrozen amount. */
|
@@ -30,6 +30,11 @@ export type BalanceStatus = BalanceStatusLive | "live" | "cache" | "stale";
|
|
30
30
|
export type IBalance = {
|
31
31
|
/** The module that this balance was retrieved by */
|
32
32
|
source: string;
|
33
|
+
/**
|
34
|
+
* For modules which fetch balances via module sources, this is the sub-source
|
35
|
+
* e.g. `staking` or `crowdloans`
|
36
|
+
**/
|
37
|
+
subSource?: string;
|
33
38
|
/** Has this balance never been fetched, or is it from a cache, or is it up to date? */
|
34
39
|
status: BalanceStatus;
|
35
40
|
/** The address of the account which owns this balance */
|
@@ -59,6 +64,7 @@ export type Amount = string;
|
|
59
64
|
export type AmountWithLabel<TLabel extends string> = {
|
60
65
|
label: TLabel;
|
61
66
|
amount: Amount;
|
67
|
+
meta?: unknown;
|
62
68
|
};
|
63
69
|
/** A labelled locked amount of a balance */
|
64
70
|
export type LockedAmount<TLabel extends string> = AmountWithLabel<TLabel> & {
|
@@ -4,11 +4,13 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
5
5
|
var dexie = require('dexie');
|
6
6
|
var types = require('@polkadot/types');
|
7
|
-
var anylogger = require('anylogger');
|
8
7
|
var util = require('@talismn/util');
|
8
|
+
var groupBy = require('lodash/groupBy');
|
9
|
+
var anylogger = require('anylogger');
|
9
10
|
|
10
11
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
11
12
|
|
13
|
+
var groupBy__default = /*#__PURE__*/_interopDefault(groupBy);
|
12
14
|
var anylogger__default = /*#__PURE__*/_interopDefault(anylogger);
|
13
15
|
|
14
16
|
// TODO: Document default balances module purpose/usage
|
@@ -67,7 +69,7 @@ const db = new TalismanBalancesDatabase();
|
|
67
69
|
|
68
70
|
var packageJson = {
|
69
71
|
name: "@talismn/balances",
|
70
|
-
version: "0.0.0-
|
72
|
+
version: "0.0.0-pr677-20230413171850",
|
71
73
|
author: "Talisman",
|
72
74
|
homepage: "https://talisman.xyz",
|
73
75
|
license: "UNLICENSED",
|
@@ -100,20 +102,22 @@ var packageJson = {
|
|
100
102
|
"@talismn/token-rates": "workspace:^",
|
101
103
|
"@talismn/util": "workspace:^",
|
102
104
|
anylogger: "^1.0.11",
|
103
|
-
dexie: "^3.2.3"
|
105
|
+
dexie: "^3.2.3",
|
106
|
+
lodash: "4.17.21"
|
104
107
|
},
|
105
108
|
devDependencies: {
|
106
|
-
"@polkadot/types": "^
|
109
|
+
"@polkadot/types": "^10.1.4",
|
107
110
|
"@talismn/eslint-config": "workspace:^",
|
108
111
|
"@talismn/tsconfig": "workspace:^",
|
109
112
|
"@types/jest": "^27.5.1",
|
113
|
+
"@types/lodash": "^4.14.180",
|
110
114
|
eslint: "^8.4.0",
|
111
115
|
jest: "^28.1.0",
|
112
116
|
"ts-jest": "^28.0.2",
|
113
117
|
typescript: "^4.6.4"
|
114
118
|
},
|
115
119
|
peerDependencies: {
|
116
|
-
"@polkadot/types": "
|
120
|
+
"@polkadot/types": "10.x"
|
117
121
|
},
|
118
122
|
preconstruct: {
|
119
123
|
entrypoints: [
|
@@ -146,8 +150,14 @@ const createTypeRegistryCache = () => {
|
|
146
150
|
if (cached) return cached;
|
147
151
|
const typeRegistry = new types.TypeRegistry();
|
148
152
|
if (typeof metadataRpc === "string") {
|
149
|
-
|
150
|
-
|
153
|
+
try {
|
154
|
+
const metadata = new types.Metadata(typeRegistry, metadataRpc);
|
155
|
+
metadata.registry.setMetadata(metadata);
|
156
|
+
} catch (cause) {
|
157
|
+
log.warn(new Error(`Failed to set metadata for chain ${chainId}`, {
|
158
|
+
cause
|
159
|
+
}));
|
160
|
+
}
|
151
161
|
}
|
152
162
|
typeRegistryCache.set(chainId, typeRegistry);
|
153
163
|
return typeRegistry;
|
@@ -286,6 +296,75 @@ class StorageHelper {
|
|
286
296
|
}
|
287
297
|
}
|
288
298
|
|
299
|
+
/**
|
300
|
+
* Pass some these into an `RpcStateQueryHelper` in order to easily batch multiple state queries into the one rpc call.
|
301
|
+
*/
|
302
|
+
|
303
|
+
/**
|
304
|
+
* Used by a variety of balance modules to help batch multiple state queries into the one rpc call.
|
305
|
+
*/
|
306
|
+
class RpcStateQueryHelper {
|
307
|
+
#chainConnector;
|
308
|
+
#queries;
|
309
|
+
constructor(chainConnector, queries) {
|
310
|
+
this.#chainConnector = chainConnector;
|
311
|
+
this.#queries = queries;
|
312
|
+
}
|
313
|
+
async subscribe(callback, timeout = false, subscribeMethod = "state_subscribeStorage", responseMethod = "state_storage", unsubscribeMethod = "state_unsubscribeStorage") {
|
314
|
+
const queriesByChain = groupBy__default["default"](this.#queries, "chainId");
|
315
|
+
const subscriptions = Object.entries(queriesByChain).map(([chainId, queries]) => {
|
316
|
+
const params = [queries.map(({
|
317
|
+
stateKey
|
318
|
+
}) => stateKey)];
|
319
|
+
const unsubscribe = this.#chainConnector.subscribe(chainId, subscribeMethod, responseMethod, params, (error, result) => {
|
320
|
+
error ? callback(error) : callback(null, this.#distributeChangesToQueryDecoders.call(this, chainId, result));
|
321
|
+
}, timeout);
|
322
|
+
return () => unsubscribe(unsubscribeMethod);
|
323
|
+
}).map(subscription => subscription.catch(error => {
|
324
|
+
log.warn(`Failed to create subscription: ${error.message}`);
|
325
|
+
return () => {};
|
326
|
+
}));
|
327
|
+
return () => subscriptions.forEach(subscription => subscription.then(unsubscribe => unsubscribe()));
|
328
|
+
}
|
329
|
+
async fetch(method = "state_queryStorageAt") {
|
330
|
+
const queriesByChain = groupBy__default["default"](this.#queries, "chainId");
|
331
|
+
const resultsByChain = await Promise.all(Object.entries(queriesByChain).map(async ([chainId, queries]) => {
|
332
|
+
const params = [queries.map(({
|
333
|
+
stateKey
|
334
|
+
}) => stateKey)];
|
335
|
+
const result = (await this.#chainConnector.send(chainId, method, params))[0];
|
336
|
+
return this.#distributeChangesToQueryDecoders.call(this, chainId, result);
|
337
|
+
}));
|
338
|
+
return resultsByChain.flatMap(result => result);
|
339
|
+
}
|
340
|
+
#distributeChangesToQueryDecoders(chainId, result) {
|
341
|
+
if (typeof result !== "object" || result === null) return [];
|
342
|
+
if (!util.hasOwnProperty(result, "changes") || typeof result.changes !== "object") return [];
|
343
|
+
if (!Array.isArray(result.changes)) return [];
|
344
|
+
return result.changes.flatMap(([reference, change]) => {
|
345
|
+
if (typeof reference !== "string") {
|
346
|
+
log.warn(`Received non-string reference in RPC result: ${reference}`);
|
347
|
+
return [];
|
348
|
+
}
|
349
|
+
if (typeof change !== "string" && change !== null) {
|
350
|
+
log.warn(`Received non-string and non-null change in RPC result: ${reference} | ${change}`);
|
351
|
+
return [];
|
352
|
+
}
|
353
|
+
const query = this.#queries.find(({
|
354
|
+
chainId: cId,
|
355
|
+
stateKey
|
356
|
+
}) => cId === chainId && stateKey === reference);
|
357
|
+
if (!query) {
|
358
|
+
log.warn(`Failed to find query:\n${reference} in\n${this.#queries.map(({
|
359
|
+
stateKey
|
360
|
+
}) => stateKey)}`);
|
361
|
+
return [];
|
362
|
+
}
|
363
|
+
return query.decodeResult(change);
|
364
|
+
});
|
365
|
+
}
|
366
|
+
}
|
367
|
+
|
289
368
|
const BalanceStatusLive = subscriptionId => `live-${subscriptionId}`;
|
290
369
|
function excludeFromTransferableAmount(locks) {
|
291
370
|
if (typeof locks === "string") return BigInt(locks);
|
@@ -536,13 +615,14 @@ class Balance {
|
|
536
615
|
get id() {
|
537
616
|
const {
|
538
617
|
source,
|
618
|
+
subSource,
|
539
619
|
address,
|
540
620
|
chainId,
|
541
621
|
evmNetworkId,
|
542
622
|
tokenId
|
543
623
|
} = this.#storage;
|
544
624
|
const locationId = chainId !== undefined ? chainId : evmNetworkId;
|
545
|
-
return
|
625
|
+
return [source, address, locationId, tokenId, subSource].filter(Boolean).join("-");
|
546
626
|
}
|
547
627
|
get source() {
|
548
628
|
return this.#storage.source;
|
@@ -597,10 +677,36 @@ class Balance {
|
|
597
677
|
get reserved() {
|
598
678
|
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"));
|
599
679
|
}
|
680
|
+
get reserves() {
|
681
|
+
return (Array.isArray(this.#storage.reserves) ? this.#storage.reserves : [this.#storage.reserves]).flatMap(reserve => {
|
682
|
+
if (reserve === undefined) return [];
|
683
|
+
if (typeof reserve === "string") return {
|
684
|
+
label: "other",
|
685
|
+
amount: this.#format(reserve)
|
686
|
+
};
|
687
|
+
return {
|
688
|
+
...reserve,
|
689
|
+
amount: this.#format(reserve.amount)
|
690
|
+
};
|
691
|
+
});
|
692
|
+
}
|
600
693
|
/** The frozen balance of this token. Is included in the free amount. */
|
601
694
|
get locked() {
|
602
695
|
return this.#format(typeof this.#storage.locks === "string" ? BigInt(this.#storage.locks) : Array.isArray(this.#storage.locks) ? this.#storage.locks.map(lock => BigInt(lock.amount)).reduce((a, b) => util.BigMath.max(a, b), BigInt("0")) : BigInt(this.#storage.locks?.amount || "0"));
|
603
696
|
}
|
697
|
+
get locks() {
|
698
|
+
return (Array.isArray(this.#storage.locks) ? this.#storage.locks : [this.#storage.locks]).flatMap(lock => {
|
699
|
+
if (lock === undefined) return [];
|
700
|
+
if (typeof lock === "string") return {
|
701
|
+
label: "other",
|
702
|
+
amount: this.#format(lock)
|
703
|
+
};
|
704
|
+
return {
|
705
|
+
...lock,
|
706
|
+
amount: this.#format(lock.amount)
|
707
|
+
};
|
708
|
+
});
|
709
|
+
}
|
604
710
|
/** @depreacted - use balance.locked */
|
605
711
|
get frozen() {
|
606
712
|
return this.locked;
|
@@ -720,6 +826,7 @@ exports.BalanceStatusLive = BalanceStatusLive;
|
|
720
826
|
exports.Balances = Balances;
|
721
827
|
exports.DefaultBalanceModule = DefaultBalanceModule;
|
722
828
|
exports.FiatSumBalancesFormatter = FiatSumBalancesFormatter;
|
829
|
+
exports.RpcStateQueryHelper = RpcStateQueryHelper;
|
723
830
|
exports.StorageHelper = StorageHelper;
|
724
831
|
exports.SumBalancesFormatter = SumBalancesFormatter;
|
725
832
|
exports.TalismanBalancesDatabase = TalismanBalancesDatabase;
|
@@ -4,11 +4,13 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
5
5
|
var dexie = require('dexie');
|
6
6
|
var types = require('@polkadot/types');
|
7
|
-
var anylogger = require('anylogger');
|
8
7
|
var util = require('@talismn/util');
|
8
|
+
var groupBy = require('lodash/groupBy');
|
9
|
+
var anylogger = require('anylogger');
|
9
10
|
|
10
11
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
11
12
|
|
13
|
+
var groupBy__default = /*#__PURE__*/_interopDefault(groupBy);
|
12
14
|
var anylogger__default = /*#__PURE__*/_interopDefault(anylogger);
|
13
15
|
|
14
16
|
// TODO: Document default balances module purpose/usage
|
@@ -67,7 +69,7 @@ const db = new TalismanBalancesDatabase();
|
|
67
69
|
|
68
70
|
var packageJson = {
|
69
71
|
name: "@talismn/balances",
|
70
|
-
version: "0.0.0-
|
72
|
+
version: "0.0.0-pr677-20230413171850",
|
71
73
|
author: "Talisman",
|
72
74
|
homepage: "https://talisman.xyz",
|
73
75
|
license: "UNLICENSED",
|
@@ -100,20 +102,22 @@ var packageJson = {
|
|
100
102
|
"@talismn/token-rates": "workspace:^",
|
101
103
|
"@talismn/util": "workspace:^",
|
102
104
|
anylogger: "^1.0.11",
|
103
|
-
dexie: "^3.2.3"
|
105
|
+
dexie: "^3.2.3",
|
106
|
+
lodash: "4.17.21"
|
104
107
|
},
|
105
108
|
devDependencies: {
|
106
|
-
"@polkadot/types": "^
|
109
|
+
"@polkadot/types": "^10.1.4",
|
107
110
|
"@talismn/eslint-config": "workspace:^",
|
108
111
|
"@talismn/tsconfig": "workspace:^",
|
109
112
|
"@types/jest": "^27.5.1",
|
113
|
+
"@types/lodash": "^4.14.180",
|
110
114
|
eslint: "^8.4.0",
|
111
115
|
jest: "^28.1.0",
|
112
116
|
"ts-jest": "^28.0.2",
|
113
117
|
typescript: "^4.6.4"
|
114
118
|
},
|
115
119
|
peerDependencies: {
|
116
|
-
"@polkadot/types": "
|
120
|
+
"@polkadot/types": "10.x"
|
117
121
|
},
|
118
122
|
preconstruct: {
|
119
123
|
entrypoints: [
|
@@ -146,8 +150,14 @@ const createTypeRegistryCache = () => {
|
|
146
150
|
if (cached) return cached;
|
147
151
|
const typeRegistry = new types.TypeRegistry();
|
148
152
|
if (typeof metadataRpc === "string") {
|
149
|
-
|
150
|
-
|
153
|
+
try {
|
154
|
+
const metadata = new types.Metadata(typeRegistry, metadataRpc);
|
155
|
+
metadata.registry.setMetadata(metadata);
|
156
|
+
} catch (cause) {
|
157
|
+
log.warn(new Error(`Failed to set metadata for chain ${chainId}`, {
|
158
|
+
cause
|
159
|
+
}));
|
160
|
+
}
|
151
161
|
}
|
152
162
|
typeRegistryCache.set(chainId, typeRegistry);
|
153
163
|
return typeRegistry;
|
@@ -286,6 +296,75 @@ class StorageHelper {
|
|
286
296
|
}
|
287
297
|
}
|
288
298
|
|
299
|
+
/**
|
300
|
+
* Pass some these into an `RpcStateQueryHelper` in order to easily batch multiple state queries into the one rpc call.
|
301
|
+
*/
|
302
|
+
|
303
|
+
/**
|
304
|
+
* Used by a variety of balance modules to help batch multiple state queries into the one rpc call.
|
305
|
+
*/
|
306
|
+
class RpcStateQueryHelper {
|
307
|
+
#chainConnector;
|
308
|
+
#queries;
|
309
|
+
constructor(chainConnector, queries) {
|
310
|
+
this.#chainConnector = chainConnector;
|
311
|
+
this.#queries = queries;
|
312
|
+
}
|
313
|
+
async subscribe(callback, timeout = false, subscribeMethod = "state_subscribeStorage", responseMethod = "state_storage", unsubscribeMethod = "state_unsubscribeStorage") {
|
314
|
+
const queriesByChain = groupBy__default["default"](this.#queries, "chainId");
|
315
|
+
const subscriptions = Object.entries(queriesByChain).map(([chainId, queries]) => {
|
316
|
+
const params = [queries.map(({
|
317
|
+
stateKey
|
318
|
+
}) => stateKey)];
|
319
|
+
const unsubscribe = this.#chainConnector.subscribe(chainId, subscribeMethod, responseMethod, params, (error, result) => {
|
320
|
+
error ? callback(error) : callback(null, this.#distributeChangesToQueryDecoders.call(this, chainId, result));
|
321
|
+
}, timeout);
|
322
|
+
return () => unsubscribe(unsubscribeMethod);
|
323
|
+
}).map(subscription => subscription.catch(error => {
|
324
|
+
log.warn(`Failed to create subscription: ${error.message}`);
|
325
|
+
return () => {};
|
326
|
+
}));
|
327
|
+
return () => subscriptions.forEach(subscription => subscription.then(unsubscribe => unsubscribe()));
|
328
|
+
}
|
329
|
+
async fetch(method = "state_queryStorageAt") {
|
330
|
+
const queriesByChain = groupBy__default["default"](this.#queries, "chainId");
|
331
|
+
const resultsByChain = await Promise.all(Object.entries(queriesByChain).map(async ([chainId, queries]) => {
|
332
|
+
const params = [queries.map(({
|
333
|
+
stateKey
|
334
|
+
}) => stateKey)];
|
335
|
+
const result = (await this.#chainConnector.send(chainId, method, params))[0];
|
336
|
+
return this.#distributeChangesToQueryDecoders.call(this, chainId, result);
|
337
|
+
}));
|
338
|
+
return resultsByChain.flatMap(result => result);
|
339
|
+
}
|
340
|
+
#distributeChangesToQueryDecoders(chainId, result) {
|
341
|
+
if (typeof result !== "object" || result === null) return [];
|
342
|
+
if (!util.hasOwnProperty(result, "changes") || typeof result.changes !== "object") return [];
|
343
|
+
if (!Array.isArray(result.changes)) return [];
|
344
|
+
return result.changes.flatMap(([reference, change]) => {
|
345
|
+
if (typeof reference !== "string") {
|
346
|
+
log.warn(`Received non-string reference in RPC result: ${reference}`);
|
347
|
+
return [];
|
348
|
+
}
|
349
|
+
if (typeof change !== "string" && change !== null) {
|
350
|
+
log.warn(`Received non-string and non-null change in RPC result: ${reference} | ${change}`);
|
351
|
+
return [];
|
352
|
+
}
|
353
|
+
const query = this.#queries.find(({
|
354
|
+
chainId: cId,
|
355
|
+
stateKey
|
356
|
+
}) => cId === chainId && stateKey === reference);
|
357
|
+
if (!query) {
|
358
|
+
log.warn(`Failed to find query:\n${reference} in\n${this.#queries.map(({
|
359
|
+
stateKey
|
360
|
+
}) => stateKey)}`);
|
361
|
+
return [];
|
362
|
+
}
|
363
|
+
return query.decodeResult(change);
|
364
|
+
});
|
365
|
+
}
|
366
|
+
}
|
367
|
+
|
289
368
|
const BalanceStatusLive = subscriptionId => `live-${subscriptionId}`;
|
290
369
|
function excludeFromTransferableAmount(locks) {
|
291
370
|
if (typeof locks === "string") return BigInt(locks);
|
@@ -536,13 +615,14 @@ class Balance {
|
|
536
615
|
get id() {
|
537
616
|
const {
|
538
617
|
source,
|
618
|
+
subSource,
|
539
619
|
address,
|
540
620
|
chainId,
|
541
621
|
evmNetworkId,
|
542
622
|
tokenId
|
543
623
|
} = this.#storage;
|
544
624
|
const locationId = chainId !== undefined ? chainId : evmNetworkId;
|
545
|
-
return
|
625
|
+
return [source, address, locationId, tokenId, subSource].filter(Boolean).join("-");
|
546
626
|
}
|
547
627
|
get source() {
|
548
628
|
return this.#storage.source;
|
@@ -597,10 +677,36 @@ class Balance {
|
|
597
677
|
get reserved() {
|
598
678
|
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"));
|
599
679
|
}
|
680
|
+
get reserves() {
|
681
|
+
return (Array.isArray(this.#storage.reserves) ? this.#storage.reserves : [this.#storage.reserves]).flatMap(reserve => {
|
682
|
+
if (reserve === undefined) return [];
|
683
|
+
if (typeof reserve === "string") return {
|
684
|
+
label: "other",
|
685
|
+
amount: this.#format(reserve)
|
686
|
+
};
|
687
|
+
return {
|
688
|
+
...reserve,
|
689
|
+
amount: this.#format(reserve.amount)
|
690
|
+
};
|
691
|
+
});
|
692
|
+
}
|
600
693
|
/** The frozen balance of this token. Is included in the free amount. */
|
601
694
|
get locked() {
|
602
695
|
return this.#format(typeof this.#storage.locks === "string" ? BigInt(this.#storage.locks) : Array.isArray(this.#storage.locks) ? this.#storage.locks.map(lock => BigInt(lock.amount)).reduce((a, b) => util.BigMath.max(a, b), BigInt("0")) : BigInt(this.#storage.locks?.amount || "0"));
|
603
696
|
}
|
697
|
+
get locks() {
|
698
|
+
return (Array.isArray(this.#storage.locks) ? this.#storage.locks : [this.#storage.locks]).flatMap(lock => {
|
699
|
+
if (lock === undefined) return [];
|
700
|
+
if (typeof lock === "string") return {
|
701
|
+
label: "other",
|
702
|
+
amount: this.#format(lock)
|
703
|
+
};
|
704
|
+
return {
|
705
|
+
...lock,
|
706
|
+
amount: this.#format(lock.amount)
|
707
|
+
};
|
708
|
+
});
|
709
|
+
}
|
604
710
|
/** @depreacted - use balance.locked */
|
605
711
|
get frozen() {
|
606
712
|
return this.locked;
|
@@ -720,6 +826,7 @@ exports.BalanceStatusLive = BalanceStatusLive;
|
|
720
826
|
exports.Balances = Balances;
|
721
827
|
exports.DefaultBalanceModule = DefaultBalanceModule;
|
722
828
|
exports.FiatSumBalancesFormatter = FiatSumBalancesFormatter;
|
829
|
+
exports.RpcStateQueryHelper = RpcStateQueryHelper;
|
723
830
|
exports.StorageHelper = StorageHelper;
|
724
831
|
exports.SumBalancesFormatter = SumBalancesFormatter;
|
725
832
|
exports.TalismanBalancesDatabase = TalismanBalancesDatabase;
|
@@ -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.0.0-
|
63
|
+
version: "0.0.0-pr677-20230413171850",
|
63
64
|
author: "Talisman",
|
64
65
|
homepage: "https://talisman.xyz",
|
65
66
|
license: "UNLICENSED",
|
@@ -92,20 +93,22 @@ var packageJson = {
|
|
92
93
|
"@talismn/token-rates": "workspace:^",
|
93
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": "^
|
100
|
+
"@polkadot/types": "^10.1.4",
|
99
101
|
"@talismn/eslint-config": "workspace:^",
|
100
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: [
|
@@ -138,8 +141,14 @@ const createTypeRegistryCache = () => {
|
|
138
141
|
if (cached) return cached;
|
139
142
|
const typeRegistry = new TypeRegistry();
|
140
143
|
if (typeof metadataRpc === "string") {
|
141
|
-
|
142
|
-
|
144
|
+
try {
|
145
|
+
const metadata = new Metadata(typeRegistry, metadataRpc);
|
146
|
+
metadata.registry.setMetadata(metadata);
|
147
|
+
} catch (cause) {
|
148
|
+
log.warn(new Error(`Failed to set metadata for chain ${chainId}`, {
|
149
|
+
cause
|
150
|
+
}));
|
151
|
+
}
|
143
152
|
}
|
144
153
|
typeRegistryCache.set(chainId, typeRegistry);
|
145
154
|
return typeRegistry;
|
@@ -278,6 +287,75 @@ class StorageHelper {
|
|
278
287
|
}
|
279
288
|
}
|
280
289
|
|
290
|
+
/**
|
291
|
+
* Pass some these into an `RpcStateQueryHelper` in order to easily batch multiple state queries into the one rpc call.
|
292
|
+
*/
|
293
|
+
|
294
|
+
/**
|
295
|
+
* Used by a variety of balance modules to help batch multiple state queries into the one rpc call.
|
296
|
+
*/
|
297
|
+
class RpcStateQueryHelper {
|
298
|
+
#chainConnector;
|
299
|
+
#queries;
|
300
|
+
constructor(chainConnector, queries) {
|
301
|
+
this.#chainConnector = chainConnector;
|
302
|
+
this.#queries = queries;
|
303
|
+
}
|
304
|
+
async subscribe(callback, timeout = false, subscribeMethod = "state_subscribeStorage", responseMethod = "state_storage", unsubscribeMethod = "state_unsubscribeStorage") {
|
305
|
+
const queriesByChain = groupBy(this.#queries, "chainId");
|
306
|
+
const subscriptions = Object.entries(queriesByChain).map(([chainId, queries]) => {
|
307
|
+
const params = [queries.map(({
|
308
|
+
stateKey
|
309
|
+
}) => stateKey)];
|
310
|
+
const unsubscribe = this.#chainConnector.subscribe(chainId, subscribeMethod, responseMethod, params, (error, result) => {
|
311
|
+
error ? callback(error) : callback(null, this.#distributeChangesToQueryDecoders.call(this, chainId, result));
|
312
|
+
}, timeout);
|
313
|
+
return () => unsubscribe(unsubscribeMethod);
|
314
|
+
}).map(subscription => subscription.catch(error => {
|
315
|
+
log.warn(`Failed to create subscription: ${error.message}`);
|
316
|
+
return () => {};
|
317
|
+
}));
|
318
|
+
return () => subscriptions.forEach(subscription => subscription.then(unsubscribe => unsubscribe()));
|
319
|
+
}
|
320
|
+
async fetch(method = "state_queryStorageAt") {
|
321
|
+
const queriesByChain = groupBy(this.#queries, "chainId");
|
322
|
+
const resultsByChain = await Promise.all(Object.entries(queriesByChain).map(async ([chainId, queries]) => {
|
323
|
+
const params = [queries.map(({
|
324
|
+
stateKey
|
325
|
+
}) => stateKey)];
|
326
|
+
const result = (await this.#chainConnector.send(chainId, method, params))[0];
|
327
|
+
return this.#distributeChangesToQueryDecoders.call(this, chainId, result);
|
328
|
+
}));
|
329
|
+
return resultsByChain.flatMap(result => result);
|
330
|
+
}
|
331
|
+
#distributeChangesToQueryDecoders(chainId, result) {
|
332
|
+
if (typeof result !== "object" || result === null) return [];
|
333
|
+
if (!hasOwnProperty(result, "changes") || typeof result.changes !== "object") return [];
|
334
|
+
if (!Array.isArray(result.changes)) return [];
|
335
|
+
return result.changes.flatMap(([reference, change]) => {
|
336
|
+
if (typeof reference !== "string") {
|
337
|
+
log.warn(`Received non-string reference in RPC result: ${reference}`);
|
338
|
+
return [];
|
339
|
+
}
|
340
|
+
if (typeof change !== "string" && change !== null) {
|
341
|
+
log.warn(`Received non-string and non-null change in RPC result: ${reference} | ${change}`);
|
342
|
+
return [];
|
343
|
+
}
|
344
|
+
const query = this.#queries.find(({
|
345
|
+
chainId: cId,
|
346
|
+
stateKey
|
347
|
+
}) => cId === chainId && stateKey === reference);
|
348
|
+
if (!query) {
|
349
|
+
log.warn(`Failed to find query:\n${reference} in\n${this.#queries.map(({
|
350
|
+
stateKey
|
351
|
+
}) => stateKey)}`);
|
352
|
+
return [];
|
353
|
+
}
|
354
|
+
return query.decodeResult(change);
|
355
|
+
});
|
356
|
+
}
|
357
|
+
}
|
358
|
+
|
281
359
|
const BalanceStatusLive = subscriptionId => `live-${subscriptionId}`;
|
282
360
|
function excludeFromTransferableAmount(locks) {
|
283
361
|
if (typeof locks === "string") return BigInt(locks);
|
@@ -528,13 +606,14 @@ class Balance {
|
|
528
606
|
get id() {
|
529
607
|
const {
|
530
608
|
source,
|
609
|
+
subSource,
|
531
610
|
address,
|
532
611
|
chainId,
|
533
612
|
evmNetworkId,
|
534
613
|
tokenId
|
535
614
|
} = this.#storage;
|
536
615
|
const locationId = chainId !== undefined ? chainId : evmNetworkId;
|
537
|
-
return
|
616
|
+
return [source, address, locationId, tokenId, subSource].filter(Boolean).join("-");
|
538
617
|
}
|
539
618
|
get source() {
|
540
619
|
return this.#storage.source;
|
@@ -589,10 +668,36 @@ class Balance {
|
|
589
668
|
get reserved() {
|
590
669
|
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"));
|
591
670
|
}
|
671
|
+
get reserves() {
|
672
|
+
return (Array.isArray(this.#storage.reserves) ? this.#storage.reserves : [this.#storage.reserves]).flatMap(reserve => {
|
673
|
+
if (reserve === undefined) return [];
|
674
|
+
if (typeof reserve === "string") return {
|
675
|
+
label: "other",
|
676
|
+
amount: this.#format(reserve)
|
677
|
+
};
|
678
|
+
return {
|
679
|
+
...reserve,
|
680
|
+
amount: this.#format(reserve.amount)
|
681
|
+
};
|
682
|
+
});
|
683
|
+
}
|
592
684
|
/** The frozen balance of this token. Is included in the free amount. */
|
593
685
|
get locked() {
|
594
686
|
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"));
|
595
687
|
}
|
688
|
+
get locks() {
|
689
|
+
return (Array.isArray(this.#storage.locks) ? this.#storage.locks : [this.#storage.locks]).flatMap(lock => {
|
690
|
+
if (lock === undefined) return [];
|
691
|
+
if (typeof lock === "string") return {
|
692
|
+
label: "other",
|
693
|
+
amount: this.#format(lock)
|
694
|
+
};
|
695
|
+
return {
|
696
|
+
...lock,
|
697
|
+
amount: this.#format(lock.amount)
|
698
|
+
};
|
699
|
+
});
|
700
|
+
}
|
596
701
|
/** @depreacted - use balance.locked */
|
597
702
|
get frozen() {
|
598
703
|
return this.locked;
|
@@ -706,4 +811,4 @@ class SumBalancesFormatter {
|
|
706
811
|
}
|
707
812
|
}
|
708
813
|
|
709
|
-
export { Balance, BalanceFormatter, BalanceStatusLive, Balances, DefaultBalanceModule, FiatSumBalancesFormatter, StorageHelper, SumBalancesFormatter, TalismanBalancesDatabase, balances, createSubscriptionId, createTypeRegistryCache, db, deleteSubscriptionId, deriveStatuses, excludeFromFeePayableLocks, excludeFromTransferableAmount, filterMirrorTokens, getValidSubscriptionIds, includeInTotalExtraAmount };
|
814
|
+
export { Balance, BalanceFormatter, BalanceStatusLive, Balances, DefaultBalanceModule, FiatSumBalancesFormatter, RpcStateQueryHelper, StorageHelper, SumBalancesFormatter, TalismanBalancesDatabase, balances, createSubscriptionId, createTypeRegistryCache, db, deleteSubscriptionId, deriveStatuses, excludeFromFeePayableLocks, excludeFromTransferableAmount, filterMirrorTokens, getValidSubscriptionIds, includeInTotalExtraAmount };
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@talismn/balances",
|
3
|
-
"version": "0.0.0-
|
3
|
+
"version": "0.0.0-pr677-20230413171850",
|
4
4
|
"author": "Talisman",
|
5
5
|
"homepage": "https://talisman.xyz",
|
6
6
|
"license": "UNLICENSED",
|
@@ -27,26 +27,28 @@
|
|
27
27
|
"clean": "rm -rf dist && rm -rf .turbo rm -rf node_modules"
|
28
28
|
},
|
29
29
|
"dependencies": {
|
30
|
-
"@talismn/chain-connector": "^0.0.0-
|
31
|
-
"@talismn/chain-connector-evm": "^0.0.0-
|
32
|
-
"@talismn/chaindata-provider": "^0.0.0-
|
33
|
-
"@talismn/token-rates": "^0.0.0-
|
34
|
-
"@talismn/util": "^0.
|
30
|
+
"@talismn/chain-connector": "^0.0.0-pr677-20230413171850",
|
31
|
+
"@talismn/chain-connector-evm": "^0.0.0-pr677-20230413171850",
|
32
|
+
"@talismn/chaindata-provider": "^0.0.0-pr677-20230413171850",
|
33
|
+
"@talismn/token-rates": "^0.0.0-pr677-20230413171850",
|
34
|
+
"@talismn/util": "^0.0.0-pr677-20230413171850",
|
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
|
+
"@polkadot/types": "^10.1.4",
|
40
41
|
"@talismn/eslint-config": "^0.0.1",
|
41
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": [
|