@talismn/balances 0.0.0-pr2043-20250619170346 → 0.0.0-pr2043-20250620074243
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/BalanceModule.d.ts +14 -7
- package/dist/declarations/src/modules/EvmErc20Module.d.ts +18 -11
- package/dist/declarations/src/modules/EvmNativeModule.d.ts +17 -4
- package/dist/declarations/src/modules/EvmUniswapV2Module.d.ts +26 -17
- package/dist/declarations/src/modules/SubstrateAssetsModule.d.ts +19 -8
- package/dist/declarations/src/modules/SubstrateForeignAssetsModule.d.ts +19 -8
- package/dist/declarations/src/modules/SubstrateNativeModule/index.d.ts +14 -1
- package/dist/declarations/src/modules/SubstrateNativeModule/types.d.ts +2 -4
- package/dist/declarations/src/modules/SubstratePsp22Module.d.ts +19 -11
- package/dist/declarations/src/modules/SubstrateTokensModule.d.ts +18 -11
- package/dist/declarations/src/modules/index.d.ts +110 -8
- package/dist/declarations/src/modules/util/InferBalanceModuleTypes.d.ts +5 -3
- package/dist/declarations/src/types/balances.d.ts +18 -2
- package/dist/declarations/src/types/tokens.d.ts +11 -0
- package/dist/talismn-balances.cjs.dev.js +239 -339
- package/dist/talismn-balances.cjs.prod.js +239 -339
- package/dist/talismn-balances.esm.js +236 -343
- package/package.json +7 -7
- package/dist/declarations/src/modules/SubstrateNativeModule/subscribeCrowdloans.d.ts +0 -5
- package/dist/declarations/src/modules/SubstrateNativeModule/util/crowdloanFundContributionsChildKey.d.ts +0 -4
@@ -1,11 +1,11 @@
|
|
1
1
|
import { Dexie } from 'dexie';
|
2
2
|
import anylogger from 'anylogger';
|
3
|
-
import { evmErc20TokenId, EvmErc20TokenSchema, networkIdFromTokenId,
|
3
|
+
import { evmErc20TokenId, TokenBaseSchema, EvmErc20TokenSchema, networkIdFromTokenId, EvmUniswapV2TokenSchema, evmUniswapV2TokenId, getGithubTokenLogoUrl, DotNetworkBalancesConfigSchema, SubAssetsTokenSchema, parseSubAssetTokenId, subAssetTokenId, SubForeignAssetsTokenSchema, parseSubForeignAssetTokenId, subForeignAssetTokenId, parseTokenId, subNativeTokenId, SubPsp22TokenSchema, subPsp22TokenId, SubTokensTokenSchema, parseSubTokensTokenId, subTokensTokenId } from '@talismn/chaindata-provider';
|
4
4
|
import { newTokenRates } from '@talismn/token-rates';
|
5
|
-
import { isBigInt, BigMath, planckToTokens, isArrayOf, isTruthy, isEthereumAddress, hasOwnProperty, isAbortError,
|
5
|
+
import { isBigInt, BigMath, planckToTokens, isArrayOf, isTruthy, isEthereumAddress, hasOwnProperty, isAbortError, isNotNil, decodeAnyAddress, blake2Concat, Deferred } from '@talismn/util';
|
6
6
|
import BigNumber from 'bignumber.js';
|
7
|
-
import { u8aToHex, assert, stringCamelCase, u8aConcatStrict,
|
8
|
-
import { xxhashAsU8a
|
7
|
+
import { u8aToHex, assert, stringCamelCase, u8aConcatStrict, arrayChunk, u8aToString, hexToNumber, hexToU8a } from '@polkadot/util';
|
8
|
+
import { xxhashAsU8a } from '@polkadot/util-crypto';
|
9
9
|
import pako from 'pako';
|
10
10
|
import { parseAbi, isHex, hexToBigInt } from 'viem';
|
11
11
|
import { fromPairs, toPairs, keys, groupBy as groupBy$1 } from 'lodash';
|
@@ -14,17 +14,16 @@ import { defineMethod } from '@substrate/txwrapper-core';
|
|
14
14
|
import { unifyMetadata, decAnyMetadata, getDynamicBuilder, getLookupFn, compactMetadata, encodeMetadata, decodeScale, papiParse, getMetadataVersion, encodeStateKey } from '@talismn/scale';
|
15
15
|
import camelCase from 'lodash/camelCase';
|
16
16
|
import PQueue from 'p-queue';
|
17
|
+
import z from 'zod/v4';
|
17
18
|
import { fetchBestMetadata, getScaleApi } from '@talismn/sapi';
|
18
19
|
import { Metadata, TypeRegistry } from '@polkadot/types';
|
19
20
|
import groupBy from 'lodash/groupBy';
|
20
21
|
import { mergeUint8, toHex } from '@polkadot-api/utils';
|
21
22
|
import { Binary, AccountId } from 'polkadot-api';
|
22
|
-
import PromisePool from '@supercharge/promise-pool';
|
23
23
|
import { ChainConnectionError } from '@talismn/chain-connector';
|
24
24
|
import { Observable, scan, share, map, switchAll, combineLatest, from, mergeMap, toArray, interval, startWith, exhaustMap, BehaviorSubject, debounceTime, takeUntil, distinctUntilChanged, switchMap, withLatestFrom, concatMap } from 'rxjs';
|
25
|
-
import { u32,
|
25
|
+
import { u32, Struct, u128 } from 'scale-ts';
|
26
26
|
import upperFirst from 'lodash/upperFirst';
|
27
|
-
import z from 'zod/v4';
|
28
27
|
import { Abi } from '@polkadot/api-contract';
|
29
28
|
|
30
29
|
// Record<string, unknown> | undefined
|
@@ -113,7 +112,7 @@ class EvmTokenFetcher {
|
|
113
112
|
|
114
113
|
var pkg = {
|
115
114
|
name: "@talismn/balances",
|
116
|
-
version: "0.0.0-pr2043-
|
115
|
+
version: "0.0.0-pr2043-20250620074243"};
|
117
116
|
|
118
117
|
var log = anylogger(pkg.name);
|
119
118
|
|
@@ -1017,6 +1016,10 @@ class TalismanBalancesDatabase extends Dexie {
|
|
1017
1016
|
}
|
1018
1017
|
const db = new TalismanBalancesDatabase();
|
1019
1018
|
|
1019
|
+
const TokenConfigBaseSchema = TokenBaseSchema.partial().omit({
|
1020
|
+
id: true
|
1021
|
+
});
|
1022
|
+
|
1020
1023
|
const erc20Abi = [{
|
1021
1024
|
constant: true,
|
1022
1025
|
inputs: [],
|
@@ -1248,6 +1251,20 @@ const erc20Abi = [{
|
|
1248
1251
|
const erc20BalancesAggregatorAbi = parseAbi(["struct AccountToken {address account; address token;}", "function balances(AccountToken[] memory accountTokens) public view returns (uint256[] memory)"]);
|
1249
1252
|
|
1250
1253
|
const moduleType$7 = "evm-erc20";
|
1254
|
+
// {
|
1255
|
+
// tokens?: Array<
|
1256
|
+
// {
|
1257
|
+
// symbol?: string
|
1258
|
+
// decimals?: number
|
1259
|
+
// name?: string
|
1260
|
+
// contractAddress?: `0x${string}`
|
1261
|
+
// } & BalancesConfigTokenParams
|
1262
|
+
// >
|
1263
|
+
// }
|
1264
|
+
|
1265
|
+
const EvmErc20TokenConfigSchema = TokenConfigBaseSchema.extend({
|
1266
|
+
contractAddress: EvmErc20TokenSchema.shape.contractAddress
|
1267
|
+
});
|
1251
1268
|
const EvmErc20Module = hydrate => {
|
1252
1269
|
const {
|
1253
1270
|
chainConnectors,
|
@@ -1293,11 +1310,11 @@ const EvmErc20Module = hydrate => {
|
|
1293
1310
|
* This method is currently executed on [a squid](https://github.com/TalismanSociety/chaindata-squid/blob/0ee02818bf5caa7362e3f3664e55ef05ec8df078/src/steps/updateEvmNetworksFromGithub.ts#L338-L343).
|
1294
1311
|
* In a future version of the balance libraries, we may build some kind of async scheduling system which will keep the list of tokens for each chain up to date without relying on a squid.
|
1295
1312
|
*/
|
1296
|
-
async fetchEvmChainTokens(chainId, _chainMeta, moduleConfig) {
|
1313
|
+
async fetchEvmChainTokens(chainId, _chainMeta, moduleConfig, tokens) {
|
1297
1314
|
//const { isTestnet } = chainMeta
|
1298
1315
|
|
1299
1316
|
const chainTokens = {};
|
1300
|
-
for (const tokenConfig of
|
1317
|
+
for (const tokenConfig of tokens ?? []) {
|
1301
1318
|
const {
|
1302
1319
|
contractAddress,
|
1303
1320
|
symbol: contractSymbol,
|
@@ -1581,6 +1598,7 @@ function groupAddressesByTokenByEvmNetwork$1(addressesByToken, tokens) {
|
|
1581
1598
|
const abiMulticall = parseAbi(["struct Call { address target; bytes callData; }", "struct Call3 { address target; bool allowFailure; bytes callData; }", "struct Call3Value { address target; bool allowFailure; uint256 value; bytes callData; }", "struct Result { bool success; bytes returnData; }", "function aggregate(Call[] calldata calls) public payable returns (uint256 blockNumber, bytes[] memory returnData)", "function aggregate3(Call3[] calldata calls) public payable returns (Result[] memory returnData)", "function aggregate3Value(Call3Value[] calldata calls) public payable returns (Result[] memory returnData)", "function blockAndAggregate(Call[] calldata calls) public payable returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData)", "function getBasefee() view returns (uint256 basefee)", "function getBlockHash(uint256 blockNumber) view returns (bytes32 blockHash)", "function getBlockNumber() view returns (uint256 blockNumber)", "function getChainId() view returns (uint256 chainid)", "function getCurrentBlockCoinbase() view returns (address coinbase)", "function getCurrentBlockDifficulty() view returns (uint256 difficulty)", "function getCurrentBlockGasLimit() view returns (uint256 gaslimit)", "function getCurrentBlockTimestamp() view returns (uint256 timestamp)", "function getEthBalance(address addr) view returns (uint256 balance)", "function getLastBlockHash() view returns (bytes32 blockHash)", "function tryAggregate(bool requireSuccess, Call[] calldata calls) public payable returns (Result[] memory returnData)", "function tryBlockAndAggregate(bool requireSuccess, Call[] calldata calls) public payable returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData)"]);
|
1582
1599
|
|
1583
1600
|
const moduleType$6 = "evm-native";
|
1601
|
+
const EvmNativeTokenConfigSchema = TokenConfigBaseSchema;
|
1584
1602
|
const EvmNativeModule = hydrate => {
|
1585
1603
|
const {
|
1586
1604
|
chainConnectors,
|
@@ -1608,29 +1626,34 @@ const EvmNativeModule = hydrate => {
|
|
1608
1626
|
* This method is currently executed on [a squid](https://github.com/TalismanSociety/chaindata-squid/blob/0ee02818bf5caa7362e3f3664e55ef05ec8df078/src/steps/updateEvmNetworksFromGithub.ts#L338-L343).
|
1609
1627
|
* In a future version of the balance libraries, we may build some kind of async scheduling system which will keep the list of tokens for each chain up to date without relying on a squid.
|
1610
1628
|
*/
|
1611
|
-
async fetchEvmChainTokens(
|
1612
|
-
|
1613
|
-
|
1614
|
-
|
1615
|
-
|
1616
|
-
const
|
1617
|
-
|
1618
|
-
|
1619
|
-
|
1620
|
-
|
1621
|
-
|
1622
|
-
|
1623
|
-
|
1624
|
-
|
1625
|
-
|
1626
|
-
|
1627
|
-
|
1628
|
-
|
1629
|
-
|
1630
|
-
|
1631
|
-
|
1632
|
-
|
1633
|
-
|
1629
|
+
async fetchEvmChainTokens() {
|
1630
|
+
// networkId, chainMeta, moduleConfig, tokens
|
1631
|
+
// TODO ? seems unneeded, this info is set on the EthNetworkConfig["nativeCurrency"] field
|
1632
|
+
return {};
|
1633
|
+
|
1634
|
+
// const symbol = moduleConfig?.symbol ?? "ETH"
|
1635
|
+
// const decimals = typeof moduleConfig?.decimals === "number" ? moduleConfig.decimals : 18
|
1636
|
+
// const name = moduleConfig?.name ?? symbol
|
1637
|
+
|
1638
|
+
// const id = evmNativeTokenId(networkId)
|
1639
|
+
// const nativeToken: EvmNativeToken = {
|
1640
|
+
// platform: "ethereum",
|
1641
|
+
// id,
|
1642
|
+
// type: "evm-native",
|
1643
|
+
// isDefault: true,
|
1644
|
+
// symbol,
|
1645
|
+
// decimals,
|
1646
|
+
// name,
|
1647
|
+
// logo: moduleConfig?.logo,
|
1648
|
+
// networkId,
|
1649
|
+
// }
|
1650
|
+
|
1651
|
+
// if (moduleConfig?.symbol) nativeToken.symbol = moduleConfig?.symbol
|
1652
|
+
// if (moduleConfig?.coingeckoId) nativeToken.coingeckoId = moduleConfig?.coingeckoId
|
1653
|
+
// if (moduleConfig?.mirrorOf) nativeToken.mirrorOf = moduleConfig?.mirrorOf
|
1654
|
+
// if (moduleConfig?.noDiscovery) nativeToken.noDiscovery = moduleConfig?.noDiscovery
|
1655
|
+
|
1656
|
+
// return { [nativeToken.id]: nativeToken }
|
1634
1657
|
},
|
1635
1658
|
async subscribeBalances({
|
1636
1659
|
addressesByToken,
|
@@ -2372,6 +2395,36 @@ const uniswapV2PairAbi = [{
|
|
2372
2395
|
}];
|
2373
2396
|
|
2374
2397
|
const moduleType$5 = "evm-uniswapv2";
|
2398
|
+
const EvmUniswapV2TokenConfigSchema = TokenConfigBaseSchema.extend({
|
2399
|
+
contractAddress: EvmUniswapV2TokenSchema.shape.contractAddress,
|
2400
|
+
// the ones below are unused and prone to error, feels better to always fetch these from chain
|
2401
|
+
symbol0: EvmUniswapV2TokenSchema.shape.symbol0.optional(),
|
2402
|
+
symbol1: EvmUniswapV2TokenSchema.shape.symbol1.optional(),
|
2403
|
+
decimals0: EvmUniswapV2TokenSchema.shape.decimals0.optional(),
|
2404
|
+
decimals1: EvmUniswapV2TokenSchema.shape.decimals1.optional(),
|
2405
|
+
tokenAddress0: EvmUniswapV2TokenSchema.shape.tokenAddress0.optional(),
|
2406
|
+
tokenAddress1: EvmUniswapV2TokenSchema.shape.tokenAddress1.optional(),
|
2407
|
+
coingeckoId0: EvmUniswapV2TokenSchema.shape.coingeckoId0.optional(),
|
2408
|
+
coingeckoId1: EvmUniswapV2TokenSchema.shape.coingeckoId1.optional()
|
2409
|
+
});
|
2410
|
+
|
2411
|
+
// {
|
2412
|
+
// pools?: Array<
|
2413
|
+
// {
|
2414
|
+
// contractAddress?: `0x${string}`
|
2415
|
+
// decimals?: number
|
2416
|
+
// symbol0?: string
|
2417
|
+
// symbol1?: string
|
2418
|
+
// decimals0?: number
|
2419
|
+
// decimals1?: number
|
2420
|
+
// tokenAddress0?: `0x${string}`
|
2421
|
+
// tokenAddress1?: `0x${string}`
|
2422
|
+
// coingeckoId0?: string
|
2423
|
+
// coingeckoId1?: string
|
2424
|
+
// } & BalancesConfigTokenParams
|
2425
|
+
// >
|
2426
|
+
// }
|
2427
|
+
|
2375
2428
|
const EvmUniswapV2Module = hydrate => {
|
2376
2429
|
const {
|
2377
2430
|
chainConnectors,
|
@@ -2387,9 +2440,9 @@ const EvmUniswapV2Module = hydrate => {
|
|
2387
2440
|
extra: null
|
2388
2441
|
};
|
2389
2442
|
},
|
2390
|
-
async fetchEvmChainTokens(chainId, _chainMeta, moduleConfig) {
|
2443
|
+
async fetchEvmChainTokens(chainId, _chainMeta, moduleConfig, pools) {
|
2391
2444
|
const tokens = {};
|
2392
|
-
for (const tokenConfig of
|
2445
|
+
for (const tokenConfig of pools ?? []) {
|
2393
2446
|
const {
|
2394
2447
|
contractAddress,
|
2395
2448
|
decimals,
|
@@ -2679,7 +2732,9 @@ const getSpecVersion = async (chainConnector, networkId) => {
|
|
2679
2732
|
const CACHE$1 = new Map();
|
2680
2733
|
const getMetadataRpc = async (chainConnector, networkId) => {
|
2681
2734
|
if (CACHE$1.has(networkId)) return CACHE$1.get(networkId);
|
2682
|
-
const pResult = fetchBestMetadata((
|
2735
|
+
const pResult = fetchBestMetadata((method, params, isCacheable) => chainConnector.send(networkId, method, params, isCacheable, {
|
2736
|
+
expectErrors: true
|
2737
|
+
}), true // allow fallback to 14 as modules dont use any v15 or v16 specifics yet
|
2683
2738
|
);
|
2684
2739
|
CACHE$1.set(networkId, pResult);
|
2685
2740
|
try {
|
@@ -2703,6 +2758,8 @@ const POOL = new PQueue({
|
|
2703
2758
|
});
|
2704
2759
|
const getMiniMetadatas = async (chainConnector, chaindataProvider, networkId, specVersion, signal) => {
|
2705
2760
|
if (CACHE.has(networkId)) return CACHE.get(networkId);
|
2761
|
+
if (!signal) log.warn("[miniMetadata] getMiniMetadatas called without signal, this may hang the updates", new Error("No signal provided") // this will show the stack trace
|
2762
|
+
);
|
2706
2763
|
const pResult = POOL.add(() => fetchMiniMetadatas(chainConnector, chaindataProvider, networkId, specVersion), {
|
2707
2764
|
signal
|
2708
2765
|
});
|
@@ -2718,9 +2775,10 @@ const getMiniMetadatas = async (chainConnector, chaindataProvider, networkId, sp
|
|
2718
2775
|
CACHE.delete(networkId);
|
2719
2776
|
}
|
2720
2777
|
};
|
2778
|
+
const DotBalanceModuleTypeSchema = z.keyof(DotNetworkBalancesConfigSchema);
|
2721
2779
|
const fetchMiniMetadatas = async (chainConnector, chaindataProvider, chainId, specVersion, signal) => {
|
2722
2780
|
const start = performance.now();
|
2723
|
-
log.
|
2781
|
+
log.info("[miniMetadata] fetching minimetadatas for %s", chainId);
|
2724
2782
|
try {
|
2725
2783
|
const metadataRpc = await getMetadataRpc(chainConnector, chainId);
|
2726
2784
|
signal?.throwIfAborted();
|
@@ -2731,10 +2789,14 @@ const fetchMiniMetadatas = async (chainConnector, chaindataProvider, chainId, sp
|
|
2731
2789
|
const modules = defaultBalanceModules.map(mod => mod({
|
2732
2790
|
chainConnectors,
|
2733
2791
|
chaindataProvider
|
2734
|
-
})).filter(mod => mod.type.
|
2792
|
+
})).filter(mod => DotBalanceModuleTypeSchema.safeParse(mod.type).success);
|
2735
2793
|
return Promise.all(modules.map(async mod => {
|
2736
2794
|
const source = mod.type;
|
2737
|
-
const
|
2795
|
+
const chain = await chaindataProvider.chainById(chainId);
|
2796
|
+
const balancesConfig = chain?.balancesConfig?.[mod.type];
|
2797
|
+
const chainMeta = await mod.fetchSubstrateChainMeta(chainId, balancesConfig,
|
2798
|
+
// TODO fix typings
|
2799
|
+
metadataRpc);
|
2738
2800
|
return {
|
2739
2801
|
id: deriveMiniMetadataId({
|
2740
2802
|
source,
|
@@ -3060,10 +3122,23 @@ const decompress = data => {
|
|
3060
3122
|
};
|
3061
3123
|
|
3062
3124
|
const moduleType$4 = "substrate-assets";
|
3125
|
+
const SubAssetsTokenConfigSchema = TokenConfigBaseSchema.extend({
|
3126
|
+
assetId: SubAssetsTokenSchema.shape.assetId,
|
3127
|
+
existentialDeposit: SubAssetsTokenSchema.shape.existentialDeposit
|
3128
|
+
});
|
3063
3129
|
const UNSUPPORTED_CHAIN_META$3 = {
|
3064
3130
|
miniMetadata: null,
|
3065
3131
|
extra: null
|
3066
3132
|
};
|
3133
|
+
|
3134
|
+
// {
|
3135
|
+
// tokens?: Array<
|
3136
|
+
// {
|
3137
|
+
// assetId: number | string
|
3138
|
+
// } & BalancesConfigTokenParams
|
3139
|
+
// >
|
3140
|
+
// }
|
3141
|
+
|
3067
3142
|
const SubAssetsModule = hydrate => {
|
3068
3143
|
const {
|
3069
3144
|
chainConnectors,
|
@@ -3087,8 +3162,8 @@ const SubAssetsModule = hydrate => {
|
|
3087
3162
|
extra: null
|
3088
3163
|
};
|
3089
3164
|
},
|
3090
|
-
async fetchSubstrateChainTokens(chainId, chainMeta, moduleConfig) {
|
3091
|
-
if (
|
3165
|
+
async fetchSubstrateChainTokens(chainId, chainMeta, moduleConfig, tokens) {
|
3166
|
+
if (!tokens?.length) return {};
|
3092
3167
|
const {
|
3093
3168
|
miniMetadata
|
3094
3169
|
} = chainMeta;
|
@@ -3097,8 +3172,8 @@ const SubAssetsModule = hydrate => {
|
|
3097
3172
|
const scaleBuilder = getDynamicBuilder(getLookupFn(metadata));
|
3098
3173
|
const assetCoder = scaleBuilder.buildStorage("Assets", "Asset");
|
3099
3174
|
const metadataCoder = scaleBuilder.buildStorage("Assets", "Metadata");
|
3100
|
-
const
|
3101
|
-
for (const tokenConfig of
|
3175
|
+
const tokenList = {};
|
3176
|
+
for (const tokenConfig of tokens ?? []) {
|
3102
3177
|
try {
|
3103
3178
|
const assetId = String(tokenConfig.assetId);
|
3104
3179
|
const assetStateKey = tryEncode(assetCoder, BigInt(assetId)) ?? tryEncode(assetCoder, assetId);
|
@@ -3130,13 +3205,13 @@ const SubAssetsModule = hydrate => {
|
|
3130
3205
|
}
|
3131
3206
|
if (tokenConfig?.coingeckoId) token.coingeckoId = tokenConfig?.coingeckoId;
|
3132
3207
|
if (tokenConfig?.mirrorOf) token.mirrorOf = tokenConfig?.mirrorOf;
|
3133
|
-
|
3208
|
+
tokenList[token.id] = token;
|
3134
3209
|
} catch (error) {
|
3135
3210
|
log.error(`Failed to build substrate-assets token ${tokenConfig.assetId} (${tokenConfig.symbol}) on ${chainId}`, error);
|
3136
3211
|
continue;
|
3137
3212
|
}
|
3138
3213
|
}
|
3139
|
-
return
|
3214
|
+
return tokenList;
|
3140
3215
|
},
|
3141
3216
|
// TODO: Don't create empty subscriptions
|
3142
3217
|
async subscribeBalances({
|
@@ -3166,10 +3241,10 @@ const SubAssetsModule = hydrate => {
|
|
3166
3241
|
}
|
3167
3242
|
}));
|
3168
3243
|
return () => {
|
3169
|
-
controller.abort();
|
3170
3244
|
pUnsubs.then(unsubs => {
|
3171
3245
|
unsubs.forEach(unsubscribe => unsubscribe());
|
3172
3246
|
});
|
3247
|
+
controller.abort();
|
3173
3248
|
};
|
3174
3249
|
},
|
3175
3250
|
async fetchBalances(addressesByToken) {
|
@@ -3353,6 +3428,19 @@ const UNSUPPORTED_CHAIN_META$2 = {
|
|
3353
3428
|
miniMetadata: null,
|
3354
3429
|
extra: null
|
3355
3430
|
};
|
3431
|
+
const SubForeignAssetsTokenConfigSchema = TokenConfigBaseSchema.extend({
|
3432
|
+
onChainId: SubForeignAssetsTokenSchema.shape.onChainId,
|
3433
|
+
existentialDeposit: SubForeignAssetsTokenSchema.shape.existentialDeposit
|
3434
|
+
});
|
3435
|
+
|
3436
|
+
// {
|
3437
|
+
// tokens?: Array<
|
3438
|
+
// {
|
3439
|
+
// onChainId: string
|
3440
|
+
// } & BalancesConfigTokenParams
|
3441
|
+
// >
|
3442
|
+
// }
|
3443
|
+
|
3356
3444
|
const SubForeignAssetsModule = hydrate => {
|
3357
3445
|
const {
|
3358
3446
|
chainConnectors,
|
@@ -3377,8 +3465,8 @@ const SubForeignAssetsModule = hydrate => {
|
|
3377
3465
|
extra: null
|
3378
3466
|
};
|
3379
3467
|
},
|
3380
|
-
async fetchSubstrateChainTokens(chainId, chainMeta, moduleConfig) {
|
3381
|
-
if (
|
3468
|
+
async fetchSubstrateChainTokens(chainId, chainMeta, moduleConfig, tokens) {
|
3469
|
+
if (!tokens?.length) return {};
|
3382
3470
|
const {
|
3383
3471
|
miniMetadata
|
3384
3472
|
} = chainMeta;
|
@@ -3388,8 +3476,8 @@ const SubForeignAssetsModule = hydrate => {
|
|
3388
3476
|
const scaleBuilder = getDynamicBuilder(getLookupFn(unifiedMetadata));
|
3389
3477
|
const assetCoder = scaleBuilder.buildStorage("ForeignAssets", "Asset");
|
3390
3478
|
const metadataCoder = scaleBuilder.buildStorage("ForeignAssets", "Metadata");
|
3391
|
-
const
|
3392
|
-
for (const tokenConfig of
|
3479
|
+
const tokenList = {};
|
3480
|
+
for (const tokenConfig of tokens ?? []) {
|
3393
3481
|
try {
|
3394
3482
|
const onChainId = (() => {
|
3395
3483
|
try {
|
@@ -3424,13 +3512,13 @@ const SubForeignAssetsModule = hydrate => {
|
|
3424
3512
|
};
|
3425
3513
|
if (tokenConfig?.coingeckoId) token.coingeckoId = tokenConfig?.coingeckoId;
|
3426
3514
|
if (tokenConfig?.mirrorOf) token.mirrorOf = tokenConfig?.mirrorOf;
|
3427
|
-
|
3515
|
+
tokenList[token.id] = token;
|
3428
3516
|
} catch (error) {
|
3429
3517
|
log.error(`Failed to build substrate-foreignassets token ${tokenConfig.onChainId} (${tokenConfig.symbol}) on ${chainId}`, error?.message ?? error);
|
3430
3518
|
continue;
|
3431
3519
|
}
|
3432
3520
|
}
|
3433
|
-
return
|
3521
|
+
return tokenList;
|
3434
3522
|
},
|
3435
3523
|
// TODO: Don't create empty subscriptions
|
3436
3524
|
async subscribeBalances({
|
@@ -3459,10 +3547,10 @@ const SubForeignAssetsModule = hydrate => {
|
|
3459
3547
|
}
|
3460
3548
|
}));
|
3461
3549
|
return () => {
|
3462
|
-
controller.abort();
|
3463
3550
|
pUnsubs.then(unsubs => {
|
3464
3551
|
unsubs.forEach(unsubscribe => unsubscribe());
|
3465
3552
|
});
|
3553
|
+
controller.abort();
|
3466
3554
|
};
|
3467
3555
|
},
|
3468
3556
|
async fetchBalances(addressesByToken) {
|
@@ -3649,263 +3737,6 @@ const asObservable = handler => (...args) => new Observable(subscriber => {
|
|
3649
3737
|
return unsubscribe;
|
3650
3738
|
});
|
3651
3739
|
|
3652
|
-
/**
|
3653
|
-
* Crowdloan contributions are stored in the `childstate` key returned by this function.
|
3654
|
-
*/
|
3655
|
-
const crowdloanFundContributionsChildKey = fundIndex => u8aToHex(u8aConcat(":child_storage:default:", blake2AsU8a(u8aConcat("crowdloan", u32.enc(fundIndex)))));
|
3656
|
-
|
3657
|
-
// TODO make this method chain-specific
|
3658
|
-
async function subscribeCrowdloans(chaindataProvider, chainConnector, addressesByToken, callback, signal) {
|
3659
|
-
const allChains = await chaindataProvider.chainsById();
|
3660
|
-
const tokens = await chaindataProvider.tokensById();
|
3661
|
-
|
3662
|
-
// there should be only one network here when subscribing to balances, we've split it up by network at the top level
|
3663
|
-
const networkIds = keys(addressesByToken).map(tokenId => parseTokenId(tokenId).networkId);
|
3664
|
-
const miniMetadatas = new Map();
|
3665
|
-
for (const networkId of networkIds) miniMetadatas.set(networkId, await getMiniMetadata(chaindataProvider, chainConnector, networkId, "substrate-native"));
|
3666
|
-
const crowdloanTokenIds = Object.entries(tokens).filter(([, token]) => {
|
3667
|
-
// ignore non-native tokens
|
3668
|
-
if (token.type !== "substrate-native") return;
|
3669
|
-
// ignore tokens on chains with no crowdloans pallet
|
3670
|
-
const miniMetadata = miniMetadatas.get(token.networkId);
|
3671
|
-
return typeof miniMetadata?.extra?.crowdloanPalletId === "string";
|
3672
|
-
}).map(([tokenId]) => tokenId);
|
3673
|
-
|
3674
|
-
// crowdloan contributions can only be done by the native token on chains with the crowdloan pallet
|
3675
|
-
const addressesByCrowdloanToken = Object.fromEntries(Object.entries(addressesByToken)
|
3676
|
-
// remove ethereum addresses
|
3677
|
-
.map(([tokenId, addresses]) => [tokenId, addresses.filter(address => !isEthereumAddress(address))])
|
3678
|
-
// remove tokens which aren't crowdloan tokens
|
3679
|
-
.filter(([tokenId]) => crowdloanTokenIds.includes(tokenId)));
|
3680
|
-
const uniqueChainIds = getUniqueChainIds(addressesByCrowdloanToken, tokens);
|
3681
|
-
const chains = Object.fromEntries(Object.entries(allChains).filter(([chainId]) => uniqueChainIds.includes(chainId)));
|
3682
|
-
const chainStorageCoders = buildStorageCoders({
|
3683
|
-
chainIds: uniqueChainIds,
|
3684
|
-
chains,
|
3685
|
-
miniMetadatas,
|
3686
|
-
coders: {
|
3687
|
-
parachains: ["Paras", "Parachains"],
|
3688
|
-
funds: ["Crowdloan", "Funds"]
|
3689
|
-
}
|
3690
|
-
});
|
3691
|
-
const tokenSubscriptions = [];
|
3692
|
-
for (const [tokenId, addresses] of Object.entries(addressesByCrowdloanToken)) {
|
3693
|
-
const token = tokens[tokenId];
|
3694
|
-
if (!token) {
|
3695
|
-
log.warn(`Token ${tokenId} not found`);
|
3696
|
-
continue;
|
3697
|
-
}
|
3698
|
-
if (token.type !== "substrate-native") {
|
3699
|
-
log.debug(`This module doesn't handle tokens of type ${token.type}`);
|
3700
|
-
continue;
|
3701
|
-
}
|
3702
|
-
const chainId = token.networkId;
|
3703
|
-
if (!chainId) {
|
3704
|
-
log.warn(`Token ${tokenId} has no chain`);
|
3705
|
-
continue;
|
3706
|
-
}
|
3707
|
-
const chain = chains[chainId];
|
3708
|
-
if (!chain) {
|
3709
|
-
log.warn(`Chain ${chainId} for token ${tokenId} not found`);
|
3710
|
-
continue;
|
3711
|
-
}
|
3712
|
-
const subscribeParaIds = callback => {
|
3713
|
-
const scaleCoder = chainStorageCoders.get(chainId)?.parachains;
|
3714
|
-
const queries = [0].flatMap(() => {
|
3715
|
-
const stateKey = encodeStateKey(scaleCoder);
|
3716
|
-
if (!stateKey) return [];
|
3717
|
-
const decodeResult = change => {
|
3718
|
-
/** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
|
3719
|
-
|
3720
|
-
const decoded = decodeScale(scaleCoder, change, `Failed to decode parachains on chain ${chainId}`);
|
3721
|
-
const paraIds = decoded ?? [];
|
3722
|
-
return paraIds;
|
3723
|
-
};
|
3724
|
-
return {
|
3725
|
-
chainId,
|
3726
|
-
stateKey,
|
3727
|
-
decodeResult
|
3728
|
-
};
|
3729
|
-
});
|
3730
|
-
const subscription = new RpcStateQueryHelper(chainConnector, queries).subscribe(callback);
|
3731
|
-
return () => subscription.then(unsubscribe => unsubscribe());
|
3732
|
-
};
|
3733
|
-
const subscribeParaFundIndexes = (paraIds, callback) => {
|
3734
|
-
const scaleCoder = chainStorageCoders.get(chainId)?.funds;
|
3735
|
-
const queries = paraIds.flatMap(paraId => {
|
3736
|
-
const stateKey = encodeStateKey(scaleCoder, `Invalid paraId in ${chainId} funds query ${paraId}`, paraId);
|
3737
|
-
if (!stateKey) return [];
|
3738
|
-
const decodeResult = change => {
|
3739
|
-
/** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
|
3740
|
-
|
3741
|
-
const decoded = decodeScale(scaleCoder, change, `Failed to decode paras on chain ${chainId}`);
|
3742
|
-
const firstPeriod = decoded?.first_period?.toString?.() ?? "";
|
3743
|
-
const lastPeriod = decoded?.last_period?.toString?.() ?? "";
|
3744
|
-
const fundPeriod = `${firstPeriod}-${lastPeriod}`;
|
3745
|
-
const fundIndex = decoded?.fund_index ?? decoded?.trie_index;
|
3746
|
-
return {
|
3747
|
-
paraId,
|
3748
|
-
fundPeriod,
|
3749
|
-
fundIndex
|
3750
|
-
};
|
3751
|
-
};
|
3752
|
-
return {
|
3753
|
-
chainId,
|
3754
|
-
stateKey,
|
3755
|
-
decodeResult
|
3756
|
-
};
|
3757
|
-
});
|
3758
|
-
const subscription = new RpcStateQueryHelper(chainConnector, queries).subscribe(callback);
|
3759
|
-
return () => subscription.then(unsubscribe => unsubscribe());
|
3760
|
-
};
|
3761
|
-
const subscribeFundContributions = (funds, addresses, callback) => {
|
3762
|
-
// TODO: Watch system_events in order to subscribe to changes, then redo the contributions query when changes are detected:
|
3763
|
-
// https://github.com/polkadot-js/api/blob/8fe02a14345b57e6abb8f7f2c2b624cf70c51b23/packages/api-derive/src/crowdloan/ownContributions.ts#L32-L47
|
3764
|
-
//
|
3765
|
-
// For now we just re-fetch all contributions on a timer and then only send them to the subscription callback when they have changed
|
3766
|
-
|
3767
|
-
const queries = funds.map(({
|
3768
|
-
paraId,
|
3769
|
-
fundIndex
|
3770
|
-
}) => ({
|
3771
|
-
paraId,
|
3772
|
-
fundIndex,
|
3773
|
-
addresses,
|
3774
|
-
childKey: crowdloanFundContributionsChildKey(fundIndex),
|
3775
|
-
storageKeys: addresses.map(address => u8aToHex(decodeAnyAddress(address)))
|
3776
|
-
}));
|
3777
|
-
|
3778
|
-
// track whether our caller is still subscribed
|
3779
|
-
let subscriptionActive = true;
|
3780
|
-
let previousContributions = null;
|
3781
|
-
const fetchContributions = async () => {
|
3782
|
-
try {
|
3783
|
-
const results = await Promise.all(queries.map(async ({
|
3784
|
-
paraId,
|
3785
|
-
fundIndex,
|
3786
|
-
addresses,
|
3787
|
-
childKey,
|
3788
|
-
storageKeys
|
3789
|
-
}) => ({
|
3790
|
-
paraId,
|
3791
|
-
fundIndex,
|
3792
|
-
addresses,
|
3793
|
-
result: await chainConnector.send(chainId, "childstate_getStorageEntries", [childKey, storageKeys])
|
3794
|
-
})));
|
3795
|
-
const contributions = results.flatMap(queryResult => {
|
3796
|
-
const {
|
3797
|
-
paraId,
|
3798
|
-
fundIndex,
|
3799
|
-
addresses,
|
3800
|
-
result
|
3801
|
-
} = queryResult;
|
3802
|
-
return (Array.isArray(result) ? result : []).flatMap((encoded, index) => {
|
3803
|
-
const amount = (() => {
|
3804
|
-
try {
|
3805
|
-
return typeof encoded === "string" ? u128.dec(encoded) ?? 0n : 0n;
|
3806
|
-
} catch {
|
3807
|
-
return 0n;
|
3808
|
-
}
|
3809
|
-
})().toString();
|
3810
|
-
return {
|
3811
|
-
paraId,
|
3812
|
-
fundIndex,
|
3813
|
-
address: addresses[index],
|
3814
|
-
amount
|
3815
|
-
};
|
3816
|
-
});
|
3817
|
-
});
|
3818
|
-
|
3819
|
-
// ignore these results if our caller has tried to close this subscription
|
3820
|
-
if (!subscriptionActive) return;
|
3821
|
-
|
3822
|
-
// ignore these results if they're the same as what we previously fetched
|
3823
|
-
if (isEqual(previousContributions, contributions)) return;
|
3824
|
-
previousContributions = contributions;
|
3825
|
-
callback(null, contributions);
|
3826
|
-
} catch (error) {
|
3827
|
-
callback(error);
|
3828
|
-
}
|
3829
|
-
};
|
3830
|
-
|
3831
|
-
// set up polling for contributions
|
3832
|
-
const crowdloanContributionsPollInterval = 60_000; // 60_000ms === 1 minute
|
3833
|
-
const pollContributions = async () => {
|
3834
|
-
if (!subscriptionActive) return;
|
3835
|
-
try {
|
3836
|
-
await fetchContributions();
|
3837
|
-
} catch (error) {
|
3838
|
-
// log any errors, but don't cancel the poll for contributions when one fetch fails
|
3839
|
-
log.error(error);
|
3840
|
-
}
|
3841
|
-
if (!subscriptionActive) return;
|
3842
|
-
setTimeout(pollContributions, crowdloanContributionsPollInterval);
|
3843
|
-
};
|
3844
|
-
|
3845
|
-
// start polling
|
3846
|
-
pollContributions();
|
3847
|
-
return () => {
|
3848
|
-
// stop polling
|
3849
|
-
subscriptionActive = false;
|
3850
|
-
};
|
3851
|
-
};
|
3852
|
-
const paraIds$ = asObservable(subscribeParaIds)().pipe(scan((_, next) => Array.from(new Set(next.flatMap(paraIds => paraIds))), []), share());
|
3853
|
-
const fundIndexesByParaId$ = paraIds$.pipe(map(paraIds => asObservable(subscribeParaFundIndexes)(paraIds)), switchAll(), scan((state, next) => {
|
3854
|
-
for (const fund of next) {
|
3855
|
-
const {
|
3856
|
-
paraId,
|
3857
|
-
fundIndex
|
3858
|
-
} = fund;
|
3859
|
-
if (typeof fundIndex === "number") {
|
3860
|
-
state.set(paraId, (state.get(paraId) ?? new Set()).add(fundIndex));
|
3861
|
-
}
|
3862
|
-
}
|
3863
|
-
return state;
|
3864
|
-
}, new Map()));
|
3865
|
-
const contributionsByAddress$ = fundIndexesByParaId$.pipe(map(fundIndexesByParaId => Array.from(fundIndexesByParaId).flatMap(([paraId, fundIndexes]) => Array.from(fundIndexes).map(fundIndex => ({
|
3866
|
-
paraId,
|
3867
|
-
fundIndex
|
3868
|
-
})))), map(funds => asObservable(subscribeFundContributions)(funds, addresses)), switchAll(), scan((state, next) => {
|
3869
|
-
for (const contribution of next) {
|
3870
|
-
const {
|
3871
|
-
address
|
3872
|
-
} = contribution;
|
3873
|
-
state.set(address, (state.get(address) ?? new Set()).add(contribution));
|
3874
|
-
}
|
3875
|
-
return state;
|
3876
|
-
}, new Map()));
|
3877
|
-
const subscription = contributionsByAddress$.subscribe({
|
3878
|
-
next: contributionsByAddress => {
|
3879
|
-
const balances = Array.from(contributionsByAddress).map(([address, contributions]) => {
|
3880
|
-
return {
|
3881
|
-
source: "substrate-native",
|
3882
|
-
status: "live",
|
3883
|
-
address,
|
3884
|
-
networkId: chainId,
|
3885
|
-
tokenId,
|
3886
|
-
values: Array.from(contributions).map(({
|
3887
|
-
amount,
|
3888
|
-
paraId
|
3889
|
-
}) => ({
|
3890
|
-
type: "crowdloan",
|
3891
|
-
label: "crowdloan",
|
3892
|
-
source: "crowdloan",
|
3893
|
-
amount: amount,
|
3894
|
-
meta: {
|
3895
|
-
paraId
|
3896
|
-
}
|
3897
|
-
}))
|
3898
|
-
};
|
3899
|
-
});
|
3900
|
-
if (balances.length > 0) callback(null, balances);
|
3901
|
-
},
|
3902
|
-
error: error => callback(error)
|
3903
|
-
});
|
3904
|
-
tokenSubscriptions.push(() => subscription.unsubscribe());
|
3905
|
-
}
|
3906
|
-
return () => tokenSubscriptions.forEach(unsub => unsub());
|
3907
|
-
}
|
3908
|
-
|
3909
3740
|
/**
|
3910
3741
|
* Each nominationPool in the nominationPools pallet has access to some accountIds which have no
|
3911
3742
|
* associated private key. Instead, they are derived from this function.
|
@@ -3937,6 +3768,7 @@ async function subscribeNompoolStaking(chaindataProvider, chainConnector, addres
|
|
3937
3768
|
const miniMetadata = await getMiniMetadata(chaindataProvider, chainConnector, networkId, "substrate-native");
|
3938
3769
|
miniMetadatas.set(networkId, miniMetadata);
|
3939
3770
|
}
|
3771
|
+
signal?.throwIfAborted();
|
3940
3772
|
const nomPoolTokenIds = Object.entries(tokens).filter(([, token]) => {
|
3941
3773
|
// ignore non-native tokens
|
3942
3774
|
if (token.type !== "substrate-native") return false;
|
@@ -4254,9 +4086,10 @@ async function subscribeSubtensorStaking(chaindataProvider, chainConnector, addr
|
|
4254
4086
|
const networkIds = keys(addressesByToken).map(tokenId => parseTokenId(tokenId).networkId);
|
4255
4087
|
const miniMetadatas = new Map();
|
4256
4088
|
for (const networkId of networkIds) {
|
4257
|
-
const miniMetadata = await getMiniMetadata(chaindataProvider, chainConnector, networkId, "substrate-native");
|
4089
|
+
const miniMetadata = await getMiniMetadata(chaindataProvider, chainConnector, networkId, "substrate-native", signal);
|
4258
4090
|
miniMetadatas.set(networkId, miniMetadata);
|
4259
4091
|
}
|
4092
|
+
signal?.throwIfAborted();
|
4260
4093
|
const subtensorTokenIds = Object.entries(tokens).filter(([, token]) => {
|
4261
4094
|
// ignore non-native tokens
|
4262
4095
|
if (token.type !== "substrate-native") return false;
|
@@ -4462,7 +4295,9 @@ async function subscribeSubtensorStaking(chaindataProvider, chainConnector, addr
|
|
4462
4295
|
});
|
4463
4296
|
|
4464
4297
|
// use the abortController to tear the subscription down when we don't need it anymore
|
4465
|
-
abortController.signal.
|
4298
|
+
abortController.signal.addEventListener("abort", () => {
|
4299
|
+
subscription.unsubscribe();
|
4300
|
+
});
|
4466
4301
|
}
|
4467
4302
|
return () => abortController.abort();
|
4468
4303
|
}
|
@@ -4548,6 +4383,10 @@ const getLockTitle = (lock, {
|
|
4548
4383
|
|
4549
4384
|
const moduleType$2 = "substrate-native";
|
4550
4385
|
|
4386
|
+
// {
|
4387
|
+
// disable?: boolean
|
4388
|
+
// } & BalancesConfigTokenParams
|
4389
|
+
|
4551
4390
|
/**
|
4552
4391
|
* Function to merge two 'sub sources' of the same balance together, or
|
4553
4392
|
* two instances of the same balance with different values.
|
@@ -5025,6 +4864,7 @@ const UNSUPPORTED_CHAIN_META$1 = {
|
|
5025
4864
|
miniMetadata: null,
|
5026
4865
|
extra: null
|
5027
4866
|
};
|
4867
|
+
const SubNativeTokenConfigSchema = TokenConfigBaseSchema;
|
5028
4868
|
const SubNativeModule = hydrate => {
|
5029
4869
|
const {
|
5030
4870
|
chainConnectors,
|
@@ -5040,7 +4880,7 @@ const SubNativeModule = hydrate => {
|
|
5040
4880
|
// subscribeBalances was split by network to prevent all subs to wait for all minimetadatas to be ready.
|
5041
4881
|
// however the multichain logic in there is so deep in the function below that i had to keep it as-is, and call it by per-network chunks
|
5042
4882
|
// TODO refactor this be actually network specific
|
5043
|
-
const subscribeChainBalances =
|
4883
|
+
const subscribeChainBalances = (chainId, opts, callback, signal) => {
|
5044
4884
|
const {
|
5045
4885
|
addressesByToken,
|
5046
4886
|
initialBalances
|
@@ -5139,13 +4979,19 @@ const SubNativeModule = hydrate => {
|
|
5139
4979
|
return from(queryCache.getQueries(newAddressesByToken)).pipe(switchMap(baseQueries => {
|
5140
4980
|
return new Observable(subscriber => {
|
5141
4981
|
if (!chainConnectors.substrate) return;
|
5142
|
-
const unsubSubtensorStaking = subscribeSubtensorStaking(chaindataProvider, chainConnectors.substrate, newAddressesByToken, handleUpdateForSource("subtensor-staking"));
|
5143
|
-
const unsubNompoolStaking = subscribeNompoolStaking(chaindataProvider, chainConnectors.substrate, newAddressesByToken, handleUpdateForSource("nompools-staking"));
|
5144
|
-
const unsubCrowdloans = subscribeCrowdloans(
|
4982
|
+
const unsubSubtensorStaking = subscribeSubtensorStaking(chaindataProvider, chainConnectors.substrate, newAddressesByToken, handleUpdateForSource("subtensor-staking"), signal);
|
4983
|
+
const unsubNompoolStaking = subscribeNompoolStaking(chaindataProvider, chainConnectors.substrate, newAddressesByToken, handleUpdateForSource("nompools-staking"), signal);
|
4984
|
+
// const unsubCrowdloans = subscribeCrowdloans(
|
4985
|
+
// chaindataProvider,
|
4986
|
+
// chainConnectors.substrate,
|
4987
|
+
// newAddressesByToken,
|
4988
|
+
// handleUpdateForSource("crowdloan"),
|
4989
|
+
// signal,
|
4990
|
+
// )
|
5145
4991
|
const unsubBase = subscribeBase(baseQueries, chainConnectors.substrate, handleUpdateForSource("base"));
|
5146
4992
|
subscriber.add(async () => (await unsubSubtensorStaking)());
|
5147
4993
|
subscriber.add(async () => (await unsubNompoolStaking)());
|
5148
|
-
subscriber.add(async () => (await unsubCrowdloans)())
|
4994
|
+
// subscriber.add(async () => (await unsubCrowdloans)())
|
5149
4995
|
subscriber.add(async () => (await unsubBase)());
|
5150
4996
|
});
|
5151
4997
|
}));
|
@@ -5177,8 +5023,13 @@ const SubNativeModule = hydrate => {
|
|
5177
5023
|
const nonCurrentTokens = Object.keys(addressesByToken).filter(tokenId => !currentTokens.has(tokenId)).sort(sortChains);
|
5178
5024
|
|
5179
5025
|
// break nonCurrentTokens into chunks of POLLING_WINDOW_SIZE
|
5180
|
-
|
5026
|
+
const pool = new PQueue({
|
5027
|
+
concurrency: POLLING_WINDOW_SIZE
|
5028
|
+
});
|
5029
|
+
nonCurrentTokens.forEach(nonCurrentTokenId => pool.add(() => poll({
|
5181
5030
|
[nonCurrentTokenId]: addressesByToken[nonCurrentTokenId]
|
5031
|
+
}), {
|
5032
|
+
signal
|
5182
5033
|
}));
|
5183
5034
|
|
5184
5035
|
// now poll every 30s on chains which are not subscriptionTokens
|
@@ -5191,7 +5042,9 @@ const SubNativeModule = hydrate => {
|
|
5191
5042
|
Object.keys(addressesByToken).filter(tokenId => !subscribedTokenIds.includes(tokenId))), exhaustMap(tokenIds => from(arrayChunk(tokenIds, POLLING_WINDOW_SIZE)).pipe(concatMap(async tokenChunk => {
|
5192
5043
|
// tokenChunk is a chunk of tokenIds with size POLLING_WINDOW_SIZE
|
5193
5044
|
const pollingTokenAddresses = Object.fromEntries(tokenChunk.map(tokenId => [tokenId, addressesByToken[tokenId]]));
|
5194
|
-
await poll(pollingTokenAddresses)
|
5045
|
+
await pool.add(() => poll(pollingTokenAddresses), {
|
5046
|
+
signal
|
5047
|
+
});
|
5195
5048
|
return true;
|
5196
5049
|
})))).subscribe();
|
5197
5050
|
return () => {
|
@@ -5236,7 +5089,7 @@ const SubNativeModule = hydrate => {
|
|
5236
5089
|
};
|
5237
5090
|
const existentialDeposit = getConstantValue("Balances", "ExistentialDeposit")?.toString();
|
5238
5091
|
const nominationPoolsPalletId = getConstantValue("NominationPools", "PalletId")?.asText();
|
5239
|
-
const crowdloanPalletId = getConstantValue("Crowdloan", "PalletId")?.asText();
|
5092
|
+
const crowdloanPalletId = getConstantValue("Crowdloan", "PalletId")?.asText(); // TODO yeet
|
5240
5093
|
const hasSubtensorPallet = getConstantValue("SubtensorModule", "KeySwapCost") !== undefined;
|
5241
5094
|
|
5242
5095
|
//
|
@@ -5259,10 +5112,13 @@ const SubNativeModule = hydrate => {
|
|
5259
5112
|
}, {
|
5260
5113
|
pallet: "Crowdloan",
|
5261
5114
|
items: ["Funds"]
|
5262
|
-
},
|
5115
|
+
},
|
5116
|
+
// TODO yeet
|
5117
|
+
{
|
5263
5118
|
pallet: "Paras",
|
5264
5119
|
items: ["Parachains"]
|
5265
5120
|
},
|
5121
|
+
// TODO yeet
|
5266
5122
|
// TotalColdkeyStake is used until v.2.2.1, then it is replaced by StakingHotkeys+Stake
|
5267
5123
|
// Need to keep TotalColdkeyStake for a while so chaindata keeps including it in miniMetadatas, so it doesnt break old versions of the wallet
|
5268
5124
|
{
|
@@ -5305,22 +5161,24 @@ const SubNativeModule = hydrate => {
|
|
5305
5161
|
const {
|
5306
5162
|
existentialDeposit
|
5307
5163
|
} = chainMeta.extra ?? {};
|
5164
|
+
if (existentialDeposit === undefined) log.warn("Substrate native module: existentialDeposit is undefined for %s, using 0", chainId);
|
5308
5165
|
const id = subNativeTokenId(chainId);
|
5309
5166
|
const nativeToken = {
|
5310
5167
|
id,
|
5311
5168
|
type: "substrate-native",
|
5312
5169
|
platform: "polkadot",
|
5313
|
-
isDefault:
|
5170
|
+
isDefault: true,
|
5314
5171
|
symbol: symbol,
|
5315
|
-
name:
|
5172
|
+
name: symbol,
|
5316
5173
|
decimals: decimals,
|
5317
|
-
logo: moduleConfig?.logo,
|
5318
5174
|
existentialDeposit: existentialDeposit ?? "0",
|
5319
5175
|
networkId: chainId
|
5320
5176
|
};
|
5321
|
-
|
5322
|
-
if (moduleConfig?.
|
5323
|
-
if (moduleConfig?.
|
5177
|
+
|
5178
|
+
// if (moduleConfig?.symbol) nativeToken.symbol = moduleConfig?.symbol
|
5179
|
+
// if (moduleConfig?.coingeckoId) nativeToken.coingeckoId = moduleConfig?.coingeckoId
|
5180
|
+
// if (moduleConfig?.mirrorOf) nativeToken.mirrorOf = moduleConfig?.mirrorOf
|
5181
|
+
|
5324
5182
|
return {
|
5325
5183
|
[nativeToken.id]: nativeToken
|
5326
5184
|
};
|
@@ -5352,11 +5210,11 @@ const SubNativeModule = hydrate => {
|
|
5352
5210
|
return subscribeChainBalances(networkId, {
|
5353
5211
|
addressesByToken: addressesByTokenByNetwork[networkId] ?? {},
|
5354
5212
|
initialBalances: initialBalancesByNetwork[networkId] ?? []
|
5355
|
-
}, safeCallback);
|
5213
|
+
}, safeCallback, controller.signal);
|
5356
5214
|
}));
|
5357
5215
|
return () => {
|
5358
|
-
controller.abort();
|
5359
5216
|
unsubsribeFns.then(fns => fns.forEach(unsubscribe => unsubscribe()));
|
5217
|
+
controller.abort();
|
5360
5218
|
};
|
5361
5219
|
},
|
5362
5220
|
fetchBalances,
|
@@ -6574,6 +6432,22 @@ var psp22Abi = {
|
|
6574
6432
|
};
|
6575
6433
|
|
6576
6434
|
const moduleType$1 = "substrate-psp22";
|
6435
|
+
const SubPsp22TokenConfigSchema = TokenConfigBaseSchema.extend({
|
6436
|
+
contractAddress: SubPsp22TokenSchema.shape.contractAddress,
|
6437
|
+
existentialDeposit: SubPsp22TokenSchema.shape.existentialDeposit.optional()
|
6438
|
+
});
|
6439
|
+
|
6440
|
+
// {
|
6441
|
+
// tokens?: Array<
|
6442
|
+
// {
|
6443
|
+
// symbol?: string
|
6444
|
+
// decimals?: number
|
6445
|
+
// ed?: string
|
6446
|
+
// contractAddress: string
|
6447
|
+
// } & BalancesConfigTokenParams
|
6448
|
+
// >
|
6449
|
+
// }
|
6450
|
+
|
6577
6451
|
const SubPsp22Module = hydrate => {
|
6578
6452
|
const {
|
6579
6453
|
chainConnectors,
|
@@ -6590,7 +6464,8 @@ const SubPsp22Module = hydrate => {
|
|
6590
6464
|
extra: null
|
6591
6465
|
};
|
6592
6466
|
},
|
6593
|
-
async fetchSubstrateChainTokens(chainId, _chainMeta, moduleConfig) {
|
6467
|
+
async fetchSubstrateChainTokens(chainId, _chainMeta, moduleConfig, tokens) {
|
6468
|
+
if (!tokens?.length) return {};
|
6594
6469
|
// const { isTestnet } = chainMeta
|
6595
6470
|
|
6596
6471
|
const registry = new TypeRegistry();
|
@@ -6602,12 +6477,12 @@ const SubPsp22Module = hydrate => {
|
|
6602
6477
|
chainId,
|
6603
6478
|
registry
|
6604
6479
|
});
|
6605
|
-
const
|
6606
|
-
for (const tokenConfig of
|
6480
|
+
const tokenList = {};
|
6481
|
+
for (const tokenConfig of tokens ?? []) {
|
6607
6482
|
try {
|
6608
6483
|
let symbol = tokenConfig?.symbol ?? "Unit";
|
6609
6484
|
let decimals = tokenConfig?.decimals ?? 0;
|
6610
|
-
const existentialDeposit = tokenConfig?.
|
6485
|
+
const existentialDeposit = tokenConfig?.existentialDeposit ?? "0";
|
6611
6486
|
const contractAddress = tokenConfig?.contractAddress ?? undefined;
|
6612
6487
|
if (contractAddress === undefined) continue;
|
6613
6488
|
await (async () => {
|
@@ -6640,13 +6515,13 @@ const SubPsp22Module = hydrate => {
|
|
6640
6515
|
};
|
6641
6516
|
if (tokenConfig?.coingeckoId) token.coingeckoId = tokenConfig?.coingeckoId;
|
6642
6517
|
if (tokenConfig?.mirrorOf) token.mirrorOf = tokenConfig?.mirrorOf;
|
6643
|
-
|
6518
|
+
tokenList[token.id] = token;
|
6644
6519
|
} catch (error) {
|
6645
6520
|
log.error(`Failed to build substrate-psp22 token ${tokenConfig.contractAddress} (${tokenConfig.symbol}) on ${chainId}`, error?.message ?? error);
|
6646
6521
|
continue;
|
6647
6522
|
}
|
6648
6523
|
}
|
6649
|
-
return
|
6524
|
+
return tokenList;
|
6650
6525
|
},
|
6651
6526
|
// TODO: Don't create empty subscriptions
|
6652
6527
|
async subscribeBalances({
|
@@ -6821,11 +6696,28 @@ const fetchBalances = async (chainConnector, tokens, addressesByToken) => {
|
|
6821
6696
|
};
|
6822
6697
|
|
6823
6698
|
const moduleType = "substrate-tokens";
|
6699
|
+
const SubTokensTokenConfigSchema = TokenConfigBaseSchema.extend({
|
6700
|
+
onChainId: SubTokensTokenSchema.shape.onChainId,
|
6701
|
+
existentialDeposit: SubTokensTokenSchema.shape.existentialDeposit
|
6702
|
+
});
|
6824
6703
|
const defaultPalletId = "Tokens";
|
6825
6704
|
const UNSUPPORTED_CHAIN_META = {
|
6826
6705
|
miniMetadata: null,
|
6827
6706
|
extra: {}
|
6828
6707
|
};
|
6708
|
+
|
6709
|
+
// {
|
6710
|
+
// palletId?: string // TODO unlikely it will ever be used - remove this ?
|
6711
|
+
// tokens?: Array<
|
6712
|
+
// {
|
6713
|
+
// symbol?: string
|
6714
|
+
// decimals?: number
|
6715
|
+
// ed?: string
|
6716
|
+
// onChainId?: string | number
|
6717
|
+
// } & BalancesConfigTokenParams
|
6718
|
+
// >
|
6719
|
+
// }
|
6720
|
+
|
6829
6721
|
const SubTokensModule = hydrate => {
|
6830
6722
|
const {
|
6831
6723
|
chainConnectors,
|
@@ -6851,13 +6743,14 @@ const SubTokensModule = hydrate => {
|
|
6851
6743
|
}
|
6852
6744
|
};
|
6853
6745
|
},
|
6854
|
-
async fetchSubstrateChainTokens(chainId, chainMeta, moduleConfig) {
|
6855
|
-
const
|
6856
|
-
for (const tokenConfig of
|
6746
|
+
async fetchSubstrateChainTokens(chainId, chainMeta, moduleConfig, tokens) {
|
6747
|
+
const tokenList = {};
|
6748
|
+
for (const tokenConfig of tokens ?? []) {
|
6857
6749
|
try {
|
6750
|
+
// TODO fetch metadata from chain, like we do for assets
|
6858
6751
|
const symbol = tokenConfig?.symbol ?? "Unit";
|
6859
6752
|
const decimals = tokenConfig?.decimals ?? 0;
|
6860
|
-
const existentialDeposit = tokenConfig?.
|
6753
|
+
const existentialDeposit = tokenConfig?.existentialDeposit ?? "0";
|
6861
6754
|
const onChainId = tokenConfig?.onChainId ?? undefined;
|
6862
6755
|
if (onChainId === undefined) continue;
|
6863
6756
|
const id = subTokensTokenId(chainId, onChainId);
|
@@ -6876,13 +6769,13 @@ const SubTokensModule = hydrate => {
|
|
6876
6769
|
};
|
6877
6770
|
if (tokenConfig?.coingeckoId) token.coingeckoId = tokenConfig?.coingeckoId;
|
6878
6771
|
if (tokenConfig?.mirrorOf) token.mirrorOf = tokenConfig?.mirrorOf;
|
6879
|
-
|
6772
|
+
tokenList[token.id] = token;
|
6880
6773
|
} catch (error) {
|
6881
6774
|
log.error(`Failed to build substrate-tokens token ${tokenConfig.onChainId} (${tokenConfig.symbol}) on ${chainId}`, error?.message ?? error);
|
6882
6775
|
continue;
|
6883
6776
|
}
|
6884
6777
|
}
|
6885
|
-
return
|
6778
|
+
return tokenList;
|
6886
6779
|
},
|
6887
6780
|
// TODO: Don't create empty subscriptions
|
6888
6781
|
async subscribeBalances({
|
@@ -6912,10 +6805,10 @@ const SubTokensModule = hydrate => {
|
|
6912
6805
|
}
|
6913
6806
|
}));
|
6914
6807
|
return () => {
|
6915
|
-
controller.abort();
|
6916
6808
|
pUnsubs.then(unsubs => {
|
6917
6809
|
unsubs.forEach(unsubscribe => unsubscribe());
|
6918
6810
|
});
|
6811
|
+
controller.abort();
|
6919
6812
|
};
|
6920
6813
|
},
|
6921
6814
|
async fetchBalances(addressesByToken) {
|
@@ -7124,4 +7017,4 @@ async function buildQueries(chainConnector, chaindataProvider, addressesByToken,
|
|
7124
7017
|
|
7125
7018
|
const defaultBalanceModules = [EvmErc20Module, EvmNativeModule, EvmUniswapV2Module, SubAssetsModule, SubForeignAssetsModule, SubNativeModule, SubPsp22Module, SubTokensModule];
|
7126
7019
|
|
7127
|
-
export { Balance, BalanceFormatter, BalanceValueGetter, Balances, Change24hCurrencyFormatter, DefaultBalanceModule, EvmErc20Module, EvmNativeModule, EvmTokenFetcher, EvmUniswapV2Module, FiatSumBalancesFormatter, ONE_ALPHA_TOKEN, PlanckSumBalancesFormatter, RpcStateQueryHelper, SCALE_FACTOR, SUBTENSOR_MIN_STAKE_AMOUNT_PLANK, SUBTENSOR_ROOT_NETUID, SubAssetsModule, SubForeignAssetsModule, SubNativeModule, SubPsp22Module, SubTokensModule, SumBalancesFormatter, TalismanBalancesDatabase, abiMulticall, balances, buildNetworkStorageCoders, buildStorageCoders, calculateAlphaPrice, calculateTaoAmountFromAlpha, calculateTaoFromDynamicInfo, compress, configureStore, db, decodeOutput, decompress, defaultBalanceModules, deriveMiniMetadataId, detectTransferMethod, erc20Abi, erc20BalancesAggregatorAbi, excludeFromFeePayableLocks, excludeFromTransferableAmount, filterBaseLocks, filterMirrorTokens, getBalanceId, getLockTitle, getUniqueChainIds, getValueId, includeInTotalExtraAmount, makeContractCaller, uniswapV2PairAbi };
|
7020
|
+
export { Balance, BalanceFormatter, BalanceValueGetter, Balances, Change24hCurrencyFormatter, DefaultBalanceModule, EvmErc20Module, EvmErc20TokenConfigSchema, EvmNativeModule, EvmNativeTokenConfigSchema, EvmTokenFetcher, EvmUniswapV2Module, EvmUniswapV2TokenConfigSchema, FiatSumBalancesFormatter, ONE_ALPHA_TOKEN, PlanckSumBalancesFormatter, RpcStateQueryHelper, SCALE_FACTOR, SUBTENSOR_MIN_STAKE_AMOUNT_PLANK, SUBTENSOR_ROOT_NETUID, SubAssetsModule, SubAssetsTokenConfigSchema, SubForeignAssetsModule, SubForeignAssetsTokenConfigSchema, SubNativeModule, SubNativeTokenConfigSchema, SubPsp22Module, SubPsp22TokenConfigSchema, SubTokensModule, SubTokensTokenConfigSchema, SumBalancesFormatter, TalismanBalancesDatabase, abiMulticall, balances, buildNetworkStorageCoders, buildStorageCoders, calculateAlphaPrice, calculateTaoAmountFromAlpha, calculateTaoFromDynamicInfo, compress, configureStore, db, decodeOutput, decompress, defaultBalanceModules, deriveMiniMetadataId, detectTransferMethod, erc20Abi, erc20BalancesAggregatorAbi, excludeFromFeePayableLocks, excludeFromTransferableAmount, filterBaseLocks, filterMirrorTokens, getBalanceId, getLockTitle, getUniqueChainIds, getValueId, includeInTotalExtraAmount, makeContractCaller, uniswapV2PairAbi };
|