@talismn/balances 0.0.0-pr2075-20250710091134 → 0.0.0-pr2075-20250710124714
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/dist/declarations/src/BalancesProvider.d.ts +1 -1
- package/dist/talismn-balances.cjs.dev.js +124 -112
- package/dist/talismn-balances.cjs.prod.js +124 -112
- package/dist/talismn-balances.esm.js +125 -113
- package/package.json +10 -10
@@ -24,7 +24,7 @@ export declare class BalancesProvider {
|
|
24
24
|
private getStoredMiniMetadatas$;
|
25
25
|
private getDefaultMiniMetadatas$;
|
26
26
|
private getStoredBalances;
|
27
|
-
private cleanupAddressesByTokenId
|
27
|
+
private cleanupAddressesByTokenId$;
|
28
28
|
}
|
29
29
|
export declare const isAddressCompatibleWithNetwork: (network: Network, address: Address) => boolean;
|
30
30
|
export {};
|
@@ -6202,6 +6202,7 @@ const POOL = new PQueue__default.default({
|
|
6202
6202
|
const getMiniMetadatas = async (chainConnector, chaindataProvider, networkId, specVersion) => {
|
6203
6203
|
if (specVersion === undefined) specVersion = await getSpecVersion(chainConnector, networkId);
|
6204
6204
|
const cacheKey = getCacheKey(networkId, specVersion);
|
6205
|
+
if (CACHE.has(cacheKey)) return CACHE.get(cacheKey);
|
6205
6206
|
const pResult = POOL.add(() => fetchMiniMetadatas(chainConnector, chaindataProvider, networkId, specVersion));
|
6206
6207
|
|
6207
6208
|
// keep the results in cache (unless call fails) as observables call this function a lot of times
|
@@ -6215,15 +6216,13 @@ const getMiniMetadatas = async (chainConnector, chaindataProvider, networkId, sp
|
|
6215
6216
|
});
|
6216
6217
|
}
|
6217
6218
|
};
|
6218
|
-
const fetchMiniMetadatas = async (chainConnector, chaindataProvider, chainId, specVersion
|
6219
|
+
const fetchMiniMetadatas = async (chainConnector, chaindataProvider, chainId, specVersion) => {
|
6219
6220
|
const start = performance.now();
|
6220
6221
|
log.info("[miniMetadata] fetching minimetadatas for %s", chainId);
|
6221
6222
|
try {
|
6222
6223
|
const network = await chaindataProvider.getNetworkById(chainId, "polkadot");
|
6223
6224
|
if (!network) throw new Error(`Network ${chainId} not found in chaindataProvider`);
|
6224
|
-
signal?.throwIfAborted();
|
6225
6225
|
const metadataRpc = await getMetadataRpc(chainConnector, chainId);
|
6226
|
-
signal?.throwIfAborted();
|
6227
6226
|
return Promise.all(BALANCE_MODULES.filter(m => m.platform === "polkadot").map(mod => mod.getMiniMetadata({
|
6228
6227
|
networkId: chainId,
|
6229
6228
|
metadataRpc,
|
@@ -6256,9 +6255,9 @@ class BalancesProvider {
|
|
6256
6255
|
balances,
|
6257
6256
|
miniMetadatas
|
6258
6257
|
}) => ({
|
6259
|
-
balances: lodashEs.values(balances).filter(util.isNotNil),
|
6260
|
-
miniMetadatas: lodashEs.values(miniMetadatas).filter(util.isNotNil)
|
6261
|
-
})));
|
6258
|
+
balances: lodashEs.values(balances).filter(util.isNotNil).sort(sortByBalanceId),
|
6259
|
+
miniMetadatas: lodashEs.values(miniMetadatas).filter(util.isNotNil).sort(sortByMiniMetadataId)
|
6260
|
+
}), rxjs.shareReplay(1)));
|
6262
6261
|
}
|
6263
6262
|
get storedMiniMetadataMapById$() {
|
6264
6263
|
return this.#storage.pipe(rxjs.map(storage => lodashEs.keyBy(storage.miniMetadatas, m => m.id)), rxjs.distinctUntilChanged(lodashEs.isEqual), rxjs.shareReplay(1));
|
@@ -6266,39 +6265,35 @@ class BalancesProvider {
|
|
6266
6265
|
|
6267
6266
|
// this is the only public method
|
6268
6267
|
getBalances$(addressesByTokenId) {
|
6269
|
-
|
6270
|
-
//
|
6271
|
-
|
6272
|
-
|
6273
|
-
|
6274
|
-
|
6275
|
-
|
6276
|
-
|
6277
|
-
|
6278
|
-
|
6279
|
-
|
6280
|
-
|
6281
|
-
|
6282
|
-
|
6283
|
-
|
6284
|
-
|
6285
|
-
|
6286
|
-
|
6287
|
-
|
6288
|
-
|
6289
|
-
}) =>
|
6290
|
-
|
6291
|
-
|
6292
|
-
|
6293
|
-
|
6294
|
-
|
6295
|
-
|
6296
|
-
|
6297
|
-
|
6298
|
-
status: "initialising",
|
6299
|
-
balances: this.getStoredBalances(addressesByTokenId)
|
6300
|
-
}), rxjs.distinctUntilChanged(lodashEs.isEqual));
|
6301
|
-
});
|
6268
|
+
return this.cleanupAddressesByTokenId$(addressesByTokenId).pipe(rxjs.map(
|
6269
|
+
// split by network
|
6270
|
+
addressesByTokenId => lodashEs.toPairs(addressesByTokenId).reduce((acc, [tokenId, addresses]) => {
|
6271
|
+
const networkId = chaindataProvider.parseTokenId(tokenId).networkId;
|
6272
|
+
if (!acc[networkId]) acc[networkId] = {};
|
6273
|
+
acc[networkId][tokenId] = addresses;
|
6274
|
+
return acc;
|
6275
|
+
}, {})), rxjs.switchMap(addressesByTokenIdByNetworkId =>
|
6276
|
+
// fetch balances and start a 30s timer to mark the whole subscription live after 30s
|
6277
|
+
rxjs.combineLatest({
|
6278
|
+
isStale: rxjs.timer(30_000).pipe(rxjs.map(() => true), rxjs.startWith(false)),
|
6279
|
+
results: rxjs.combineLatest(lodashEs.toPairs(addressesByTokenIdByNetworkId).map(([networkId]) => this.getNetworkBalances$(networkId, addressesByTokenIdByNetworkId[networkId])))
|
6280
|
+
})), rxjs.map(
|
6281
|
+
// combine
|
6282
|
+
({
|
6283
|
+
isStale,
|
6284
|
+
results
|
6285
|
+
}) => ({
|
6286
|
+
status: !isStale && results.some(({
|
6287
|
+
status
|
6288
|
+
}) => status === "initialising") ? "initialising" : "live",
|
6289
|
+
balances: results.flatMap(result => result.balances.map(b => isStale && b.status !== "live" ? {
|
6290
|
+
...b,
|
6291
|
+
status: "stale"
|
6292
|
+
} : b)).sort(sortByBalanceId)
|
6293
|
+
})), rxjs.startWith({
|
6294
|
+
status: "initialising",
|
6295
|
+
balances: this.getStoredBalances(addressesByTokenId)
|
6296
|
+
}), rxjs.distinctUntilChanged(lodashEs.isEqual));
|
6302
6297
|
}
|
6303
6298
|
fetchBalances(addressesByTokenId) {
|
6304
6299
|
// TODO: better
|
@@ -6309,84 +6304,95 @@ class BalancesProvider {
|
|
6309
6304
|
}) => balances)));
|
6310
6305
|
}
|
6311
6306
|
getNetworkBalances$(networkId, addressesByTokenId) {
|
6312
|
-
|
6313
|
-
|
6314
|
-
|
6315
|
-
|
6316
|
-
const
|
6317
|
-
|
6318
|
-
|
6319
|
-
|
6320
|
-
const
|
6321
|
-
|
6322
|
-
|
6323
|
-
|
6324
|
-
|
6325
|
-
|
6326
|
-
|
6327
|
-
|
6328
|
-
|
6329
|
-
|
6330
|
-
|
6307
|
+
return util.getSharedObservable(`BalancesProvider.getNetorkBalances$`, {
|
6308
|
+
networkId,
|
6309
|
+
addressesByTokenId
|
6310
|
+
}, () => {
|
6311
|
+
const network$ = this.#chaindataProvider.getNetworkById$(networkId);
|
6312
|
+
const tokensMapById$ = this.#chaindataProvider.getTokensMapById$();
|
6313
|
+
const miniMetadatas$ = this.getNetworkMiniMetadatas$(networkId);
|
6314
|
+
return rxjs.combineLatest([network$, miniMetadatas$, tokensMapById$]).pipe(rxjs.switchMap(([network, miniMetadatas, tokensMapById]) => {
|
6315
|
+
const tokensAndAddresses = lodashEs.toPairs(addressesByTokenId).map(([tokenId, addresses]) => [tokensMapById[tokenId], addresses]);
|
6316
|
+
return rxjs.combineLatest(BALANCE_MODULES.filter(mod => mod.platform === network?.platform).map(mod => {
|
6317
|
+
const tokensWithAddresses = tokensAndAddresses.filter(([token]) => token.type === mod.type);
|
6318
|
+
const moduleAddressesByTokenId = lodashEs.fromPairs(tokensWithAddresses.map(([token, addresses]) => [token.id, addresses]));
|
6319
|
+
const miniMetadata = miniMetadatas.find(m => m.source === mod.type);
|
6320
|
+
|
6321
|
+
// all balance ids expected in result set
|
6322
|
+
const balanceIds = lodashEs.toPairs(moduleAddressesByTokenId).flatMap(([tokenId, addresses]) => addresses.map(address => getBalanceId({
|
6323
|
+
tokenId,
|
6324
|
+
address
|
6325
|
+
})));
|
6326
|
+
const initValue = {
|
6327
|
+
status: "initialising",
|
6328
|
+
balances: this.getStoredBalances(moduleAddressesByTokenId)
|
6329
|
+
};
|
6331
6330
|
|
6332
|
-
|
6333
|
-
|
6334
|
-
|
6335
|
-
|
6336
|
-
|
6337
|
-
|
6338
|
-
|
6339
|
-
|
6340
|
-
|
6341
|
-
|
6342
|
-
|
6343
|
-
|
6344
|
-
|
6345
|
-
|
6346
|
-
|
6347
|
-
|
6348
|
-
|
6349
|
-
|
6350
|
-
|
6351
|
-
|
6331
|
+
// updating storage has to be done on a per-module basis, so we know which balances can be deleted
|
6332
|
+
const updateStorage = results => {
|
6333
|
+
if (results.status !== "live") return;
|
6334
|
+
const storage = this.#storage.getValue();
|
6335
|
+
const balances = lodashEs.assign({}, storage.balances,
|
6336
|
+
// delete all balances expected in the result set. because if they are not present it means they are empty.
|
6337
|
+
lodashEs.fromPairs(balanceIds.map(balanceId => [balanceId, undefined])), lodashEs.keyBy(
|
6338
|
+
// storage balances must have status "cache", because they are used as start value when initialising subsequent subscriptions
|
6339
|
+
results.balances.map(b => ({
|
6340
|
+
...b,
|
6341
|
+
status: "cache"
|
6342
|
+
})), b => getBalanceId(b)));
|
6343
|
+
this.#storage.next(lodashEs.assign({}, storage, {
|
6344
|
+
balances
|
6345
|
+
}));
|
6346
|
+
};
|
6347
|
+
switch (mod.platform) {
|
6348
|
+
case "ethereum":
|
6349
|
+
{
|
6350
|
+
if (!this.#chainConnectors.evm) return rxjs.of(initValue);
|
6351
|
+
return mod.subscribeBalances({
|
6352
|
+
networkId,
|
6353
|
+
tokensWithAddresses,
|
6354
|
+
connector: this.#chainConnectors.evm
|
6355
|
+
}).pipe(rxjs.map(results => ({
|
6356
|
+
status: "live",
|
6357
|
+
// exclude zero balances
|
6358
|
+
balances: results.success.filter(b => new Balance(b).total.planck > 0n)
|
6359
|
+
})), rxjs.tap(updateStorage), rxjs.startWith(initValue));
|
6360
|
+
}
|
6361
|
+
case "polkadot":
|
6362
|
+
if (!this.#chainConnectors.substrate || !miniMetadata) {
|
6363
|
+
log.debug("[balances] no substrate connector or miniMetadata for polkadot", mod.type);
|
6364
|
+
return rxjs.of(initValue);
|
6365
|
+
}
|
6352
6366
|
return mod.subscribeBalances({
|
6353
6367
|
networkId,
|
6354
6368
|
tokensWithAddresses,
|
6355
|
-
connector: this.#chainConnectors.
|
6369
|
+
connector: this.#chainConnectors.substrate,
|
6370
|
+
miniMetadata: miniMetadata
|
6356
6371
|
}).pipe(rxjs.map(results => ({
|
6357
6372
|
status: "live",
|
6358
6373
|
// exclude zero balances
|
6359
6374
|
balances: results.success.filter(b => new Balance(b).total.planck > 0n)
|
6360
6375
|
})), rxjs.tap(updateStorage), rxjs.startWith(initValue));
|
6361
|
-
|
6362
|
-
|
6363
|
-
|
6364
|
-
|
6365
|
-
|
6366
|
-
|
6367
|
-
|
6368
|
-
|
6369
|
-
|
6370
|
-
|
6371
|
-
|
6372
|
-
|
6373
|
-
|
6374
|
-
|
6375
|
-
|
6376
|
-
|
6377
|
-
|
6378
|
-
|
6379
|
-
|
6380
|
-
|
6381
|
-
status: results.some(({
|
6382
|
-
status
|
6383
|
-
}) => status === "initialising") ? "initialising" : "live",
|
6384
|
-
balances: results.flatMap(result => result.balances)
|
6385
|
-
};
|
6386
|
-
}), rxjs.startWith({
|
6387
|
-
status: "initialising",
|
6388
|
-
balances: this.getStoredBalances(addressesByTokenId)
|
6389
|
-
}));
|
6376
|
+
}
|
6377
|
+
}));
|
6378
|
+
}), rxjs.map(results => {
|
6379
|
+
return {
|
6380
|
+
status: results.some(({
|
6381
|
+
status
|
6382
|
+
}) => status === "initialising") ? "initialising" : "live",
|
6383
|
+
balances: results.flatMap(result => result.balances).sort(sortByBalanceId)
|
6384
|
+
};
|
6385
|
+
}), rxjs.startWith({
|
6386
|
+
status: "initialising",
|
6387
|
+
balances: this.getStoredBalances(addressesByTokenId)
|
6388
|
+
}), rxjs.distinctUntilChanged(lodashEs.isEqual),
|
6389
|
+
// shareReplay + keepAlive allow for subscription to not restart as long as the inputs dont change
|
6390
|
+
// for example, if another network is enabled/disabled
|
6391
|
+
rxjs.shareReplay({
|
6392
|
+
refCount: true,
|
6393
|
+
bufferSize: 1
|
6394
|
+
}), util.keepAlive(2_000));
|
6395
|
+
});
|
6390
6396
|
}
|
6391
6397
|
getNetworkMiniMetadatas$(networkId) {
|
6392
6398
|
return this.#chaindataProvider.getNetworkById$(networkId).pipe(rxjs.switchMap(network => chaindataProvider.isNetworkDot(network) && this.#chainConnectors.substrate ? rxjs.from(getSpecVersion(this.#chainConnectors.substrate, networkId)).pipe(rxjs.switchMap(specVersion => this.getMiniMetadatas$(networkId, specVersion))) : rxjs.of([])));
|
@@ -6421,13 +6427,17 @@ class BalancesProvider {
|
|
6421
6427
|
miniMetadatas
|
6422
6428
|
}));
|
6423
6429
|
}));
|
6424
|
-
})
|
6430
|
+
}),
|
6431
|
+
// emit only when mini metadata changes, as a change here would restart all subscriptions for the network
|
6432
|
+
rxjs.distinctUntilChanged(lodashEs.isEqual));
|
6425
6433
|
}
|
6426
6434
|
getStoredMiniMetadatas$(miniMetadataIds) {
|
6427
6435
|
return this.storedMiniMetadataMapById$.pipe(rxjs.map(mapById => {
|
6428
6436
|
const miniMetadatas = miniMetadataIds.map(id => mapById[id]);
|
6429
6437
|
return miniMetadatas.length && miniMetadatas.every(util.isTruthy) ? miniMetadatas : null;
|
6430
|
-
})
|
6438
|
+
}),
|
6439
|
+
// source changes very often
|
6440
|
+
rxjs.distinctUntilChanged(lodashEs.isEqual));
|
6431
6441
|
}
|
6432
6442
|
getDefaultMiniMetadatas$(miniMetadataIds) {
|
6433
6443
|
return this.#chaindataProvider.miniMetadatasMapById$.pipe(rxjs.map(mapById => {
|
@@ -6440,9 +6450,9 @@ class BalancesProvider {
|
|
6440
6450
|
return balanceDefs.map(([tokenId, address]) => this.#storage.value.balances[getBalanceId({
|
6441
6451
|
address,
|
6442
6452
|
tokenId
|
6443
|
-
})]).filter(util.isNotNil).sort(
|
6453
|
+
})]).filter(util.isNotNil).sort(sortByBalanceId);
|
6444
6454
|
}
|
6445
|
-
cleanupAddressesByTokenId(addressesByTokenId) {
|
6455
|
+
cleanupAddressesByTokenId$(addressesByTokenId) {
|
6446
6456
|
return this.#chaindataProvider.getNetworksMapById$().pipe(rxjs.map(networksById => {
|
6447
6457
|
return lodashEs.fromPairs(lodashEs.toPairs(addressesByTokenId).map(([tokenId, addresses]) => {
|
6448
6458
|
const networkId = chaindataProvider.parseTokenId(tokenId).networkId;
|
@@ -6463,6 +6473,8 @@ const isAddressCompatibleWithNetwork = (network, address) => {
|
|
6463
6473
|
throw new Error("Unsupported network platform");
|
6464
6474
|
}
|
6465
6475
|
};
|
6476
|
+
const sortByBalanceId = (a, b) => getBalanceId(a).localeCompare(getBalanceId(b));
|
6477
|
+
const sortByMiniMetadataId = (a, b) => a.id.localeCompare(b.id);
|
6466
6478
|
|
6467
6479
|
Object.defineProperty(exports, "MINIMETADATA_VERSION", {
|
6468
6480
|
enumerable: true,
|
@@ -6202,6 +6202,7 @@ const POOL = new PQueue__default.default({
|
|
6202
6202
|
const getMiniMetadatas = async (chainConnector, chaindataProvider, networkId, specVersion) => {
|
6203
6203
|
if (specVersion === undefined) specVersion = await getSpecVersion(chainConnector, networkId);
|
6204
6204
|
const cacheKey = getCacheKey(networkId, specVersion);
|
6205
|
+
if (CACHE.has(cacheKey)) return CACHE.get(cacheKey);
|
6205
6206
|
const pResult = POOL.add(() => fetchMiniMetadatas(chainConnector, chaindataProvider, networkId, specVersion));
|
6206
6207
|
|
6207
6208
|
// keep the results in cache (unless call fails) as observables call this function a lot of times
|
@@ -6215,15 +6216,13 @@ const getMiniMetadatas = async (chainConnector, chaindataProvider, networkId, sp
|
|
6215
6216
|
});
|
6216
6217
|
}
|
6217
6218
|
};
|
6218
|
-
const fetchMiniMetadatas = async (chainConnector, chaindataProvider, chainId, specVersion
|
6219
|
+
const fetchMiniMetadatas = async (chainConnector, chaindataProvider, chainId, specVersion) => {
|
6219
6220
|
const start = performance.now();
|
6220
6221
|
log.info("[miniMetadata] fetching minimetadatas for %s", chainId);
|
6221
6222
|
try {
|
6222
6223
|
const network = await chaindataProvider.getNetworkById(chainId, "polkadot");
|
6223
6224
|
if (!network) throw new Error(`Network ${chainId} not found in chaindataProvider`);
|
6224
|
-
signal?.throwIfAborted();
|
6225
6225
|
const metadataRpc = await getMetadataRpc(chainConnector, chainId);
|
6226
|
-
signal?.throwIfAborted();
|
6227
6226
|
return Promise.all(BALANCE_MODULES.filter(m => m.platform === "polkadot").map(mod => mod.getMiniMetadata({
|
6228
6227
|
networkId: chainId,
|
6229
6228
|
metadataRpc,
|
@@ -6256,9 +6255,9 @@ class BalancesProvider {
|
|
6256
6255
|
balances,
|
6257
6256
|
miniMetadatas
|
6258
6257
|
}) => ({
|
6259
|
-
balances: lodashEs.values(balances).filter(util.isNotNil),
|
6260
|
-
miniMetadatas: lodashEs.values(miniMetadatas).filter(util.isNotNil)
|
6261
|
-
})));
|
6258
|
+
balances: lodashEs.values(balances).filter(util.isNotNil).sort(sortByBalanceId),
|
6259
|
+
miniMetadatas: lodashEs.values(miniMetadatas).filter(util.isNotNil).sort(sortByMiniMetadataId)
|
6260
|
+
}), rxjs.shareReplay(1)));
|
6262
6261
|
}
|
6263
6262
|
get storedMiniMetadataMapById$() {
|
6264
6263
|
return this.#storage.pipe(rxjs.map(storage => lodashEs.keyBy(storage.miniMetadatas, m => m.id)), rxjs.distinctUntilChanged(lodashEs.isEqual), rxjs.shareReplay(1));
|
@@ -6266,39 +6265,35 @@ class BalancesProvider {
|
|
6266
6265
|
|
6267
6266
|
// this is the only public method
|
6268
6267
|
getBalances$(addressesByTokenId) {
|
6269
|
-
|
6270
|
-
//
|
6271
|
-
|
6272
|
-
|
6273
|
-
|
6274
|
-
|
6275
|
-
|
6276
|
-
|
6277
|
-
|
6278
|
-
|
6279
|
-
|
6280
|
-
|
6281
|
-
|
6282
|
-
|
6283
|
-
|
6284
|
-
|
6285
|
-
|
6286
|
-
|
6287
|
-
|
6288
|
-
|
6289
|
-
}) =>
|
6290
|
-
|
6291
|
-
|
6292
|
-
|
6293
|
-
|
6294
|
-
|
6295
|
-
|
6296
|
-
|
6297
|
-
|
6298
|
-
status: "initialising",
|
6299
|
-
balances: this.getStoredBalances(addressesByTokenId)
|
6300
|
-
}), rxjs.distinctUntilChanged(lodashEs.isEqual));
|
6301
|
-
});
|
6268
|
+
return this.cleanupAddressesByTokenId$(addressesByTokenId).pipe(rxjs.map(
|
6269
|
+
// split by network
|
6270
|
+
addressesByTokenId => lodashEs.toPairs(addressesByTokenId).reduce((acc, [tokenId, addresses]) => {
|
6271
|
+
const networkId = chaindataProvider.parseTokenId(tokenId).networkId;
|
6272
|
+
if (!acc[networkId]) acc[networkId] = {};
|
6273
|
+
acc[networkId][tokenId] = addresses;
|
6274
|
+
return acc;
|
6275
|
+
}, {})), rxjs.switchMap(addressesByTokenIdByNetworkId =>
|
6276
|
+
// fetch balances and start a 30s timer to mark the whole subscription live after 30s
|
6277
|
+
rxjs.combineLatest({
|
6278
|
+
isStale: rxjs.timer(30_000).pipe(rxjs.map(() => true), rxjs.startWith(false)),
|
6279
|
+
results: rxjs.combineLatest(lodashEs.toPairs(addressesByTokenIdByNetworkId).map(([networkId]) => this.getNetworkBalances$(networkId, addressesByTokenIdByNetworkId[networkId])))
|
6280
|
+
})), rxjs.map(
|
6281
|
+
// combine
|
6282
|
+
({
|
6283
|
+
isStale,
|
6284
|
+
results
|
6285
|
+
}) => ({
|
6286
|
+
status: !isStale && results.some(({
|
6287
|
+
status
|
6288
|
+
}) => status === "initialising") ? "initialising" : "live",
|
6289
|
+
balances: results.flatMap(result => result.balances.map(b => isStale && b.status !== "live" ? {
|
6290
|
+
...b,
|
6291
|
+
status: "stale"
|
6292
|
+
} : b)).sort(sortByBalanceId)
|
6293
|
+
})), rxjs.startWith({
|
6294
|
+
status: "initialising",
|
6295
|
+
balances: this.getStoredBalances(addressesByTokenId)
|
6296
|
+
}), rxjs.distinctUntilChanged(lodashEs.isEqual));
|
6302
6297
|
}
|
6303
6298
|
fetchBalances(addressesByTokenId) {
|
6304
6299
|
// TODO: better
|
@@ -6309,84 +6304,95 @@ class BalancesProvider {
|
|
6309
6304
|
}) => balances)));
|
6310
6305
|
}
|
6311
6306
|
getNetworkBalances$(networkId, addressesByTokenId) {
|
6312
|
-
|
6313
|
-
|
6314
|
-
|
6315
|
-
|
6316
|
-
const
|
6317
|
-
|
6318
|
-
|
6319
|
-
|
6320
|
-
const
|
6321
|
-
|
6322
|
-
|
6323
|
-
|
6324
|
-
|
6325
|
-
|
6326
|
-
|
6327
|
-
|
6328
|
-
|
6329
|
-
|
6330
|
-
|
6307
|
+
return util.getSharedObservable(`BalancesProvider.getNetorkBalances$`, {
|
6308
|
+
networkId,
|
6309
|
+
addressesByTokenId
|
6310
|
+
}, () => {
|
6311
|
+
const network$ = this.#chaindataProvider.getNetworkById$(networkId);
|
6312
|
+
const tokensMapById$ = this.#chaindataProvider.getTokensMapById$();
|
6313
|
+
const miniMetadatas$ = this.getNetworkMiniMetadatas$(networkId);
|
6314
|
+
return rxjs.combineLatest([network$, miniMetadatas$, tokensMapById$]).pipe(rxjs.switchMap(([network, miniMetadatas, tokensMapById]) => {
|
6315
|
+
const tokensAndAddresses = lodashEs.toPairs(addressesByTokenId).map(([tokenId, addresses]) => [tokensMapById[tokenId], addresses]);
|
6316
|
+
return rxjs.combineLatest(BALANCE_MODULES.filter(mod => mod.platform === network?.platform).map(mod => {
|
6317
|
+
const tokensWithAddresses = tokensAndAddresses.filter(([token]) => token.type === mod.type);
|
6318
|
+
const moduleAddressesByTokenId = lodashEs.fromPairs(tokensWithAddresses.map(([token, addresses]) => [token.id, addresses]));
|
6319
|
+
const miniMetadata = miniMetadatas.find(m => m.source === mod.type);
|
6320
|
+
|
6321
|
+
// all balance ids expected in result set
|
6322
|
+
const balanceIds = lodashEs.toPairs(moduleAddressesByTokenId).flatMap(([tokenId, addresses]) => addresses.map(address => getBalanceId({
|
6323
|
+
tokenId,
|
6324
|
+
address
|
6325
|
+
})));
|
6326
|
+
const initValue = {
|
6327
|
+
status: "initialising",
|
6328
|
+
balances: this.getStoredBalances(moduleAddressesByTokenId)
|
6329
|
+
};
|
6331
6330
|
|
6332
|
-
|
6333
|
-
|
6334
|
-
|
6335
|
-
|
6336
|
-
|
6337
|
-
|
6338
|
-
|
6339
|
-
|
6340
|
-
|
6341
|
-
|
6342
|
-
|
6343
|
-
|
6344
|
-
|
6345
|
-
|
6346
|
-
|
6347
|
-
|
6348
|
-
|
6349
|
-
|
6350
|
-
|
6351
|
-
|
6331
|
+
// updating storage has to be done on a per-module basis, so we know which balances can be deleted
|
6332
|
+
const updateStorage = results => {
|
6333
|
+
if (results.status !== "live") return;
|
6334
|
+
const storage = this.#storage.getValue();
|
6335
|
+
const balances = lodashEs.assign({}, storage.balances,
|
6336
|
+
// delete all balances expected in the result set. because if they are not present it means they are empty.
|
6337
|
+
lodashEs.fromPairs(balanceIds.map(balanceId => [balanceId, undefined])), lodashEs.keyBy(
|
6338
|
+
// storage balances must have status "cache", because they are used as start value when initialising subsequent subscriptions
|
6339
|
+
results.balances.map(b => ({
|
6340
|
+
...b,
|
6341
|
+
status: "cache"
|
6342
|
+
})), b => getBalanceId(b)));
|
6343
|
+
this.#storage.next(lodashEs.assign({}, storage, {
|
6344
|
+
balances
|
6345
|
+
}));
|
6346
|
+
};
|
6347
|
+
switch (mod.platform) {
|
6348
|
+
case "ethereum":
|
6349
|
+
{
|
6350
|
+
if (!this.#chainConnectors.evm) return rxjs.of(initValue);
|
6351
|
+
return mod.subscribeBalances({
|
6352
|
+
networkId,
|
6353
|
+
tokensWithAddresses,
|
6354
|
+
connector: this.#chainConnectors.evm
|
6355
|
+
}).pipe(rxjs.map(results => ({
|
6356
|
+
status: "live",
|
6357
|
+
// exclude zero balances
|
6358
|
+
balances: results.success.filter(b => new Balance(b).total.planck > 0n)
|
6359
|
+
})), rxjs.tap(updateStorage), rxjs.startWith(initValue));
|
6360
|
+
}
|
6361
|
+
case "polkadot":
|
6362
|
+
if (!this.#chainConnectors.substrate || !miniMetadata) {
|
6363
|
+
log.debug("[balances] no substrate connector or miniMetadata for polkadot", mod.type);
|
6364
|
+
return rxjs.of(initValue);
|
6365
|
+
}
|
6352
6366
|
return mod.subscribeBalances({
|
6353
6367
|
networkId,
|
6354
6368
|
tokensWithAddresses,
|
6355
|
-
connector: this.#chainConnectors.
|
6369
|
+
connector: this.#chainConnectors.substrate,
|
6370
|
+
miniMetadata: miniMetadata
|
6356
6371
|
}).pipe(rxjs.map(results => ({
|
6357
6372
|
status: "live",
|
6358
6373
|
// exclude zero balances
|
6359
6374
|
balances: results.success.filter(b => new Balance(b).total.planck > 0n)
|
6360
6375
|
})), rxjs.tap(updateStorage), rxjs.startWith(initValue));
|
6361
|
-
|
6362
|
-
|
6363
|
-
|
6364
|
-
|
6365
|
-
|
6366
|
-
|
6367
|
-
|
6368
|
-
|
6369
|
-
|
6370
|
-
|
6371
|
-
|
6372
|
-
|
6373
|
-
|
6374
|
-
|
6375
|
-
|
6376
|
-
|
6377
|
-
|
6378
|
-
|
6379
|
-
|
6380
|
-
|
6381
|
-
status: results.some(({
|
6382
|
-
status
|
6383
|
-
}) => status === "initialising") ? "initialising" : "live",
|
6384
|
-
balances: results.flatMap(result => result.balances)
|
6385
|
-
};
|
6386
|
-
}), rxjs.startWith({
|
6387
|
-
status: "initialising",
|
6388
|
-
balances: this.getStoredBalances(addressesByTokenId)
|
6389
|
-
}));
|
6376
|
+
}
|
6377
|
+
}));
|
6378
|
+
}), rxjs.map(results => {
|
6379
|
+
return {
|
6380
|
+
status: results.some(({
|
6381
|
+
status
|
6382
|
+
}) => status === "initialising") ? "initialising" : "live",
|
6383
|
+
balances: results.flatMap(result => result.balances).sort(sortByBalanceId)
|
6384
|
+
};
|
6385
|
+
}), rxjs.startWith({
|
6386
|
+
status: "initialising",
|
6387
|
+
balances: this.getStoredBalances(addressesByTokenId)
|
6388
|
+
}), rxjs.distinctUntilChanged(lodashEs.isEqual),
|
6389
|
+
// shareReplay + keepAlive allow for subscription to not restart as long as the inputs dont change
|
6390
|
+
// for example, if another network is enabled/disabled
|
6391
|
+
rxjs.shareReplay({
|
6392
|
+
refCount: true,
|
6393
|
+
bufferSize: 1
|
6394
|
+
}), util.keepAlive(2_000));
|
6395
|
+
});
|
6390
6396
|
}
|
6391
6397
|
getNetworkMiniMetadatas$(networkId) {
|
6392
6398
|
return this.#chaindataProvider.getNetworkById$(networkId).pipe(rxjs.switchMap(network => chaindataProvider.isNetworkDot(network) && this.#chainConnectors.substrate ? rxjs.from(getSpecVersion(this.#chainConnectors.substrate, networkId)).pipe(rxjs.switchMap(specVersion => this.getMiniMetadatas$(networkId, specVersion))) : rxjs.of([])));
|
@@ -6421,13 +6427,17 @@ class BalancesProvider {
|
|
6421
6427
|
miniMetadatas
|
6422
6428
|
}));
|
6423
6429
|
}));
|
6424
|
-
})
|
6430
|
+
}),
|
6431
|
+
// emit only when mini metadata changes, as a change here would restart all subscriptions for the network
|
6432
|
+
rxjs.distinctUntilChanged(lodashEs.isEqual));
|
6425
6433
|
}
|
6426
6434
|
getStoredMiniMetadatas$(miniMetadataIds) {
|
6427
6435
|
return this.storedMiniMetadataMapById$.pipe(rxjs.map(mapById => {
|
6428
6436
|
const miniMetadatas = miniMetadataIds.map(id => mapById[id]);
|
6429
6437
|
return miniMetadatas.length && miniMetadatas.every(util.isTruthy) ? miniMetadatas : null;
|
6430
|
-
})
|
6438
|
+
}),
|
6439
|
+
// source changes very often
|
6440
|
+
rxjs.distinctUntilChanged(lodashEs.isEqual));
|
6431
6441
|
}
|
6432
6442
|
getDefaultMiniMetadatas$(miniMetadataIds) {
|
6433
6443
|
return this.#chaindataProvider.miniMetadatasMapById$.pipe(rxjs.map(mapById => {
|
@@ -6440,9 +6450,9 @@ class BalancesProvider {
|
|
6440
6450
|
return balanceDefs.map(([tokenId, address]) => this.#storage.value.balances[getBalanceId({
|
6441
6451
|
address,
|
6442
6452
|
tokenId
|
6443
|
-
})]).filter(util.isNotNil).sort(
|
6453
|
+
})]).filter(util.isNotNil).sort(sortByBalanceId);
|
6444
6454
|
}
|
6445
|
-
cleanupAddressesByTokenId(addressesByTokenId) {
|
6455
|
+
cleanupAddressesByTokenId$(addressesByTokenId) {
|
6446
6456
|
return this.#chaindataProvider.getNetworksMapById$().pipe(rxjs.map(networksById => {
|
6447
6457
|
return lodashEs.fromPairs(lodashEs.toPairs(addressesByTokenId).map(([tokenId, addresses]) => {
|
6448
6458
|
const networkId = chaindataProvider.parseTokenId(tokenId).networkId;
|
@@ -6463,6 +6473,8 @@ const isAddressCompatibleWithNetwork = (network, address) => {
|
|
6463
6473
|
throw new Error("Unsupported network platform");
|
6464
6474
|
}
|
6465
6475
|
};
|
6476
|
+
const sortByBalanceId = (a, b) => getBalanceId(a).localeCompare(getBalanceId(b));
|
6477
|
+
const sortByMiniMetadataId = (a, b) => a.id.localeCompare(b.id);
|
6466
6478
|
|
6467
6479
|
Object.defineProperty(exports, "MINIMETADATA_VERSION", {
|
6468
6480
|
enumerable: true,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { EvmErc20TokenSchema, parseTokenId, parseEvmErc20TokenId, evmErc20TokenId, isTokenOfType, TokenBaseSchema, EvmNativeTokenSchema, evmNativeTokenId, EvmUniswapV2TokenSchema, evmUniswapV2TokenId, SubAssetsTokenSchema, subAssetTokenId, MINIMETADATA_VERSION, SubForeignAssetsTokenSchema, subForeignAssetTokenId, SubHydrationTokenSchema, subHydrationTokenId, SubNativeTokenSchema, subNativeTokenId, SubPsp22TokenSchema, subPsp22TokenId, SubTokensTokenSchema, subTokensTokenId, isNetworkDot } from '@talismn/chaindata-provider';
|
2
2
|
export { MINIMETADATA_VERSION } from '@talismn/chaindata-provider';
|
3
|
-
import { isEthereumAddress, isNotNil, BigMath, isArrayOf, isBigInt, planckToTokens, isAbortError, getSharedObservable, isTruthy } from '@talismn/util';
|
3
|
+
import { isEthereumAddress, isNotNil, BigMath, isArrayOf, isBigInt, planckToTokens, isAbortError, getSharedObservable, keepAlive, isTruthy } from '@talismn/util';
|
4
4
|
import { parseAbi, erc20Abi, getContract, ContractFunctionExecutionError, hexToString, erc20Abi_bytes32, encodeFunctionData, withRetry } from 'viem';
|
5
5
|
import { assign, omit, isEqual, keyBy, keys, uniq, fromPairs, values, toPairs } from 'lodash-es';
|
6
6
|
import z from 'zod/v4';
|
@@ -6193,6 +6193,7 @@ const POOL = new PQueue({
|
|
6193
6193
|
const getMiniMetadatas = async (chainConnector, chaindataProvider, networkId, specVersion) => {
|
6194
6194
|
if (specVersion === undefined) specVersion = await getSpecVersion(chainConnector, networkId);
|
6195
6195
|
const cacheKey = getCacheKey(networkId, specVersion);
|
6196
|
+
if (CACHE.has(cacheKey)) return CACHE.get(cacheKey);
|
6196
6197
|
const pResult = POOL.add(() => fetchMiniMetadatas(chainConnector, chaindataProvider, networkId, specVersion));
|
6197
6198
|
|
6198
6199
|
// keep the results in cache (unless call fails) as observables call this function a lot of times
|
@@ -6206,15 +6207,13 @@ const getMiniMetadatas = async (chainConnector, chaindataProvider, networkId, sp
|
|
6206
6207
|
});
|
6207
6208
|
}
|
6208
6209
|
};
|
6209
|
-
const fetchMiniMetadatas = async (chainConnector, chaindataProvider, chainId, specVersion
|
6210
|
+
const fetchMiniMetadatas = async (chainConnector, chaindataProvider, chainId, specVersion) => {
|
6210
6211
|
const start = performance.now();
|
6211
6212
|
log.info("[miniMetadata] fetching minimetadatas for %s", chainId);
|
6212
6213
|
try {
|
6213
6214
|
const network = await chaindataProvider.getNetworkById(chainId, "polkadot");
|
6214
6215
|
if (!network) throw new Error(`Network ${chainId} not found in chaindataProvider`);
|
6215
|
-
signal?.throwIfAborted();
|
6216
6216
|
const metadataRpc = await getMetadataRpc(chainConnector, chainId);
|
6217
|
-
signal?.throwIfAborted();
|
6218
6217
|
return Promise.all(BALANCE_MODULES.filter(m => m.platform === "polkadot").map(mod => mod.getMiniMetadata({
|
6219
6218
|
networkId: chainId,
|
6220
6219
|
metadataRpc,
|
@@ -6247,9 +6246,9 @@ class BalancesProvider {
|
|
6247
6246
|
balances,
|
6248
6247
|
miniMetadatas
|
6249
6248
|
}) => ({
|
6250
|
-
balances: values(balances).filter(isNotNil),
|
6251
|
-
miniMetadatas: values(miniMetadatas).filter(isNotNil)
|
6252
|
-
})));
|
6249
|
+
balances: values(balances).filter(isNotNil).sort(sortByBalanceId),
|
6250
|
+
miniMetadatas: values(miniMetadatas).filter(isNotNil).sort(sortByMiniMetadataId)
|
6251
|
+
}), shareReplay(1)));
|
6253
6252
|
}
|
6254
6253
|
get storedMiniMetadataMapById$() {
|
6255
6254
|
return this.#storage.pipe(map(storage => keyBy(storage.miniMetadatas, m => m.id)), distinctUntilChanged(isEqual), shareReplay(1));
|
@@ -6257,39 +6256,35 @@ class BalancesProvider {
|
|
6257
6256
|
|
6258
6257
|
// this is the only public method
|
6259
6258
|
getBalances$(addressesByTokenId) {
|
6260
|
-
|
6261
|
-
//
|
6262
|
-
|
6263
|
-
|
6264
|
-
|
6265
|
-
|
6266
|
-
|
6267
|
-
|
6268
|
-
|
6269
|
-
|
6270
|
-
|
6271
|
-
|
6272
|
-
|
6273
|
-
|
6274
|
-
|
6275
|
-
|
6276
|
-
|
6277
|
-
|
6278
|
-
|
6279
|
-
|
6280
|
-
}) =>
|
6281
|
-
|
6282
|
-
|
6283
|
-
|
6284
|
-
|
6285
|
-
|
6286
|
-
|
6287
|
-
|
6288
|
-
|
6289
|
-
status: "initialising",
|
6290
|
-
balances: this.getStoredBalances(addressesByTokenId)
|
6291
|
-
}), distinctUntilChanged(isEqual));
|
6292
|
-
});
|
6259
|
+
return this.cleanupAddressesByTokenId$(addressesByTokenId).pipe(map(
|
6260
|
+
// split by network
|
6261
|
+
addressesByTokenId => toPairs(addressesByTokenId).reduce((acc, [tokenId, addresses]) => {
|
6262
|
+
const networkId = parseTokenId(tokenId).networkId;
|
6263
|
+
if (!acc[networkId]) acc[networkId] = {};
|
6264
|
+
acc[networkId][tokenId] = addresses;
|
6265
|
+
return acc;
|
6266
|
+
}, {})), switchMap(addressesByTokenIdByNetworkId =>
|
6267
|
+
// fetch balances and start a 30s timer to mark the whole subscription live after 30s
|
6268
|
+
combineLatest({
|
6269
|
+
isStale: timer(30_000).pipe(map(() => true), startWith(false)),
|
6270
|
+
results: combineLatest(toPairs(addressesByTokenIdByNetworkId).map(([networkId]) => this.getNetworkBalances$(networkId, addressesByTokenIdByNetworkId[networkId])))
|
6271
|
+
})), map(
|
6272
|
+
// combine
|
6273
|
+
({
|
6274
|
+
isStale,
|
6275
|
+
results
|
6276
|
+
}) => ({
|
6277
|
+
status: !isStale && results.some(({
|
6278
|
+
status
|
6279
|
+
}) => status === "initialising") ? "initialising" : "live",
|
6280
|
+
balances: results.flatMap(result => result.balances.map(b => isStale && b.status !== "live" ? {
|
6281
|
+
...b,
|
6282
|
+
status: "stale"
|
6283
|
+
} : b)).sort(sortByBalanceId)
|
6284
|
+
})), startWith({
|
6285
|
+
status: "initialising",
|
6286
|
+
balances: this.getStoredBalances(addressesByTokenId)
|
6287
|
+
}), distinctUntilChanged(isEqual));
|
6293
6288
|
}
|
6294
6289
|
fetchBalances(addressesByTokenId) {
|
6295
6290
|
// TODO: better
|
@@ -6300,84 +6295,95 @@ class BalancesProvider {
|
|
6300
6295
|
}) => balances)));
|
6301
6296
|
}
|
6302
6297
|
getNetworkBalances$(networkId, addressesByTokenId) {
|
6303
|
-
|
6304
|
-
|
6305
|
-
|
6306
|
-
|
6307
|
-
const
|
6308
|
-
|
6309
|
-
|
6310
|
-
|
6311
|
-
const
|
6312
|
-
|
6313
|
-
|
6314
|
-
|
6315
|
-
|
6316
|
-
|
6317
|
-
|
6318
|
-
|
6319
|
-
|
6320
|
-
|
6321
|
-
|
6298
|
+
return getSharedObservable(`BalancesProvider.getNetorkBalances$`, {
|
6299
|
+
networkId,
|
6300
|
+
addressesByTokenId
|
6301
|
+
}, () => {
|
6302
|
+
const network$ = this.#chaindataProvider.getNetworkById$(networkId);
|
6303
|
+
const tokensMapById$ = this.#chaindataProvider.getTokensMapById$();
|
6304
|
+
const miniMetadatas$ = this.getNetworkMiniMetadatas$(networkId);
|
6305
|
+
return combineLatest([network$, miniMetadatas$, tokensMapById$]).pipe(switchMap(([network, miniMetadatas, tokensMapById]) => {
|
6306
|
+
const tokensAndAddresses = toPairs(addressesByTokenId).map(([tokenId, addresses]) => [tokensMapById[tokenId], addresses]);
|
6307
|
+
return combineLatest(BALANCE_MODULES.filter(mod => mod.platform === network?.platform).map(mod => {
|
6308
|
+
const tokensWithAddresses = tokensAndAddresses.filter(([token]) => token.type === mod.type);
|
6309
|
+
const moduleAddressesByTokenId = fromPairs(tokensWithAddresses.map(([token, addresses]) => [token.id, addresses]));
|
6310
|
+
const miniMetadata = miniMetadatas.find(m => m.source === mod.type);
|
6311
|
+
|
6312
|
+
// all balance ids expected in result set
|
6313
|
+
const balanceIds = toPairs(moduleAddressesByTokenId).flatMap(([tokenId, addresses]) => addresses.map(address => getBalanceId({
|
6314
|
+
tokenId,
|
6315
|
+
address
|
6316
|
+
})));
|
6317
|
+
const initValue = {
|
6318
|
+
status: "initialising",
|
6319
|
+
balances: this.getStoredBalances(moduleAddressesByTokenId)
|
6320
|
+
};
|
6322
6321
|
|
6323
|
-
|
6324
|
-
|
6325
|
-
|
6326
|
-
|
6327
|
-
|
6328
|
-
|
6329
|
-
|
6330
|
-
|
6331
|
-
|
6332
|
-
|
6333
|
-
|
6334
|
-
|
6335
|
-
|
6336
|
-
|
6337
|
-
|
6338
|
-
|
6339
|
-
|
6340
|
-
|
6341
|
-
|
6342
|
-
|
6322
|
+
// updating storage has to be done on a per-module basis, so we know which balances can be deleted
|
6323
|
+
const updateStorage = results => {
|
6324
|
+
if (results.status !== "live") return;
|
6325
|
+
const storage = this.#storage.getValue();
|
6326
|
+
const balances = assign({}, storage.balances,
|
6327
|
+
// delete all balances expected in the result set. because if they are not present it means they are empty.
|
6328
|
+
fromPairs(balanceIds.map(balanceId => [balanceId, undefined])), keyBy(
|
6329
|
+
// storage balances must have status "cache", because they are used as start value when initialising subsequent subscriptions
|
6330
|
+
results.balances.map(b => ({
|
6331
|
+
...b,
|
6332
|
+
status: "cache"
|
6333
|
+
})), b => getBalanceId(b)));
|
6334
|
+
this.#storage.next(assign({}, storage, {
|
6335
|
+
balances
|
6336
|
+
}));
|
6337
|
+
};
|
6338
|
+
switch (mod.platform) {
|
6339
|
+
case "ethereum":
|
6340
|
+
{
|
6341
|
+
if (!this.#chainConnectors.evm) return of(initValue);
|
6342
|
+
return mod.subscribeBalances({
|
6343
|
+
networkId,
|
6344
|
+
tokensWithAddresses,
|
6345
|
+
connector: this.#chainConnectors.evm
|
6346
|
+
}).pipe(map(results => ({
|
6347
|
+
status: "live",
|
6348
|
+
// exclude zero balances
|
6349
|
+
balances: results.success.filter(b => new Balance(b).total.planck > 0n)
|
6350
|
+
})), tap(updateStorage), startWith(initValue));
|
6351
|
+
}
|
6352
|
+
case "polkadot":
|
6353
|
+
if (!this.#chainConnectors.substrate || !miniMetadata) {
|
6354
|
+
log.debug("[balances] no substrate connector or miniMetadata for polkadot", mod.type);
|
6355
|
+
return of(initValue);
|
6356
|
+
}
|
6343
6357
|
return mod.subscribeBalances({
|
6344
6358
|
networkId,
|
6345
6359
|
tokensWithAddresses,
|
6346
|
-
connector: this.#chainConnectors.
|
6360
|
+
connector: this.#chainConnectors.substrate,
|
6361
|
+
miniMetadata: miniMetadata
|
6347
6362
|
}).pipe(map(results => ({
|
6348
6363
|
status: "live",
|
6349
6364
|
// exclude zero balances
|
6350
6365
|
balances: results.success.filter(b => new Balance(b).total.planck > 0n)
|
6351
6366
|
})), tap(updateStorage), startWith(initValue));
|
6352
|
-
|
6353
|
-
|
6354
|
-
|
6355
|
-
|
6356
|
-
|
6357
|
-
|
6358
|
-
|
6359
|
-
|
6360
|
-
|
6361
|
-
|
6362
|
-
|
6363
|
-
|
6364
|
-
|
6365
|
-
|
6366
|
-
|
6367
|
-
|
6368
|
-
|
6369
|
-
|
6370
|
-
|
6371
|
-
|
6372
|
-
status: results.some(({
|
6373
|
-
status
|
6374
|
-
}) => status === "initialising") ? "initialising" : "live",
|
6375
|
-
balances: results.flatMap(result => result.balances)
|
6376
|
-
};
|
6377
|
-
}), startWith({
|
6378
|
-
status: "initialising",
|
6379
|
-
balances: this.getStoredBalances(addressesByTokenId)
|
6380
|
-
}));
|
6367
|
+
}
|
6368
|
+
}));
|
6369
|
+
}), map(results => {
|
6370
|
+
return {
|
6371
|
+
status: results.some(({
|
6372
|
+
status
|
6373
|
+
}) => status === "initialising") ? "initialising" : "live",
|
6374
|
+
balances: results.flatMap(result => result.balances).sort(sortByBalanceId)
|
6375
|
+
};
|
6376
|
+
}), startWith({
|
6377
|
+
status: "initialising",
|
6378
|
+
balances: this.getStoredBalances(addressesByTokenId)
|
6379
|
+
}), distinctUntilChanged(isEqual),
|
6380
|
+
// shareReplay + keepAlive allow for subscription to not restart as long as the inputs dont change
|
6381
|
+
// for example, if another network is enabled/disabled
|
6382
|
+
shareReplay({
|
6383
|
+
refCount: true,
|
6384
|
+
bufferSize: 1
|
6385
|
+
}), keepAlive(2_000));
|
6386
|
+
});
|
6381
6387
|
}
|
6382
6388
|
getNetworkMiniMetadatas$(networkId) {
|
6383
6389
|
return this.#chaindataProvider.getNetworkById$(networkId).pipe(switchMap(network => isNetworkDot(network) && this.#chainConnectors.substrate ? from(getSpecVersion(this.#chainConnectors.substrate, networkId)).pipe(switchMap(specVersion => this.getMiniMetadatas$(networkId, specVersion))) : of([])));
|
@@ -6412,13 +6418,17 @@ class BalancesProvider {
|
|
6412
6418
|
miniMetadatas
|
6413
6419
|
}));
|
6414
6420
|
}));
|
6415
|
-
})
|
6421
|
+
}),
|
6422
|
+
// emit only when mini metadata changes, as a change here would restart all subscriptions for the network
|
6423
|
+
distinctUntilChanged(isEqual));
|
6416
6424
|
}
|
6417
6425
|
getStoredMiniMetadatas$(miniMetadataIds) {
|
6418
6426
|
return this.storedMiniMetadataMapById$.pipe(map(mapById => {
|
6419
6427
|
const miniMetadatas = miniMetadataIds.map(id => mapById[id]);
|
6420
6428
|
return miniMetadatas.length && miniMetadatas.every(isTruthy) ? miniMetadatas : null;
|
6421
|
-
})
|
6429
|
+
}),
|
6430
|
+
// source changes very often
|
6431
|
+
distinctUntilChanged(isEqual));
|
6422
6432
|
}
|
6423
6433
|
getDefaultMiniMetadatas$(miniMetadataIds) {
|
6424
6434
|
return this.#chaindataProvider.miniMetadatasMapById$.pipe(map(mapById => {
|
@@ -6431,9 +6441,9 @@ class BalancesProvider {
|
|
6431
6441
|
return balanceDefs.map(([tokenId, address]) => this.#storage.value.balances[getBalanceId({
|
6432
6442
|
address,
|
6433
6443
|
tokenId
|
6434
|
-
})]).filter(isNotNil).sort(
|
6444
|
+
})]).filter(isNotNil).sort(sortByBalanceId);
|
6435
6445
|
}
|
6436
|
-
cleanupAddressesByTokenId(addressesByTokenId) {
|
6446
|
+
cleanupAddressesByTokenId$(addressesByTokenId) {
|
6437
6447
|
return this.#chaindataProvider.getNetworksMapById$().pipe(map(networksById => {
|
6438
6448
|
return fromPairs(toPairs(addressesByTokenId).map(([tokenId, addresses]) => {
|
6439
6449
|
const networkId = parseTokenId(tokenId).networkId;
|
@@ -6454,5 +6464,7 @@ const isAddressCompatibleWithNetwork = (network, address) => {
|
|
6454
6464
|
throw new Error("Unsupported network platform");
|
6455
6465
|
}
|
6456
6466
|
};
|
6467
|
+
const sortByBalanceId = (a, b) => getBalanceId(a).localeCompare(getBalanceId(b));
|
6468
|
+
const sortByMiniMetadataId = (a, b) => a.id.localeCompare(b.id);
|
6457
6469
|
|
6458
6470
|
export { BALANCE_MODULES, Balance, BalanceFormatter, BalanceValueGetter, Balances, BalancesProvider, Change24hCurrencyFormatter, EvmErc20BalanceModule, EvmErc20TokenConfigSchema, EvmNativeBalanceModule, EvmNativeTokenConfigSchema, EvmUniswapV2BalanceModule, EvmUniswapV2TokenConfigSchema, FiatSumBalancesFormatter, ONE_ALPHA_TOKEN, PlanckSumBalancesFormatter, SCALE_FACTOR, SUBTENSOR_MIN_STAKE_AMOUNT_PLANK, SUBTENSOR_ROOT_NETUID, SubAssetsBalanceModule, SubAssetsTokenConfigSchema, SubForeignAssetsBalanceModule, SubForeignAssetsTokenConfigSchema, SubHydrationBalanceModule, SubHydrationTokenConfigSchema, SubNativeBalanceModule, SubNativeMiniMetadataExtraSchema, SubNativeModuleConfigSchema, SubNativeTokenConfigSchema, SubPsp22BalanceModule, SubPsp22TokenConfigSchema, SubTokensBalanceModule, SubTokensMiniMetadataExtraSchema, SubTokensModuleConfigSchema, SubTokensTokenConfigSchema, SumBalancesFormatter, abiMulticall, calculateAlphaPrice, calculateTaoAmountFromAlpha, calculateTaoFromDynamicInfo, deriveMiniMetadataId, erc20BalancesAggregatorAbi, excludeFromFeePayableLocks, excludeFromTransferableAmount, filterBaseLocks, filterMirrorTokens, getBalanceId, getLockTitle, getLockedType, getValueId, includeInTotalExtraAmount, isAddressCompatibleWithNetwork, uniswapV2PairAbi };
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@talismn/balances",
|
3
|
-
"version": "0.0.0-pr2075-
|
3
|
+
"version": "0.0.0-pr2075-20250710124714",
|
4
4
|
"author": "Talisman",
|
5
5
|
"homepage": "https://talisman.xyz",
|
6
6
|
"license": "GPL-3.0-or-later",
|
@@ -34,13 +34,13 @@
|
|
34
34
|
"scale-ts": "^1.6.1",
|
35
35
|
"viem": "^2.27.3",
|
36
36
|
"zod": "^3.25.62",
|
37
|
-
"@talismn/chain-connector": "0.0.0-pr2075-
|
38
|
-
"@talismn/
|
39
|
-
"@talismn/
|
40
|
-
"@talismn/sapi": "0.0.0-pr2075-
|
41
|
-
"@talismn/token-rates": "0.0.0-pr2075-
|
42
|
-
"@talismn/util": "0.0.0-pr2075-
|
43
|
-
"@talismn/scale": "0.0.0-pr2075-
|
37
|
+
"@talismn/chain-connector": "0.0.0-pr2075-20250710124714",
|
38
|
+
"@talismn/chaindata-provider": "0.0.0-pr2075-20250710124714",
|
39
|
+
"@talismn/chain-connector-evm": "0.0.0-pr2075-20250710124714",
|
40
|
+
"@talismn/sapi": "0.0.0-pr2075-20250710124714",
|
41
|
+
"@talismn/token-rates": "0.0.0-pr2075-20250710124714",
|
42
|
+
"@talismn/util": "0.0.0-pr2075-20250710124714",
|
43
|
+
"@talismn/scale": "0.0.0-pr2075-20250710124714"
|
44
44
|
},
|
45
45
|
"devDependencies": {
|
46
46
|
"@polkadot/api-contract": "16.1.2",
|
@@ -55,8 +55,8 @@
|
|
55
55
|
"jest": "^29.7.0",
|
56
56
|
"ts-jest": "^29.2.5",
|
57
57
|
"typescript": "^5.6.3",
|
58
|
-
"@talismn/
|
59
|
-
"@talismn/
|
58
|
+
"@talismn/tsconfig": "0.0.2",
|
59
|
+
"@talismn/eslint-config": "0.0.3"
|
60
60
|
},
|
61
61
|
"peerDependencies": {
|
62
62
|
"@polkadot/api-contract": "*",
|