@talismn/balances 3.0.6 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +373 -63
- package/dist/index.d.mts.map +1 -1
- package/dist/index.d.ts +360 -50
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +166 -76
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +166 -79
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -9
package/dist/index.js
CHANGED
|
@@ -45,10 +45,10 @@ let _metaplex_foundation_umi = require("@metaplex-foundation/umi");
|
|
|
45
45
|
let _solana_program_token_2022 = require("@solana-program/token-2022");
|
|
46
46
|
let _polkadot_api_substrate_bindings = require("@polkadot-api/substrate-bindings");
|
|
47
47
|
let _polkadot_api_utils = require("@polkadot-api/utils");
|
|
48
|
+
let _talismn_sapi = require("@talismn/sapi");
|
|
48
49
|
let lodash_es_upperFirst = require("lodash-es/upperFirst");
|
|
49
50
|
lodash_es_upperFirst = __toESM(lodash_es_upperFirst);
|
|
50
51
|
let scale_ts = require("scale-ts");
|
|
51
|
-
let _talismn_sapi = require("@talismn/sapi");
|
|
52
52
|
//#region src/configureBigNumber.ts
|
|
53
53
|
bignumber_js.default.set({ STRICT: false });
|
|
54
54
|
var configureBigNumber_default = bignumber_js.default;
|
|
@@ -443,7 +443,7 @@ var Balance = class {
|
|
|
443
443
|
}
|
|
444
444
|
/** The frozen balance of this token. Is included in the free amount. */
|
|
445
445
|
get locked() {
|
|
446
|
-
if (this.#cachedLocked === void 0) this.#cachedLocked = this.#format(this.locks
|
|
446
|
+
if (this.#cachedLocked === void 0) this.#cachedLocked = this.#format(excludeFromTransferableAmount(this.locks));
|
|
447
447
|
return this.#cachedLocked;
|
|
448
448
|
}
|
|
449
449
|
get locks() {
|
|
@@ -512,7 +512,8 @@ var Balance = class {
|
|
|
512
512
|
const newCalculation = () => _talismn_util.BigMath.max(this.locked.planck, this.reserved.planck);
|
|
513
513
|
const baseUnavailable = this.#storage.useLegacyTransferableCalculation ? oldCalculation() : newCalculation();
|
|
514
514
|
const nomPoolStakedPlancks = this.locks.some((lock) => lock.source === "substrate-native-holds" && lock.label === "DelegatedStaking") ? 0n : this.nompools.map(({ amount }) => amount.planck).reduce((a, b) => a + b, 0n);
|
|
515
|
-
|
|
515
|
+
const extra = this.getValue("extra");
|
|
516
|
+
return this.#format(baseUnavailable + nomPoolStakedPlancks + includeInTotalExtraAmount(extra));
|
|
516
517
|
};
|
|
517
518
|
/** The feePayable balance of this token. Is generally the free amount - the feeFrozen amount. */
|
|
518
519
|
get feePayable() {
|
|
@@ -1693,18 +1694,31 @@ const fetchRpcQueryPack = async (connector, networkId, queries, at) => {
|
|
|
1693
1694
|
return decodeRpcQueryPackChunked(queries, new Map(result.changes), { label: `rpcQueryPack decode ${networkId}` });
|
|
1694
1695
|
};
|
|
1695
1696
|
/**
|
|
1697
|
+
* The connector reports a chain that has been unreachable for a while with a StaleRpcError,
|
|
1698
|
+
* but keeps the subscription registered and re-issues it when a socket reconnects (the
|
|
1699
|
+
* first notification after that is a full snapshot again). Matched by its `type` rather
|
|
1700
|
+
* than `instanceof`, so a second copy of @talismn/chain-connectors still matches.
|
|
1701
|
+
*/
|
|
1702
|
+
const isStaleRpcError = (error) => typeof error === "object" && error !== null && error.type === "STALE_RPC_ERROR";
|
|
1703
|
+
/**
|
|
1696
1704
|
* Wraps the raw state_subscribeStorage subscription and emits, for every storage change
|
|
1697
1705
|
* callback, a SNAPSHOT of the accumulated changes keyed by state key.
|
|
1698
1706
|
*
|
|
1699
1707
|
* A snapshot (shallow copy of string refs, cheap) is required because decoding is chunked
|
|
1700
1708
|
* and asynchronous: a later websocket callback must not mutate the map that an in-flight
|
|
1701
1709
|
* decode is reading.
|
|
1710
|
+
*
|
|
1711
|
+
* A StaleRpcError does not end the stream. Erroring would unsubscribe, and with no
|
|
1712
|
+
* subscription holding the chain's socket, every later request (eg the dtao poll) would
|
|
1713
|
+
* open and close a socket of its own, starting from the network's first RPC each time.
|
|
1702
1714
|
*/
|
|
1703
1715
|
const getRawStorageUpdates$ = (connector, networkId, allStateKeys, timeout) => new rxjs.Observable((subscriber) => {
|
|
1704
1716
|
const changesCache = /* @__PURE__ */ new Map();
|
|
1705
1717
|
const promUnsub = connector.subscribe(networkId, "state_subscribeStorage", "state_storage", [allStateKeys], (error, result) => {
|
|
1706
|
-
if (error)
|
|
1707
|
-
|
|
1718
|
+
if (error) {
|
|
1719
|
+
if (isStaleRpcError(error)) log_default.warn(`Storage subscription stale on ${networkId}`);
|
|
1720
|
+
else subscriber.error(error);
|
|
1721
|
+
} else if (result) {
|
|
1708
1722
|
for (const [stateKey, encodedResult] of result.changes) changesCache.set(stateKey, encodedResult);
|
|
1709
1723
|
subscriber.next(new Map(changesCache));
|
|
1710
1724
|
}
|
|
@@ -2590,15 +2604,16 @@ const hasRuntimeApi = (metadata, apiName, method) => {
|
|
|
2590
2604
|
if (!api?.methods) return false;
|
|
2591
2605
|
return api.methods.some((m) => m.name === method);
|
|
2592
2606
|
};
|
|
2593
|
-
const
|
|
2594
|
-
|
|
2607
|
+
const toParsedMetadata = (metadata) => typeof metadata === "string" ? (0, _talismn_scale.parseMetadataRpc)(metadata) : metadata;
|
|
2608
|
+
const getConstantValue = (metadata, pallet, constant) => {
|
|
2609
|
+
const { unifiedMetadata, builder } = toParsedMetadata(metadata);
|
|
2595
2610
|
const codec = builder.buildConstant(pallet, constant);
|
|
2596
2611
|
const encodedValue = unifiedMetadata.pallets.find(({ name }) => name === pallet)?.constants.find(({ name }) => name === constant)?.value;
|
|
2597
2612
|
if (!encodedValue) throw new Error(`Constant ${pallet}.${constant} not found`);
|
|
2598
2613
|
return codec.dec(encodedValue);
|
|
2599
2614
|
};
|
|
2600
|
-
const tryGetConstantValue = (
|
|
2601
|
-
const { unifiedMetadata, builder } = (
|
|
2615
|
+
const tryGetConstantValue = (metadata, pallet, constant) => {
|
|
2616
|
+
const { unifiedMetadata, builder } = toParsedMetadata(metadata);
|
|
2602
2617
|
const encodedValue = unifiedMetadata.pallets.find(({ name }) => name === pallet)?.constants.find(({ name }) => name === constant)?.value;
|
|
2603
2618
|
if (!encodedValue) return null;
|
|
2604
2619
|
return builder.buildConstant(pallet, constant).dec(encodedValue);
|
|
@@ -2732,7 +2747,7 @@ const fetchOnChainTokenData$1 = async (connector, tokenId) => {
|
|
|
2732
2747
|
//#region src/modules/sol-spl/fetchBalances.ts
|
|
2733
2748
|
const SPL_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
|
|
2734
2749
|
const dynamicTokenMetadataCache$1 = new _talismn_util.LruMap(1024);
|
|
2735
|
-
const associatedTokenAccountCache = new _talismn_util.LruMap(1024);
|
|
2750
|
+
const associatedTokenAccountCache$1 = new _talismn_util.LruMap(1024);
|
|
2736
2751
|
const fetchBalances$8 = async ({ networkId, tokensWithAddresses, connector }) => {
|
|
2737
2752
|
if (!tokensWithAddresses.length) return {
|
|
2738
2753
|
success: [],
|
|
@@ -2752,7 +2767,7 @@ const fetchBalances$8 = async ({ networkId, tokensWithAddresses, connector }) =>
|
|
|
2752
2767
|
return {
|
|
2753
2768
|
mintAddress,
|
|
2754
2769
|
value,
|
|
2755
|
-
isSpendable: value !== 0n && state !== "frozen" && d.pubkey === await getAssociatedTokenAccount(address, mintAddress)
|
|
2770
|
+
isSpendable: value !== 0n && state !== "frozen" && d.pubkey === await getAssociatedTokenAccount$1(address, mintAddress)
|
|
2756
2771
|
};
|
|
2757
2772
|
} catch {
|
|
2758
2773
|
log_default.warn("Failed to parse token amount", {
|
|
@@ -2845,16 +2860,16 @@ const fetchBalances$8 = async ({ networkId, tokensWithAddresses, connector }) =>
|
|
|
2845
2860
|
};
|
|
2846
2861
|
};
|
|
2847
2862
|
const getBalanceKey$1 = (tokenId, address) => `${tokenId}:${address}`;
|
|
2848
|
-
const getAssociatedTokenAccount = async (owner, mint) => {
|
|
2863
|
+
const getAssociatedTokenAccount$1 = async (owner, mint) => {
|
|
2849
2864
|
const key = `${owner}:${mint}`;
|
|
2850
|
-
const cached = associatedTokenAccountCache.get(key);
|
|
2865
|
+
const cached = associatedTokenAccountCache$1.get(key);
|
|
2851
2866
|
if (cached) return cached;
|
|
2852
2867
|
const [associatedTokenAccount] = await (0, _solana_program_token.findAssociatedTokenPda)({
|
|
2853
2868
|
mint: (0, _solana_kit.address)(mint),
|
|
2854
2869
|
owner: (0, _solana_kit.address)(owner),
|
|
2855
2870
|
tokenProgram: _solana_program_token.TOKEN_PROGRAM_ADDRESS
|
|
2856
2871
|
});
|
|
2857
|
-
associatedTokenAccountCache.set(key, associatedTokenAccount);
|
|
2872
|
+
associatedTokenAccountCache$1.set(key, associatedTokenAccount);
|
|
2858
2873
|
return associatedTokenAccount;
|
|
2859
2874
|
};
|
|
2860
2875
|
//#endregion
|
|
@@ -3304,6 +3319,7 @@ const fetchOnChainTokenData = async (connector, tokenId) => {
|
|
|
3304
3319
|
//#region src/modules/sol-token2022/fetchBalances.ts
|
|
3305
3320
|
const TOKEN_2022_PROGRAM_ID = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb";
|
|
3306
3321
|
const dynamicTokenMetadataCache = /* @__PURE__ */ new Map();
|
|
3322
|
+
const associatedTokenAccountCache = new _talismn_util.LruMap(1024);
|
|
3307
3323
|
const fetchBalances$7 = async ({ networkId, tokensWithAddresses, connector }) => {
|
|
3308
3324
|
if (!tokensWithAddresses.length) return {
|
|
3309
3325
|
success: [],
|
|
@@ -3315,19 +3331,15 @@ const fetchBalances$7 = async ({ networkId, tokensWithAddresses, connector }) =>
|
|
|
3315
3331
|
const knownTokenIds = new Set(tokensWithAddresses.map(([token]) => token.id));
|
|
3316
3332
|
const unknownMints = /* @__PURE__ */ new Set();
|
|
3317
3333
|
const balancesPerAddress = await Promise.all(accountAddresses.map(async (address) => {
|
|
3318
|
-
const
|
|
3334
|
+
const tokenAccounts = await rpc.getTokenAccountsByOwner((0, _solana_kit.address)(address), { programId: (0, _solana_kit.address)(TOKEN_2022_PROGRAM_ID) }, { encoding: "jsonParsed" }).send();
|
|
3335
|
+
const tokenAccountHoldings = await Promise.all(tokenAccounts.value.map(async (d) => {
|
|
3319
3336
|
try {
|
|
3320
|
-
const mintAddress = d.account.data.parsed.info
|
|
3321
|
-
const value =
|
|
3322
|
-
const tokenId = (0, _talismn_chaindata_provider.solToken2022TokenId)(networkId, mintAddress);
|
|
3323
|
-
if (!knownTokenIds.has(tokenId) && value !== "0") unknownMints.add(mintAddress);
|
|
3337
|
+
const { mint: mintAddress, state, tokenAmount } = d.account.data.parsed.info;
|
|
3338
|
+
const value = BigInt(tokenAmount.amount ?? "0");
|
|
3324
3339
|
return {
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
address,
|
|
3328
|
-
source: MODULE_TYPE$7,
|
|
3329
|
-
status: "live",
|
|
3330
|
-
value
|
|
3340
|
+
mintAddress,
|
|
3341
|
+
value,
|
|
3342
|
+
isSpendable: value !== 0n && state !== "frozen" && d.pubkey === await getAssociatedTokenAccount(address, mintAddress)
|
|
3331
3343
|
};
|
|
3332
3344
|
} catch {
|
|
3333
3345
|
log_default.warn("Failed to parse token amount", {
|
|
@@ -3336,7 +3348,36 @@ const fetchBalances$7 = async ({ networkId, tokensWithAddresses, connector }) =>
|
|
|
3336
3348
|
});
|
|
3337
3349
|
return null;
|
|
3338
3350
|
}
|
|
3339
|
-
})
|
|
3351
|
+
}));
|
|
3352
|
+
const holdingsPerTokenId = /* @__PURE__ */ new Map();
|
|
3353
|
+
for (const { mintAddress, value, isSpendable } of tokenAccountHoldings.filter(_talismn_util.isNotNil)) {
|
|
3354
|
+
const tokenId = (0, _talismn_chaindata_provider.solToken2022TokenId)(networkId, mintAddress);
|
|
3355
|
+
if (!knownTokenIds.has(tokenId) && value !== 0n) unknownMints.add(mintAddress);
|
|
3356
|
+
const { total, spendable } = holdingsPerTokenId.get(tokenId) ?? {
|
|
3357
|
+
total: 0n,
|
|
3358
|
+
spendable: 0n
|
|
3359
|
+
};
|
|
3360
|
+
holdingsPerTokenId.set(tokenId, {
|
|
3361
|
+
total: total + value,
|
|
3362
|
+
spendable: spendable + (isSpendable ? value : 0n)
|
|
3363
|
+
});
|
|
3364
|
+
}
|
|
3365
|
+
const balances = [...holdingsPerTokenId].map(([tokenId, { total, spendable }]) => ({
|
|
3366
|
+
tokenId,
|
|
3367
|
+
networkId,
|
|
3368
|
+
address,
|
|
3369
|
+
source: MODULE_TYPE$7,
|
|
3370
|
+
status: "live",
|
|
3371
|
+
...spendable === total ? { value: total.toString() } : { values: [{
|
|
3372
|
+
type: "free",
|
|
3373
|
+
label: "free",
|
|
3374
|
+
amount: total.toString()
|
|
3375
|
+
}, {
|
|
3376
|
+
type: "locked",
|
|
3377
|
+
label: "locked",
|
|
3378
|
+
amount: (total - spendable).toString()
|
|
3379
|
+
}] }
|
|
3380
|
+
}));
|
|
3340
3381
|
setDetectedTokenIds(address, MODULE_TYPE$7, balances.map((b) => b.tokenId));
|
|
3341
3382
|
return [address, balances];
|
|
3342
3383
|
}));
|
|
@@ -3391,6 +3432,18 @@ const fetchBalances$7 = async ({ networkId, tokensWithAddresses, connector }) =>
|
|
|
3391
3432
|
};
|
|
3392
3433
|
};
|
|
3393
3434
|
const getBalanceKey = (tokenId, address) => `${tokenId}:${address}`;
|
|
3435
|
+
const getAssociatedTokenAccount = async (owner, mint) => {
|
|
3436
|
+
const key = `${owner}:${mint}`;
|
|
3437
|
+
const cached = associatedTokenAccountCache.get(key);
|
|
3438
|
+
if (cached) return cached;
|
|
3439
|
+
const [associatedTokenAccount] = await (0, _solana_program_token.findAssociatedTokenPda)({
|
|
3440
|
+
mint: (0, _solana_kit.address)(mint),
|
|
3441
|
+
owner: (0, _solana_kit.address)(owner),
|
|
3442
|
+
tokenProgram: _solana_program_token_2022.TOKEN_2022_PROGRAM_ADDRESS
|
|
3443
|
+
});
|
|
3444
|
+
associatedTokenAccountCache.set(key, associatedTokenAccount);
|
|
3445
|
+
return associatedTokenAccount;
|
|
3446
|
+
};
|
|
3394
3447
|
//#endregion
|
|
3395
3448
|
//#region src/modules/sol-token2022/fetchTokens.ts
|
|
3396
3449
|
const fetchTokens$7 = async ({ networkId, tokens, connector, cache }) => {
|
|
@@ -3648,14 +3701,15 @@ const deriveMiniMetadataId = ({ source, chainId, specVersion }) => (0, _talismn_
|
|
|
3648
3701
|
const getMiniMetadata$6 = ({ networkId, specVersion, metadataRpc }) => {
|
|
3649
3702
|
const source = MODULE_TYPE$6;
|
|
3650
3703
|
const chainId = networkId;
|
|
3651
|
-
const
|
|
3704
|
+
const parsed = (0, _talismn_scale.parseMetadataRpc)(metadataRpc);
|
|
3705
|
+
const { unifiedMetadata } = parsed;
|
|
3706
|
+
const systemVersion = getConstantValue(parsed, "System", "Version");
|
|
3652
3707
|
if (specVersion !== systemVersion.spec_version) throw new Error(`specVersion mismatch: expected ${specVersion}, metadata got ${systemVersion.spec_version}`);
|
|
3653
3708
|
const id = deriveMiniMetadataId({
|
|
3654
3709
|
source,
|
|
3655
3710
|
chainId,
|
|
3656
3711
|
specVersion
|
|
3657
3712
|
});
|
|
3658
|
-
const { unifiedMetadata } = (0, _talismn_scale.parseMetadataRpc)(metadataRpc);
|
|
3659
3713
|
if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
|
|
3660
3714
|
return {
|
|
3661
3715
|
id,
|
|
@@ -3663,12 +3717,11 @@ const getMiniMetadata$6 = ({ networkId, specVersion, metadataRpc }) => {
|
|
|
3663
3717
|
chainId,
|
|
3664
3718
|
specVersion,
|
|
3665
3719
|
version: _talismn_chaindata_provider.MINIMETADATA_VERSION,
|
|
3666
|
-
data: getData$4(
|
|
3720
|
+
data: getData$4(parsed),
|
|
3667
3721
|
extra: null
|
|
3668
3722
|
};
|
|
3669
3723
|
};
|
|
3670
|
-
const getData$4 = (
|
|
3671
|
-
const { metadata, unifiedMetadata } = (0, _talismn_scale.parseMetadataRpc)(metadataRpc);
|
|
3724
|
+
const getData$4 = ({ metadata, unifiedMetadata }) => {
|
|
3672
3725
|
if (!hasStorageItems(unifiedMetadata, "Assets", [
|
|
3673
3726
|
"Account",
|
|
3674
3727
|
"Asset",
|
|
@@ -3846,27 +3899,6 @@ const fetchBasketClaims = async (connector, networkId, metadataRpc, addresses, a
|
|
|
3846
3899
|
}
|
|
3847
3900
|
};
|
|
3848
3901
|
//#endregion
|
|
3849
|
-
//#region src/modules/substrate-dtao/fetchStorageKeysPaged.ts
|
|
3850
|
-
const PAGE_SIZE = 1e3;
|
|
3851
|
-
/**
|
|
3852
|
-
* Prefix scan via state_getKeysPaged. The unpaged state_getKeys is classified as heavy storage
|
|
3853
|
-
* work and rejected by some public nodes (eg the bittensor testnet one: "Storage work rate limit
|
|
3854
|
-
* exceeded"), while the paged variant is universally allowed.
|
|
3855
|
-
*/
|
|
3856
|
-
const fetchStorageKeysPaged = async (connector, networkId, keyPrefix, at) => {
|
|
3857
|
-
const keys = [];
|
|
3858
|
-
let startKey;
|
|
3859
|
-
do {
|
|
3860
|
-
const params = [keyPrefix, PAGE_SIZE];
|
|
3861
|
-
if (startKey || at) params.push(startKey ?? null);
|
|
3862
|
-
if (at) params.push(at);
|
|
3863
|
-
const page = await connector.send(networkId, "state_getKeysPaged", params);
|
|
3864
|
-
keys.push(...page);
|
|
3865
|
-
startKey = page.length === PAGE_SIZE ? page[page.length - 1] : void 0;
|
|
3866
|
-
} while (startKey);
|
|
3867
|
-
return keys;
|
|
3868
|
-
};
|
|
3869
|
-
//#endregion
|
|
3870
3902
|
//#region src/modules/substrate-dtao/convictionLocks.ts
|
|
3871
3903
|
const convictionLockKey = (address, netuid) => `${address}:${netuid}`;
|
|
3872
3904
|
const getConvictionLockLabel = (lockType) => lockType === "perpetual" ? "Perpetual Conviction Lock" : "Decaying Conviction Lock";
|
|
@@ -3963,7 +3995,7 @@ const fetchConvictionLockStorageKeys = async (connector, networkId, addresses, s
|
|
|
3963
3995
|
}
|
|
3964
3996
|
let stateKeys;
|
|
3965
3997
|
try {
|
|
3966
|
-
stateKeys = await fetchStorageKeysPaged(
|
|
3998
|
+
stateKeys = await (0, _talismn_sapi.fetchStorageKeysPaged)((method, params) => connector.send(networkId, method, params), keyPrefix, { at });
|
|
3967
3999
|
} catch (cause) {
|
|
3968
4000
|
log_default.warn(`Failed to fetch conviction Lock keys (address=${address}) on ${networkId}`, { cause });
|
|
3969
4001
|
throw cause;
|
|
@@ -4387,7 +4419,7 @@ const fetchTokens$5 = async ({ networkId, connector, tokens, miniMetadata }) =>
|
|
|
4387
4419
|
const fetchTransferableTokensMap = async (connector, metadata, networkId) => {
|
|
4388
4420
|
const { builder } = parseMetadataRpcCached(metadata);
|
|
4389
4421
|
const transferToggleCodec = builder.buildStorage("SubtensorModule", "TransferToggle");
|
|
4390
|
-
const transferToggleKeys = await fetchStorageKeysPaged(
|
|
4422
|
+
const transferToggleKeys = await (0, _talismn_sapi.fetchStorageKeysPaged)((method, params) => connector.send(networkId, method, params), (0, _talismn_scale.getStorageKeyPrefix)("SubtensorModule", "TransferToggle"));
|
|
4391
4423
|
const transferToggleResults = await connector.send(networkId, "state_queryStorageAt", [transferToggleKeys]);
|
|
4392
4424
|
const transferToggleEntries = transferToggleResults.length ? transferToggleResults[0].changes : [];
|
|
4393
4425
|
return (0, lodash_es.fromPairs)(transferToggleEntries.map(([key, value]) => {
|
|
@@ -4835,14 +4867,15 @@ const fetchTokens$4 = async ({ networkId, tokens, connector, miniMetadata }) =>
|
|
|
4835
4867
|
const getMiniMetadata$4 = ({ networkId, specVersion, metadataRpc }) => {
|
|
4836
4868
|
const source = MODULE_TYPE$4;
|
|
4837
4869
|
const chainId = networkId;
|
|
4838
|
-
const
|
|
4870
|
+
const parsed = (0, _talismn_scale.parseMetadataRpc)(metadataRpc);
|
|
4871
|
+
const { unifiedMetadata } = parsed;
|
|
4872
|
+
const systemVersion = getConstantValue(parsed, "System", "Version");
|
|
4839
4873
|
if (specVersion !== systemVersion.spec_version) throw new Error(`specVersion mismatch: expected ${specVersion}, metadata got ${systemVersion.spec_version}`);
|
|
4840
4874
|
const id = deriveMiniMetadataId({
|
|
4841
4875
|
source,
|
|
4842
4876
|
chainId,
|
|
4843
4877
|
specVersion
|
|
4844
4878
|
});
|
|
4845
|
-
const { unifiedMetadata } = (0, _talismn_scale.parseMetadataRpc)(metadataRpc);
|
|
4846
4879
|
if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
|
|
4847
4880
|
return {
|
|
4848
4881
|
id,
|
|
@@ -4850,12 +4883,11 @@ const getMiniMetadata$4 = ({ networkId, specVersion, metadataRpc }) => {
|
|
|
4850
4883
|
chainId,
|
|
4851
4884
|
specVersion,
|
|
4852
4885
|
version: _talismn_chaindata_provider.MINIMETADATA_VERSION,
|
|
4853
|
-
data: getData$2(
|
|
4886
|
+
data: getData$2(parsed),
|
|
4854
4887
|
extra: null
|
|
4855
4888
|
};
|
|
4856
4889
|
};
|
|
4857
|
-
const getData$2 = (
|
|
4858
|
-
const { metadata, unifiedMetadata } = (0, _talismn_scale.parseMetadataRpc)(metadataRpc);
|
|
4890
|
+
const getData$2 = ({ metadata, unifiedMetadata }) => {
|
|
4859
4891
|
if (!hasStorageItems(unifiedMetadata, "ForeignAssets", [
|
|
4860
4892
|
"Account",
|
|
4861
4893
|
"Asset",
|
|
@@ -5172,6 +5204,17 @@ const SubHydrationTokenConfigSchema = zod_v4.default.strictObject({
|
|
|
5172
5204
|
...TokenConfigBaseSchema.shape
|
|
5173
5205
|
});
|
|
5174
5206
|
//#endregion
|
|
5207
|
+
//#region src/modules/substrate-native/evmMirror.ts
|
|
5208
|
+
const EVM_MIRROR_LOCK_LABEL = "evm-mirror";
|
|
5209
|
+
const isEvmMirrorWithdrawableLock = (lock) => lock.meta?.type === "evm-mirror-withdrawable";
|
|
5210
|
+
const findEvmMirrorWithdrawable = (locks) => {
|
|
5211
|
+
const lock = locks?.find(isEvmMirrorWithdrawableLock);
|
|
5212
|
+
return lock ? {
|
|
5213
|
+
...lock.meta,
|
|
5214
|
+
amount: lock.amount.planck
|
|
5215
|
+
} : null;
|
|
5216
|
+
};
|
|
5217
|
+
//#endregion
|
|
5175
5218
|
//#region src/modules/substrate-native/config.ts
|
|
5176
5219
|
const MODULE_TYPE$2 = _talismn_chaindata_provider.SubNativeTokenSchema.shape.type.value;
|
|
5177
5220
|
const PLATFORM$2 = _talismn_chaindata_provider.SubNativeTokenSchema.shape.platform.value;
|
|
@@ -5217,7 +5260,7 @@ const baseLockLabels = ["fees", "misc"];
|
|
|
5217
5260
|
const isBaseLock = (lock) => baseLockLabels.includes(lock.label);
|
|
5218
5261
|
const isNonBaseLock = (lock) => !isBaseLock(lock);
|
|
5219
5262
|
const filterBaseLocks = (locks) => {
|
|
5220
|
-
if (!locks.some(isNonBaseLock)) return locks;
|
|
5263
|
+
if (!locks.some((lock) => isNonBaseLock(lock) && !lock.includeInTransferable)) return locks;
|
|
5221
5264
|
return locks.filter(isNonBaseLock);
|
|
5222
5265
|
};
|
|
5223
5266
|
const getLockTitle = (lock, { balance } = {}) => {
|
|
@@ -5228,6 +5271,7 @@ const getLockTitle = (lock, { balance } = {}) => {
|
|
|
5228
5271
|
if (lock.label === "nompools-unbonding") return "Pooled Staking";
|
|
5229
5272
|
if (lock.label === "subtensor-staking") return "Root Staking";
|
|
5230
5273
|
if (lock.label === "dapp-staking") return "DApp Staking";
|
|
5274
|
+
if (lock.label === "evm-mirror") return "EVM Balance";
|
|
5231
5275
|
if (lock.label === "fees") return "Locked (Fees)";
|
|
5232
5276
|
if (lock.label === "misc") return "Locked";
|
|
5233
5277
|
if (lock.label.startsWith("other")) return "Locked";
|
|
@@ -5235,7 +5279,7 @@ const getLockTitle = (lock, { balance } = {}) => {
|
|
|
5235
5279
|
};
|
|
5236
5280
|
//#endregion
|
|
5237
5281
|
//#region src/modules/substrate-native/queries/buildBaseQueries.ts
|
|
5238
|
-
const buildBaseQueries = (networkId, balanceDefs, miniMetadata) => {
|
|
5282
|
+
const buildBaseQueries = (networkId, balanceDefs, miniMetadata, hasFrontierMirrorWithdraw = false) => {
|
|
5239
5283
|
const networkStorageCoders = buildNetworkStorageCoders(networkId, miniMetadata, {
|
|
5240
5284
|
account: ["System", "Account"],
|
|
5241
5285
|
stakingLedger: ["Staking", "Ledger"],
|
|
@@ -5247,6 +5291,7 @@ const buildBaseQueries = (networkId, balanceDefs, miniMetadata) => {
|
|
|
5247
5291
|
});
|
|
5248
5292
|
if (!networkStorageCoders) throw new Error(`No network storage coders found for networkId: ${networkId}`);
|
|
5249
5293
|
return balanceDefs.map(({ token, address }) => {
|
|
5294
|
+
const evmMirror = hasFrontierMirrorWithdraw ? getEvmMirror(address) : null;
|
|
5250
5295
|
const getStateKeys = () => {
|
|
5251
5296
|
try {
|
|
5252
5297
|
return [
|
|
@@ -5255,7 +5300,8 @@ const buildBaseQueries = (networkId, balanceDefs, miniMetadata) => {
|
|
|
5255
5300
|
networkStorageCoders.freezes ? networkStorageCoders.freezes.keys.enc(address) : null,
|
|
5256
5301
|
networkStorageCoders.holds ? networkStorageCoders.holds.keys.enc(address) : null,
|
|
5257
5302
|
networkStorageCoders.stakingLedger ? networkStorageCoders.stakingLedger.keys.enc(address) : null,
|
|
5258
|
-
networkStorageCoders.poolMembers ? networkStorageCoders.poolMembers.keys.enc(address) : null
|
|
5303
|
+
networkStorageCoders.poolMembers ? networkStorageCoders.poolMembers.keys.enc(address) : null,
|
|
5304
|
+
networkStorageCoders.account && evmMirror ? networkStorageCoders.account.keys.enc((0, _talismn_crypto.frontierH160ToSs58Mirror)(evmMirror.h160)) : null
|
|
5259
5305
|
];
|
|
5260
5306
|
} catch {
|
|
5261
5307
|
return [];
|
|
@@ -5274,7 +5320,7 @@ const buildBaseQueries = (networkId, balanceDefs, miniMetadata) => {
|
|
|
5274
5320
|
useLegacyTransferableCalculation: miniMetadata.extra.useLegacyTransferableCalculation
|
|
5275
5321
|
};
|
|
5276
5322
|
let nomPoolMemberInfo = null;
|
|
5277
|
-
const [accountChange, lockChange, freezesChange, holdsChange, stakingLedgerChange, nomPoolMemberChange] = changes;
|
|
5323
|
+
const [accountChange, lockChange, freezesChange, holdsChange, stakingLedgerChange, nomPoolMemberChange, evmMirrorAccountChange] = changes;
|
|
5278
5324
|
if (networkStorageCoders.account) {
|
|
5279
5325
|
const baseValues = decodeBaseResult(networkStorageCoders.account, accountChange, networkId);
|
|
5280
5326
|
balance.values.push(...baseValues);
|
|
@@ -5299,6 +5345,10 @@ const buildBaseQueries = (networkId, balanceDefs, miniMetadata) => {
|
|
|
5299
5345
|
const nomPoolMemberValue = decodePoolMemberResult(networkStorageCoders.poolMembers, nomPoolMemberChange, networkId);
|
|
5300
5346
|
if (nomPoolMemberValue) nomPoolMemberInfo = nomPoolMemberValue;
|
|
5301
5347
|
}
|
|
5348
|
+
if (networkStorageCoders.account && evmMirror && evmMirrorAccountChange) {
|
|
5349
|
+
const evmMirrorValues = decodeEvmMirrorResult(networkStorageCoders.account, evmMirrorAccountChange, evmMirror, networkId);
|
|
5350
|
+
balance.values.push(...evmMirrorValues);
|
|
5351
|
+
}
|
|
5302
5352
|
return {
|
|
5303
5353
|
balance,
|
|
5304
5354
|
nomPoolMemberInfo
|
|
@@ -5336,6 +5386,35 @@ const decodeBaseResult = (coder, value, networkId) => {
|
|
|
5336
5386
|
}
|
|
5337
5387
|
];
|
|
5338
5388
|
};
|
|
5389
|
+
const getEvmMirror = (address) => {
|
|
5390
|
+
try {
|
|
5391
|
+
return {
|
|
5392
|
+
type: "evm-mirror-withdrawable",
|
|
5393
|
+
h160: (0, _talismn_crypto.frontierSs58ToTruncatedH160)(address)
|
|
5394
|
+
};
|
|
5395
|
+
} catch {
|
|
5396
|
+
return null;
|
|
5397
|
+
}
|
|
5398
|
+
};
|
|
5399
|
+
const decodeEvmMirrorResult = (coder, value, meta, networkId) => {
|
|
5400
|
+
const free = (0, _talismn_scale.decodeScale)(coder, value, `Failed to decode EVM mirror balance on chain ${networkId}`)?.data?.free ?? 0n;
|
|
5401
|
+
if (free <= 0n) return [];
|
|
5402
|
+
const withdrawable = {
|
|
5403
|
+
source: "substrate-native-evm-mirror",
|
|
5404
|
+
label: EVM_MIRROR_LOCK_LABEL,
|
|
5405
|
+
amount: free.toString(),
|
|
5406
|
+
meta
|
|
5407
|
+
};
|
|
5408
|
+
return [{
|
|
5409
|
+
...withdrawable,
|
|
5410
|
+
type: "locked",
|
|
5411
|
+
includeInTransferable: true
|
|
5412
|
+
}, {
|
|
5413
|
+
...withdrawable,
|
|
5414
|
+
type: "extra",
|
|
5415
|
+
includeInTotal: true
|
|
5416
|
+
}];
|
|
5417
|
+
};
|
|
5339
5418
|
const decodeLocksResult = (coder, value, networkId) => {
|
|
5340
5419
|
return (0, _talismn_scale.decodeScale)(coder, value, `Failed to decode lock on chain ${networkId}`)?.map?.((lock) => {
|
|
5341
5420
|
const id = lock?.id ? _polkadot_api_substrate_bindings.Binary.toText(_polkadot_api_substrate_bindings.Binary.fromHex(lock.id)) : void 0;
|
|
@@ -5503,7 +5582,7 @@ const getNomPoolStateKeys = (coders, nomPoolMemberInfo, extra) => {
|
|
|
5503
5582
|
};
|
|
5504
5583
|
//#endregion
|
|
5505
5584
|
//#region src/modules/substrate-native/fetchBalances.ts
|
|
5506
|
-
const fetchBalances$2 = async ({ networkId, tokensWithAddresses, connector, miniMetadata }) => {
|
|
5585
|
+
const fetchBalances$2 = async ({ networkId, tokensWithAddresses, connector, miniMetadata, hasFrontierMirrorWithdraw }) => {
|
|
5507
5586
|
if (!tokensWithAddresses.length) return {
|
|
5508
5587
|
success: [],
|
|
5509
5588
|
errors: []
|
|
@@ -5542,7 +5621,7 @@ const fetchBalances$2 = async ({ networkId, tokensWithAddresses, connector, mini
|
|
|
5542
5621
|
}))
|
|
5543
5622
|
};
|
|
5544
5623
|
}
|
|
5545
|
-
const baseQueries = buildBaseQueries(networkId, balanceDefs, miniMetadata);
|
|
5624
|
+
const baseQueries = buildBaseQueries(networkId, balanceDefs, miniMetadata, hasFrontierMirrorWithdraw);
|
|
5546
5625
|
const partialBalances = await fetchRpcQueryPack(connector, networkId, baseQueries);
|
|
5547
5626
|
const nomPoolQueries = buildNomPoolQueries(networkId, partialBalances, miniMetadata);
|
|
5548
5627
|
return {
|
|
@@ -5594,14 +5673,15 @@ const getChainProperties = async (connector, networkId) => {
|
|
|
5594
5673
|
const getMiniMetadata$2 = ({ networkId, specVersion, metadataRpc, config }) => {
|
|
5595
5674
|
const source = MODULE_TYPE$2;
|
|
5596
5675
|
const chainId = networkId;
|
|
5597
|
-
const
|
|
5676
|
+
const parsed = (0, _talismn_scale.parseMetadataRpc)(metadataRpc);
|
|
5677
|
+
const { metadata, unifiedMetadata } = parsed;
|
|
5678
|
+
const systemVersion = getConstantValue(parsed, "System", "Version");
|
|
5598
5679
|
if (specVersion !== systemVersion.spec_version) throw new Error(`specVersion mismatch: expected ${specVersion}, metadata got ${systemVersion.spec_version}`);
|
|
5599
5680
|
const id = deriveMiniMetadataId({
|
|
5600
5681
|
source,
|
|
5601
5682
|
chainId,
|
|
5602
5683
|
specVersion
|
|
5603
5684
|
});
|
|
5604
|
-
const { metadata, unifiedMetadata } = (0, _talismn_scale.parseMetadataRpc)(metadataRpc);
|
|
5605
5685
|
if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
|
|
5606
5686
|
if (config?.disable) return {
|
|
5607
5687
|
id,
|
|
@@ -5612,8 +5692,8 @@ const getMiniMetadata$2 = ({ networkId, specVersion, metadataRpc, config }) => {
|
|
|
5612
5692
|
data: null,
|
|
5613
5693
|
extra: { disable: true }
|
|
5614
5694
|
};
|
|
5615
|
-
const existentialDeposit = tryGetConstantValue(
|
|
5616
|
-
const nominationPoolsPalletIdHex = tryGetConstantValue(
|
|
5695
|
+
const existentialDeposit = tryGetConstantValue(parsed, "Balances", "ExistentialDeposit")?.toString();
|
|
5696
|
+
const nominationPoolsPalletIdHex = tryGetConstantValue(parsed, "NominationPools", "PalletId");
|
|
5617
5697
|
const nominationPoolsPalletId = nominationPoolsPalletIdHex ? _polkadot_api_substrate_bindings.Binary.toText(_polkadot_api_substrate_bindings.Binary.fromHex(nominationPoolsPalletIdHex)) : void 0;
|
|
5618
5698
|
const useLegacyTransferableCalculation = !Boolean(unifiedMetadata.pallets.find(({ name }) => name === "Balances")?.storage?.items.find(({ name }) => name === "Freezes"));
|
|
5619
5699
|
(0, _talismn_scale.compactMetadata)(metadata, [
|
|
@@ -5724,7 +5804,7 @@ const getTransferAllEncodedArgs = (to, codec) => {
|
|
|
5724
5804
|
};
|
|
5725
5805
|
//#endregion
|
|
5726
5806
|
//#region src/modules/substrate-native/subscribeBalances.ts
|
|
5727
|
-
const subscribeBalances$2 = ({ networkId, tokensWithAddresses, connector, miniMetadata }) => {
|
|
5807
|
+
const subscribeBalances$2 = ({ networkId, tokensWithAddresses, connector, miniMetadata, hasFrontierMirrorWithdraw }) => {
|
|
5728
5808
|
if (!tokensWithAddresses.length) return (0, rxjs.of)({
|
|
5729
5809
|
success: [],
|
|
5730
5810
|
errors: []
|
|
@@ -5732,7 +5812,7 @@ const subscribeBalances$2 = ({ networkId, tokensWithAddresses, connector, miniMe
|
|
|
5732
5812
|
const balanceDefs = getBalanceDefs(tokensWithAddresses);
|
|
5733
5813
|
return (0, rxjs.defer)(async () => {
|
|
5734
5814
|
await (0, _talismn_util.yieldToEventLoop)();
|
|
5735
|
-
return buildBaseQueries(networkId, balanceDefs, miniMetadata);
|
|
5815
|
+
return buildBaseQueries(networkId, balanceDefs, miniMetadata, hasFrontierMirrorWithdraw);
|
|
5736
5816
|
}).pipe((0, rxjs.switchMap)((baseQueries) => getRpcQueryPack$(connector, networkId, baseQueries)), (0, rxjs.switchMap)((partialBalances) => {
|
|
5737
5817
|
const nomPoolQueries = buildNomPoolQueries(networkId, partialBalances, miniMetadata);
|
|
5738
5818
|
return getRpcQueryPack$(connector, networkId, nomPoolQueries);
|
|
@@ -6778,6 +6858,8 @@ const fetchMiniMetadatas = async (chainConnector, chaindataProvider, chainId, sp
|
|
|
6778
6858
|
* Kept tight — a real incoming transfer above 0.1% of the position emits immediately.
|
|
6779
6859
|
*/
|
|
6780
6860
|
const GENERIC_DRIFT_TOLERANCE_BPS = 10n;
|
|
6861
|
+
/** Delay before resubscribing a substrate module stream that errored: 2s, doubling, capped at 1min */
|
|
6862
|
+
const substrateModuleRetryDelay = (retryCount) => (0, rxjs.timer)(Math.min(6e4, 2e3 * 2 ** (retryCount - 1)));
|
|
6781
6863
|
const DEFAULT_STORAGE = {
|
|
6782
6864
|
balances: [],
|
|
6783
6865
|
miniMetadatas: []
|
|
@@ -6859,7 +6941,7 @@ var BalancesProvider = class {
|
|
|
6859
6941
|
switch (mod.platform) {
|
|
6860
6942
|
case "ethereum": return this.getEthereumNetworkModuleBalances$(networkId, tokensWithAddresses, mod);
|
|
6861
6943
|
case "solana": return this.getSolanaNetworkModuleBalances$(networkId, tokensWithAddresses, mod);
|
|
6862
|
-
case "polkadot": return this.getPolkadotNetworkModuleBalances$(networkId, tokensWithAddresses, mod);
|
|
6944
|
+
case "polkadot": return this.getPolkadotNetworkModuleBalances$(networkId, tokensWithAddresses, mod, (0, _talismn_chaindata_provider.isNetworkDot)(network) && !!network.hasFrontierMirrorWithdraw);
|
|
6863
6945
|
default:
|
|
6864
6946
|
log_default.warn("[balances] Unsupported network platform for module", {
|
|
6865
6947
|
networkId,
|
|
@@ -6884,11 +6966,12 @@ var BalancesProvider = class {
|
|
|
6884
6966
|
};
|
|
6885
6967
|
}, { label: `network balances ${networkId}` }), (0, rxjs.distinctUntilChanged)(isEqualBalancesResult));
|
|
6886
6968
|
}
|
|
6887
|
-
getPolkadotNetworkModuleBalances$(networkId, tokensWithAddresses, mod) {
|
|
6969
|
+
getPolkadotNetworkModuleBalances$(networkId, tokensWithAddresses, mod, hasFrontierMirrorWithdraw) {
|
|
6888
6970
|
return (0, _talismn_util.getSharedObservable)(`BalancesProvider.getPolkadotNetworkModuleBalances$`, {
|
|
6889
6971
|
networkId,
|
|
6890
6972
|
mod,
|
|
6891
|
-
tokensWithAddresses
|
|
6973
|
+
tokensWithAddresses,
|
|
6974
|
+
hasFrontierMirrorWithdraw
|
|
6892
6975
|
}, () => {
|
|
6893
6976
|
if (!tokensWithAddresses.length) return (0, rxjs.of)({
|
|
6894
6977
|
status: "live",
|
|
@@ -6912,8 +6995,12 @@ var BalancesProvider = class {
|
|
|
6912
6995
|
networkId,
|
|
6913
6996
|
tokensWithAddresses,
|
|
6914
6997
|
connector: this.#chainConnectors.substrate,
|
|
6915
|
-
miniMetadata
|
|
6916
|
-
|
|
6998
|
+
miniMetadata,
|
|
6999
|
+
hasFrontierMirrorWithdraw
|
|
7000
|
+
})), stabilizeModuleResults(mod.type === "substrate-dtao" ? void 0 : classifySmallAmountDrift(GENERIC_DRIFT_TOLERANCE_BPS)), (0, rxjs.retry)({
|
|
7001
|
+
delay: (_error, retryCount) => substrateModuleRetryDelay(retryCount),
|
|
7002
|
+
resetOnSuccess: true
|
|
7003
|
+
}), (0, rxjs.tap)((results) => {
|
|
6917
7004
|
(0, _talismn_util.reportJsActivity)(`module ${mod.type} ${networkId} (${results.success.length})`);
|
|
6918
7005
|
if (results.dynamicTokens?.length) this.#chaindataProvider.registerDynamicTokens(results.dynamicTokens);
|
|
6919
7006
|
}), (0, rxjs.map)((results) => ({
|
|
@@ -7268,6 +7355,7 @@ exports.BalanceValueGetter = BalanceValueGetter;
|
|
|
7268
7355
|
exports.Balances = Balances;
|
|
7269
7356
|
exports.BalancesProvider = BalancesProvider;
|
|
7270
7357
|
exports.Change24hCurrencyFormatter = Change24hCurrencyFormatter;
|
|
7358
|
+
exports.EVM_MIRROR_LOCK_LABEL = EVM_MIRROR_LOCK_LABEL;
|
|
7271
7359
|
exports.EvmErc20BalanceModule = EvmErc20BalanceModule;
|
|
7272
7360
|
exports.EvmErc20TokenConfigSchema = EvmErc20TokenConfigSchema;
|
|
7273
7361
|
exports.EvmNativeBalanceModule = EvmNativeBalanceModule;
|
|
@@ -7320,6 +7408,7 @@ exports.filterMirrorTokens = filterMirrorTokens;
|
|
|
7320
7408
|
exports.findDTaoClaimablePlancks = findDTaoClaimablePlancks;
|
|
7321
7409
|
exports.findDTaoConvictionLock = findDTaoConvictionLock;
|
|
7322
7410
|
exports.findDTaoRootStakeHold = findDTaoRootStakeHold;
|
|
7411
|
+
exports.findEvmMirrorWithdrawable = findEvmMirrorWithdrawable;
|
|
7323
7412
|
exports.getBalanceFingerprint = getBalanceFingerprint;
|
|
7324
7413
|
exports.getBalanceId = getBalanceId;
|
|
7325
7414
|
exports.getBalanceStorageFingerprint = getBalanceStorageFingerprint;
|
|
@@ -7343,6 +7432,7 @@ exports.isEqualBalanceArrays = isEqualBalanceArrays;
|
|
|
7343
7432
|
exports.isEqualBalancesResult = isEqualBalancesResult;
|
|
7344
7433
|
exports.isEqualMiniMetadatas = isEqualMiniMetadatas;
|
|
7345
7434
|
exports.isEqualModuleResults = isEqualModuleResults;
|
|
7435
|
+
exports.isEvmMirrorWithdrawableLock = isEvmMirrorWithdrawableLock;
|
|
7346
7436
|
exports.isNonTransferable = isNonTransferable;
|
|
7347
7437
|
exports.taoToAlpha = taoToAlpha;
|
|
7348
7438
|
exports.taoToAlphaCeil = taoToAlphaCeil;
|