@talismn/balances 0.0.0-pr2136-20250814032256 → 0.0.0-pr2136-20250815050739
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 +0 -1
- package/dist/declarations/src/getMiniMetadatas/getMetadataRpc.d.ts +2 -2
- package/dist/declarations/src/getMiniMetadatas/getSpecVersion.d.ts +2 -2
- package/dist/declarations/src/getMiniMetadatas/index.d.ts +2 -2
- package/dist/declarations/src/modules/index.d.ts +0 -23
- package/dist/declarations/src/modules/shared/errors.d.ts +1 -1
- package/dist/declarations/src/modules/shared/fetchRuntimeCallResult.d.ts +2 -2
- package/dist/declarations/src/modules/shared/rpcQueryPack.d.ts +3 -3
- package/dist/declarations/src/modules/substrate-native/bittensor/getSubtensorStakingBalances.d.ts +2 -2
- package/dist/declarations/src/modules/substrate-native/fetchTokens.d.ts +2 -2
- package/dist/declarations/src/modules/substrate-psp22/util.d.ts +2 -2
- package/dist/declarations/src/types/IBalanceModule.d.ts +19 -26
- package/dist/declarations/src/types/balances.d.ts +4 -52
- package/dist/declarations/src/types/balancetypes.d.ts +4 -0
- package/dist/declarations/src/types/chainConnectors.d.ts +4 -4
- package/dist/talismn-balances.cjs.dev.js +254 -759
- package/dist/talismn-balances.cjs.prod.js +254 -759
- package/dist/talismn-balances.esm.js +246 -747
- package/package.json +8 -13
- package/dist/declarations/src/modules/sol-native/config.d.ts +0 -3
- package/dist/declarations/src/modules/sol-native/fetchBalances.d.ts +0 -3
- package/dist/declarations/src/modules/sol-native/fetchTokens.d.ts +0 -3
- package/dist/declarations/src/modules/sol-native/getMiniMetadata.d.ts +0 -3
- package/dist/declarations/src/modules/sol-native/getTransferCallData.d.ts +0 -3
- package/dist/declarations/src/modules/sol-native/index.d.ts +0 -2
- package/dist/declarations/src/modules/sol-native/module.d.ts +0 -3
- package/dist/declarations/src/modules/sol-native/subscribeBalances.d.ts +0 -3
- package/dist/declarations/src/modules/sol-native/types.d.ts +0 -13
- package/dist/declarations/src/modules/sol-spl/config.d.ts +0 -3
- package/dist/declarations/src/modules/sol-spl/fetchBalances.d.ts +0 -3
- package/dist/declarations/src/modules/sol-spl/fetchTokens.d.ts +0 -3
- package/dist/declarations/src/modules/sol-spl/getMiniMetadata.d.ts +0 -3
- package/dist/declarations/src/modules/sol-spl/getTransferCallData.d.ts +0 -3
- package/dist/declarations/src/modules/sol-spl/index.d.ts +0 -2
- package/dist/declarations/src/modules/sol-spl/module.d.ts +0 -3
- package/dist/declarations/src/modules/sol-spl/subscribeBalances.d.ts +0 -3
- package/dist/declarations/src/modules/sol-spl/types.d.ts +0 -14
@@ -1,18 +1,13 @@
|
|
1
|
-
import { EvmErc20TokenSchema, parseTokenId, parseEvmErc20TokenId, evmErc20TokenId, isTokenOfType, TokenBaseSchema, EvmNativeTokenSchema, evmNativeTokenId, EvmUniswapV2TokenSchema, evmUniswapV2TokenId,
|
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,
|
3
|
+
import { isEthereumAddress, isNotNil, BigMath, isArrayOf, isBigInt, planckToTokens, isAbortError, getSharedObservable, keepAlive, isTruthy, normalizeAddress } from '@talismn/util';
|
4
4
|
import { parseAbi, erc20Abi, getContract, ContractFunctionExecutionError, hexToString, erc20Abi_bytes32, encodeFunctionData, withRetry } from 'viem';
|
5
5
|
import { assign, omit, isEqual, uniq, keyBy, toPairs, keys, fromPairs, values } from 'lodash-es';
|
6
6
|
import z from 'zod/v4';
|
7
7
|
import anylogger from 'anylogger';
|
8
8
|
import { of, Observable, distinctUntilChanged, map, timer, switchMap, from, firstValueFrom, combineLatest, BehaviorSubject, shareReplay, startWith, filter, defer, catchError, EMPTY, tap } from 'rxjs';
|
9
9
|
import BigNumber from 'bignumber.js';
|
10
|
-
import { PublicKey, SystemProgram } from '@solana/web3.js';
|
11
|
-
import { isNotNil, BigMath, isArrayOf, isBigInt, planckToTokens, isAbortError, getSharedObservable, keepAlive, isTruthy } from '@talismn/util';
|
12
10
|
import { parseMetadataRpc, toHex, unifyMetadata, decAnyMetadata, getDynamicBuilder, getLookupFn, decodeScale, getStorageKeyPrefix, Twox128, compactMetadata, encodeMetadata, papiParse, papiStringify } from '@talismn/scale';
|
13
|
-
import { deserializeMetadata } from '@metaplex-foundation/mpl-token-metadata';
|
14
|
-
import { sol, publicKey } from '@metaplex-foundation/umi';
|
15
|
-
import { MintLayout, getAssociatedTokenAddress, createAssociatedTokenAccountInstruction, createTransferInstruction, TOKEN_PROGRAM_ID, getAccount } from '@solana/spl-token';
|
16
11
|
import { newTokenRates } from '@talismn/token-rates';
|
17
12
|
import { mergeUint8 } from '@polkadot-api/utils';
|
18
13
|
import { Binary, Enum, AccountId } from 'polkadot-api';
|
@@ -24,8 +19,8 @@ import { u8aToHex, u8aConcatStrict, u8aToString, hexToNumber } from '@polkadot/u
|
|
24
19
|
import PQueue from 'p-queue';
|
25
20
|
import { fetchBestMetadata } from '@talismn/sapi';
|
26
21
|
|
27
|
-
const MODULE_TYPE$
|
28
|
-
const PLATFORM$
|
22
|
+
const MODULE_TYPE$8 = EvmErc20TokenSchema.shape.type.value;
|
23
|
+
const PLATFORM$8 = EvmErc20TokenSchema.shape.platform.value;
|
29
24
|
|
30
25
|
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)"]);
|
31
26
|
|
@@ -621,7 +616,7 @@ const getBalanceDefs = addressesByToken => {
|
|
621
616
|
// if there is at least one storage entry, the results will be an array with a single object
|
622
617
|
// if the storage has no entries in it (ex: Assets on ewx or moonbeam), the response will be an empty array
|
623
618
|
|
624
|
-
const fetchBalances$
|
619
|
+
const fetchBalances$8 = async ({
|
625
620
|
networkId,
|
626
621
|
tokensWithAddresses,
|
627
622
|
connector
|
@@ -633,7 +628,7 @@ const fetchBalances$a = async ({
|
|
633
628
|
const client = await connector.getPublicClientForEvmNetwork(networkId);
|
634
629
|
if (!client) throw new Error(`Could not get rpc provider for evm network ${networkId}`);
|
635
630
|
for (const [token, addresses] of tokensWithAddresses) {
|
636
|
-
if (token.type !== MODULE_TYPE$
|
631
|
+
if (token.type !== MODULE_TYPE$8 || token.networkId !== networkId) throw new Error(`Invalid token type or networkId for EVM ERC20 balance module: ${token.type} on ${token.networkId}`);
|
637
632
|
for (const address of addresses) if (!isEthereumAddress(address)) throw new Error(`Invalid ethereum address for EVM ERC20 balance module: ${address} for token ${token.id}`);
|
638
633
|
}
|
639
634
|
const balanceDefs = getBalanceDefs(tokensWithAddresses);
|
@@ -663,7 +658,7 @@ const fetchWithoutAggregator = async (client, balanceDefs) => {
|
|
663
658
|
address,
|
664
659
|
tokenId: token.id,
|
665
660
|
value: result.toString(),
|
666
|
-
source: MODULE_TYPE$
|
661
|
+
source: MODULE_TYPE$8,
|
667
662
|
networkId: parseEvmErc20TokenId(token.id).networkId,
|
668
663
|
status: "live"
|
669
664
|
};
|
@@ -706,7 +701,7 @@ const fetchWithAggregator = async (client, balanceDefs, erc20BalancesAggregatorA
|
|
706
701
|
address: balanceDef.address,
|
707
702
|
tokenId: balanceDef.token.id,
|
708
703
|
value: erc20Balances[index].toString(),
|
709
|
-
source: MODULE_TYPE$
|
704
|
+
source: MODULE_TYPE$8,
|
710
705
|
networkId: parseTokenId(balanceDef.token.id).networkId,
|
711
706
|
status: "live"
|
712
707
|
}));
|
@@ -763,7 +758,7 @@ const getTypedContract$1 = (client, abi, contractAddress) => getContract({
|
|
763
758
|
}
|
764
759
|
});
|
765
760
|
|
766
|
-
const TokenCacheSchema$
|
761
|
+
const TokenCacheSchema$1 = z.discriminatedUnion("isValid", [z.strictObject({
|
767
762
|
id: EvmErc20TokenSchema.shape.id,
|
768
763
|
isValid: z.literal(true),
|
769
764
|
...EvmErc20TokenSchema.pick({
|
@@ -775,7 +770,7 @@ const TokenCacheSchema$2 = z.discriminatedUnion("isValid", [z.strictObject({
|
|
775
770
|
id: EvmErc20TokenSchema.shape.id,
|
776
771
|
isValid: z.literal(false)
|
777
772
|
})]);
|
778
|
-
const fetchTokens$
|
773
|
+
const fetchTokens$8 = async ({
|
779
774
|
networkId,
|
780
775
|
tokens,
|
781
776
|
connector,
|
@@ -784,7 +779,7 @@ const fetchTokens$a = async ({
|
|
784
779
|
const result = [];
|
785
780
|
for (const tokenConfig of tokens) {
|
786
781
|
const tokenId = evmErc20TokenId(networkId, tokenConfig.contractAddress);
|
787
|
-
const cached = cache[tokenId] && TokenCacheSchema$
|
782
|
+
const cached = cache[tokenId] && TokenCacheSchema$1.safeParse(cache[tokenId]).data;
|
788
783
|
if (!cached) {
|
789
784
|
const client = await connector.getPublicClientForEvmNetwork(networkId);
|
790
785
|
if (!client) {
|
@@ -797,7 +792,7 @@ const fetchTokens$a = async ({
|
|
797
792
|
decimals,
|
798
793
|
symbol
|
799
794
|
} = await getErc20ContractData$1(client, tokenConfig.contractAddress);
|
800
|
-
cache[tokenId] = TokenCacheSchema$
|
795
|
+
cache[tokenId] = TokenCacheSchema$1.parse({
|
801
796
|
id: tokenId,
|
802
797
|
symbol,
|
803
798
|
decimals,
|
@@ -815,11 +810,11 @@ const fetchTokens$a = async ({
|
|
815
810
|
}
|
816
811
|
const base = {
|
817
812
|
id: tokenId,
|
818
|
-
type: MODULE_TYPE$
|
819
|
-
platform: PLATFORM$
|
813
|
+
type: MODULE_TYPE$8,
|
814
|
+
platform: PLATFORM$8,
|
820
815
|
networkId
|
821
816
|
};
|
822
|
-
const cached2 = cache[tokenId] && TokenCacheSchema$
|
817
|
+
const cached2 = cache[tokenId] && TokenCacheSchema$1.safeParse(cache[tokenId]).data;
|
823
818
|
if (cached2?.isValid === false) continue;
|
824
819
|
const token = assign(base, cached2?.isValid ? omit(cached2, ["isValid"]) : {}, tokenConfig);
|
825
820
|
const parsed = EvmErc20TokenSchema.safeParse(token);
|
@@ -834,17 +829,17 @@ const fetchTokens$a = async ({
|
|
834
829
|
return result;
|
835
830
|
};
|
836
831
|
|
837
|
-
const getMiniMetadata$
|
832
|
+
const getMiniMetadata$8 = () => {
|
838
833
|
throw new Error("MiniMetadata is not supported for ethereum tokens");
|
839
834
|
};
|
840
835
|
|
841
|
-
const getTransferCallData$
|
836
|
+
const getTransferCallData$8 = ({
|
842
837
|
from,
|
843
838
|
to,
|
844
839
|
value,
|
845
840
|
token
|
846
841
|
}) => {
|
847
|
-
if (!isTokenOfType(token, MODULE_TYPE$
|
842
|
+
if (!isTokenOfType(token, MODULE_TYPE$8)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$8}.`);
|
848
843
|
if (!isEthereumAddress(from)) throw new Error("Invalid from address");
|
849
844
|
if (!isEthereumAddress(to)) throw new Error("Invalid to address");
|
850
845
|
const data = encodeFunctionData({
|
@@ -859,8 +854,8 @@ const getTransferCallData$a = ({
|
|
859
854
|
};
|
860
855
|
};
|
861
856
|
|
862
|
-
const SUBSCRIPTION_INTERVAL$
|
863
|
-
const subscribeBalances$
|
857
|
+
const SUBSCRIPTION_INTERVAL$4 = 6_000;
|
858
|
+
const subscribeBalances$8 = ({
|
864
859
|
networkId,
|
865
860
|
tokensWithAddresses,
|
866
861
|
connector
|
@@ -874,17 +869,17 @@ const subscribeBalances$a = ({
|
|
874
869
|
const poll = async () => {
|
875
870
|
try {
|
876
871
|
if (abortController.signal.aborted) return;
|
877
|
-
const balances = await fetchBalances$
|
872
|
+
const balances = await fetchBalances$8({
|
878
873
|
networkId,
|
879
874
|
tokensWithAddresses: tokensWithAddresses,
|
880
875
|
connector
|
881
876
|
});
|
882
877
|
if (abortController.signal.aborted) return;
|
883
878
|
subscriber.next(balances);
|
884
|
-
setTimeout(poll, SUBSCRIPTION_INTERVAL$
|
879
|
+
setTimeout(poll, SUBSCRIPTION_INTERVAL$4);
|
885
880
|
} catch (error) {
|
886
881
|
log.error("Error", {
|
887
|
-
module: MODULE_TYPE$
|
882
|
+
module: MODULE_TYPE$8,
|
888
883
|
networkId,
|
889
884
|
addressesByToken: tokensWithAddresses,
|
890
885
|
error
|
@@ -900,13 +895,13 @@ const subscribeBalances$a = ({
|
|
900
895
|
};
|
901
896
|
|
902
897
|
const EvmErc20BalanceModule = {
|
903
|
-
type: MODULE_TYPE$
|
904
|
-
platform: PLATFORM$
|
905
|
-
getMiniMetadata: getMiniMetadata$
|
906
|
-
fetchTokens: fetchTokens$
|
907
|
-
fetchBalances: fetchBalances$
|
908
|
-
subscribeBalances: subscribeBalances$
|
909
|
-
getTransferCallData: getTransferCallData$
|
898
|
+
type: MODULE_TYPE$8,
|
899
|
+
platform: PLATFORM$8,
|
900
|
+
getMiniMetadata: getMiniMetadata$8,
|
901
|
+
fetchTokens: fetchTokens$8,
|
902
|
+
fetchBalances: fetchBalances$8,
|
903
|
+
subscribeBalances: subscribeBalances$8,
|
904
|
+
getTransferCallData: getTransferCallData$8
|
910
905
|
};
|
911
906
|
|
912
907
|
const TokenConfigBaseSchema = TokenBaseSchema.partial().omit({
|
@@ -919,10 +914,10 @@ const EvmErc20TokenConfigSchema = z.strictObject({
|
|
919
914
|
...TokenConfigBaseSchema.shape
|
920
915
|
});
|
921
916
|
|
922
|
-
const MODULE_TYPE$
|
923
|
-
const PLATFORM$
|
917
|
+
const MODULE_TYPE$7 = EvmNativeTokenSchema.shape.type.value;
|
918
|
+
const PLATFORM$7 = EvmNativeTokenSchema.shape.platform.value;
|
924
919
|
|
925
|
-
const fetchBalances$
|
920
|
+
const fetchBalances$7 = async ({
|
926
921
|
networkId,
|
927
922
|
tokensWithAddresses,
|
928
923
|
connector
|
@@ -934,7 +929,7 @@ const fetchBalances$9 = async ({
|
|
934
929
|
const client = await connector.getPublicClientForEvmNetwork(networkId);
|
935
930
|
if (!client) throw new Error(`Could not get rpc provider for evm network ${networkId}`);
|
936
931
|
for (const [token, addresses] of tokensWithAddresses) {
|
937
|
-
if (token.type !== MODULE_TYPE$
|
932
|
+
if (token.type !== MODULE_TYPE$7 || token.networkId !== networkId) throw new Error(`Invalid token type or networkId for EVM ERC20 balance module: ${token.type} on ${token.networkId}`);
|
938
933
|
for (const address of addresses) if (!isEthereumAddress(address)) throw new Error(`Invalid ethereum address for EVM ERC20 balance module: ${address} for token ${token.id}`);
|
939
934
|
}
|
940
935
|
const balanceDefs = getBalanceDefs(tokensWithAddresses);
|
@@ -961,7 +956,7 @@ const fetchWithoutMulticall = async (client, balanceDefs) => {
|
|
961
956
|
address,
|
962
957
|
tokenId: token.id,
|
963
958
|
value: result.toString(),
|
964
|
-
source: MODULE_TYPE$
|
959
|
+
source: MODULE_TYPE$7,
|
965
960
|
networkId: parseTokenId(token.id).networkId,
|
966
961
|
status: "live"
|
967
962
|
};
|
@@ -1007,7 +1002,7 @@ const fetchWithMulticall = async (client, balanceDefs, multicall3Address) => {
|
|
1007
1002
|
address: balanceDefs[index].address,
|
1008
1003
|
tokenId: balanceDefs[index].token.id,
|
1009
1004
|
value: result.result.toString(),
|
1010
|
-
source: MODULE_TYPE$
|
1005
|
+
source: MODULE_TYPE$7,
|
1011
1006
|
networkId: parseTokenId(balanceDefs[index].token.id).networkId,
|
1012
1007
|
status: "live"
|
1013
1008
|
});
|
@@ -1037,7 +1032,7 @@ const fetchWithMulticall = async (client, balanceDefs, multicall3Address) => {
|
|
1037
1032
|
}
|
1038
1033
|
};
|
1039
1034
|
|
1040
|
-
const fetchTokens$
|
1035
|
+
const fetchTokens$7 = async ({
|
1041
1036
|
networkId,
|
1042
1037
|
tokens
|
1043
1038
|
}) => {
|
@@ -1045,8 +1040,8 @@ const fetchTokens$9 = async ({
|
|
1045
1040
|
if (tokens.length !== 1) throw new Error("EVM Native module expects the nativeCurrency to be passed as a single token in the array");
|
1046
1041
|
const token = assign({
|
1047
1042
|
id: evmNativeTokenId(networkId),
|
1048
|
-
type: MODULE_TYPE$
|
1049
|
-
platform: PLATFORM$
|
1043
|
+
type: MODULE_TYPE$7,
|
1044
|
+
platform: PLATFORM$7,
|
1050
1045
|
networkId,
|
1051
1046
|
isDefault: true
|
1052
1047
|
}, tokens[0]);
|
@@ -1058,17 +1053,17 @@ const fetchTokens$9 = async ({
|
|
1058
1053
|
return [parsed.data];
|
1059
1054
|
};
|
1060
1055
|
|
1061
|
-
const getMiniMetadata$
|
1056
|
+
const getMiniMetadata$7 = () => {
|
1062
1057
|
throw new Error("MiniMetadata is not supported for ethereum tokens");
|
1063
1058
|
};
|
1064
1059
|
|
1065
|
-
const getTransferCallData$
|
1060
|
+
const getTransferCallData$7 = ({
|
1066
1061
|
from,
|
1067
1062
|
to,
|
1068
1063
|
value,
|
1069
1064
|
token
|
1070
1065
|
}) => {
|
1071
|
-
if (!isTokenOfType(token, MODULE_TYPE$
|
1066
|
+
if (!isTokenOfType(token, MODULE_TYPE$7)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$7}.`);
|
1072
1067
|
if (!isEthereumAddress(from)) throw new Error("Invalid from address");
|
1073
1068
|
if (!isEthereumAddress(to)) throw new Error("Invalid to address");
|
1074
1069
|
return {
|
@@ -1079,8 +1074,8 @@ const getTransferCallData$9 = ({
|
|
1079
1074
|
};
|
1080
1075
|
};
|
1081
1076
|
|
1082
|
-
const SUBSCRIPTION_INTERVAL$
|
1083
|
-
const subscribeBalances$
|
1077
|
+
const SUBSCRIPTION_INTERVAL$3 = 6_000;
|
1078
|
+
const subscribeBalances$7 = ({
|
1084
1079
|
networkId,
|
1085
1080
|
tokensWithAddresses,
|
1086
1081
|
connector
|
@@ -1094,17 +1089,17 @@ const subscribeBalances$9 = ({
|
|
1094
1089
|
const poll = async () => {
|
1095
1090
|
try {
|
1096
1091
|
if (abortController.signal.aborted) return;
|
1097
|
-
const balances = await fetchBalances$
|
1092
|
+
const balances = await fetchBalances$7({
|
1098
1093
|
networkId,
|
1099
1094
|
tokensWithAddresses: tokensWithAddresses,
|
1100
1095
|
connector
|
1101
1096
|
});
|
1102
1097
|
if (abortController.signal.aborted) return;
|
1103
1098
|
subscriber.next(balances);
|
1104
|
-
setTimeout(poll, SUBSCRIPTION_INTERVAL$
|
1099
|
+
setTimeout(poll, SUBSCRIPTION_INTERVAL$3);
|
1105
1100
|
} catch (error) {
|
1106
1101
|
log.error("Error", {
|
1107
|
-
module: MODULE_TYPE$
|
1102
|
+
module: MODULE_TYPE$7,
|
1108
1103
|
networkId,
|
1109
1104
|
addressesByToken: tokensWithAddresses,
|
1110
1105
|
error
|
@@ -1120,13 +1115,13 @@ const subscribeBalances$9 = ({
|
|
1120
1115
|
};
|
1121
1116
|
|
1122
1117
|
const EvmNativeBalanceModule = {
|
1123
|
-
type: MODULE_TYPE$
|
1124
|
-
platform: PLATFORM$
|
1125
|
-
getMiniMetadata: getMiniMetadata$
|
1126
|
-
fetchTokens: fetchTokens$
|
1127
|
-
fetchBalances: fetchBalances$
|
1128
|
-
subscribeBalances: subscribeBalances$
|
1129
|
-
getTransferCallData: getTransferCallData$
|
1118
|
+
type: MODULE_TYPE$7,
|
1119
|
+
platform: PLATFORM$7,
|
1120
|
+
getMiniMetadata: getMiniMetadata$7,
|
1121
|
+
fetchTokens: fetchTokens$7,
|
1122
|
+
fetchBalances: fetchBalances$7,
|
1123
|
+
subscribeBalances: subscribeBalances$7,
|
1124
|
+
getTransferCallData: getTransferCallData$7
|
1130
1125
|
};
|
1131
1126
|
|
1132
1127
|
// to be used by chaindata too
|
@@ -1134,10 +1129,10 @@ const EvmNativeTokenConfigSchema = z.strictObject({
|
|
1134
1129
|
...TokenConfigBaseSchema.shape
|
1135
1130
|
});
|
1136
1131
|
|
1137
|
-
const MODULE_TYPE$
|
1138
|
-
const PLATFORM$
|
1132
|
+
const MODULE_TYPE$6 = EvmUniswapV2TokenSchema.shape.type.value;
|
1133
|
+
const PLATFORM$6 = EvmUniswapV2TokenSchema.shape.platform.value;
|
1139
1134
|
|
1140
|
-
const fetchBalances$
|
1135
|
+
const fetchBalances$6 = async ({
|
1141
1136
|
networkId,
|
1142
1137
|
tokensWithAddresses,
|
1143
1138
|
connector
|
@@ -1149,7 +1144,7 @@ const fetchBalances$8 = async ({
|
|
1149
1144
|
const client = await connector.getPublicClientForEvmNetwork(networkId);
|
1150
1145
|
if (!client) throw new Error(`Could not get rpc provider for evm network ${networkId}`);
|
1151
1146
|
for (const [token, addresses] of tokensWithAddresses) {
|
1152
|
-
if (token.type !== MODULE_TYPE$
|
1147
|
+
if (token.type !== MODULE_TYPE$6 || token.networkId !== networkId) throw new Error(`Invalid token type or networkId for EVM ERC20 balance module: ${token.type} on ${token.networkId}`);
|
1153
1148
|
for (const address of addresses) if (!isEthereumAddress(address)) throw new Error(`Invalid ethereum address for EVM ERC20 balance module: ${address} for token ${token.id}`);
|
1154
1149
|
}
|
1155
1150
|
const balanceDefs = getBalanceDefs(tokensWithAddresses);
|
@@ -1236,7 +1231,7 @@ const fetchPoolBalances = async (client, balanceDefs) => {
|
|
1236
1231
|
acc.success.push({
|
1237
1232
|
address,
|
1238
1233
|
tokenId: token.id,
|
1239
|
-
source: MODULE_TYPE$
|
1234
|
+
source: MODULE_TYPE$6,
|
1240
1235
|
networkId: parseTokenId(token.id).networkId,
|
1241
1236
|
status: "live",
|
1242
1237
|
values: [{
|
@@ -1296,7 +1291,7 @@ const getUniswapV2PairContractData = async (client, contractAddress) => {
|
|
1296
1291
|
};
|
1297
1292
|
};
|
1298
1293
|
|
1299
|
-
const TokenCacheSchema
|
1294
|
+
const TokenCacheSchema = z.discriminatedUnion("isValid", [z.strictObject({
|
1300
1295
|
id: EvmUniswapV2TokenSchema.shape.id,
|
1301
1296
|
isValid: z.literal(true),
|
1302
1297
|
...EvmUniswapV2TokenSchema.pick({
|
@@ -1314,7 +1309,7 @@ const TokenCacheSchema$1 = z.discriminatedUnion("isValid", [z.strictObject({
|
|
1314
1309
|
id: EvmUniswapV2TokenSchema.shape.id,
|
1315
1310
|
isValid: z.literal(false)
|
1316
1311
|
})]);
|
1317
|
-
const fetchTokens$
|
1312
|
+
const fetchTokens$6 = async ({
|
1318
1313
|
networkId,
|
1319
1314
|
tokens,
|
1320
1315
|
connector,
|
@@ -1323,7 +1318,7 @@ const fetchTokens$8 = async ({
|
|
1323
1318
|
const result = [];
|
1324
1319
|
for (const tokenConfig of tokens) {
|
1325
1320
|
const tokenId = evmUniswapV2TokenId(networkId, tokenConfig.contractAddress);
|
1326
|
-
const cached = cache[tokenId] && TokenCacheSchema
|
1321
|
+
const cached = cache[tokenId] && TokenCacheSchema.safeParse(cache[tokenId]).data;
|
1327
1322
|
if (!cached) {
|
1328
1323
|
const client = await connector.getPublicClientForEvmNetwork(networkId);
|
1329
1324
|
if (!client) {
|
@@ -1345,7 +1340,7 @@ const fetchTokens$8 = async ({
|
|
1345
1340
|
symbol: symbol1,
|
1346
1341
|
decimals: decimals1
|
1347
1342
|
} = await getErc20ContractData(client, token1);
|
1348
|
-
cache[tokenId] = TokenCacheSchema
|
1343
|
+
cache[tokenId] = TokenCacheSchema.parse({
|
1349
1344
|
id: tokenId,
|
1350
1345
|
symbol: `${symbol0}/${symbol1}`,
|
1351
1346
|
decimals,
|
@@ -1363,609 +1358,56 @@ const fetchTokens$8 = async ({
|
|
1363
1358
|
if (msg.includes("returned no data") || msg.includes("is out of bounds") || msg.includes("reverted")) {
|
1364
1359
|
cache[tokenId] = {
|
1365
1360
|
id: tokenId,
|
1366
|
-
isValid: false
|
1367
|
-
};
|
1368
|
-
} else {
|
1369
|
-
log.warn(`Failed to fetch UniswapV2 token data for ${tokenConfig.contractAddress}`, err.shortMessage);
|
1370
|
-
}
|
1371
|
-
continue;
|
1372
|
-
}
|
1373
|
-
}
|
1374
|
-
const base = {
|
1375
|
-
id: tokenId,
|
1376
|
-
type: MODULE_TYPE$8,
|
1377
|
-
platform: PLATFORM$8,
|
1378
|
-
networkId
|
1379
|
-
};
|
1380
|
-
const cached2 = cache[tokenId] && TokenCacheSchema$1.safeParse(cache[tokenId]).data;
|
1381
|
-
if (cached2?.isValid === false) continue;
|
1382
|
-
const token = assign(base, cached2?.isValid ? omit(cached2, ["isValid"]) : {}, tokenConfig);
|
1383
|
-
const parsed = EvmUniswapV2TokenSchema.safeParse(token);
|
1384
|
-
if (!parsed.success) {
|
1385
|
-
log.warn("Ignoring token with invalid schema", token);
|
1386
|
-
continue;
|
1387
|
-
}
|
1388
|
-
result.push(parsed.data);
|
1389
|
-
}
|
1390
|
-
return result;
|
1391
|
-
};
|
1392
|
-
|
1393
|
-
const getMiniMetadata$8 = () => {
|
1394
|
-
throw new Error("MiniMetadata is not supported for ethereum tokens");
|
1395
|
-
};
|
1396
|
-
|
1397
|
-
const getTransferCallData$8 = ({
|
1398
|
-
from,
|
1399
|
-
to,
|
1400
|
-
value,
|
1401
|
-
token
|
1402
|
-
}) => {
|
1403
|
-
if (!isTokenOfType(token, MODULE_TYPE$8)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$8}.`);
|
1404
|
-
if (!isEthereumAddress(from)) throw new Error("Invalid from address");
|
1405
|
-
if (!isEthereumAddress(to)) throw new Error("Invalid to address");
|
1406
|
-
const data = encodeFunctionData({
|
1407
|
-
abi: erc20Abi,
|
1408
|
-
functionName: "transfer",
|
1409
|
-
args: [to, BigInt(value)]
|
1410
|
-
});
|
1411
|
-
return {
|
1412
|
-
from,
|
1413
|
-
to: token.contractAddress,
|
1414
|
-
data
|
1415
|
-
};
|
1416
|
-
};
|
1417
|
-
|
1418
|
-
const SUBSCRIPTION_INTERVAL$4 = 6_000;
|
1419
|
-
const subscribeBalances$8 = ({
|
1420
|
-
networkId,
|
1421
|
-
tokensWithAddresses,
|
1422
|
-
connector
|
1423
|
-
}) => {
|
1424
|
-
if (!tokensWithAddresses.length) return of({
|
1425
|
-
success: [],
|
1426
|
-
errors: []
|
1427
|
-
});
|
1428
|
-
return new Observable(subscriber => {
|
1429
|
-
const abortController = new AbortController();
|
1430
|
-
const poll = async () => {
|
1431
|
-
try {
|
1432
|
-
if (abortController.signal.aborted) return;
|
1433
|
-
const balances = await fetchBalances$8({
|
1434
|
-
networkId,
|
1435
|
-
tokensWithAddresses: tokensWithAddresses,
|
1436
|
-
connector
|
1437
|
-
});
|
1438
|
-
if (abortController.signal.aborted) return;
|
1439
|
-
subscriber.next(balances);
|
1440
|
-
setTimeout(poll, SUBSCRIPTION_INTERVAL$4);
|
1441
|
-
} catch (error) {
|
1442
|
-
log.error("Error", {
|
1443
|
-
module: MODULE_TYPE$8,
|
1444
|
-
networkId,
|
1445
|
-
addressesByToken: tokensWithAddresses,
|
1446
|
-
error
|
1447
|
-
});
|
1448
|
-
subscriber.error(error);
|
1449
|
-
}
|
1450
|
-
};
|
1451
|
-
poll();
|
1452
|
-
return () => {
|
1453
|
-
abortController.abort();
|
1454
|
-
};
|
1455
|
-
}).pipe(distinctUntilChanged(isEqual));
|
1456
|
-
};
|
1457
|
-
|
1458
|
-
const EvmUniswapV2BalanceModule = {
|
1459
|
-
type: MODULE_TYPE$8,
|
1460
|
-
platform: PLATFORM$8,
|
1461
|
-
getMiniMetadata: getMiniMetadata$8,
|
1462
|
-
fetchTokens: fetchTokens$8,
|
1463
|
-
fetchBalances: fetchBalances$8,
|
1464
|
-
subscribeBalances: subscribeBalances$8,
|
1465
|
-
getTransferCallData: getTransferCallData$8
|
1466
|
-
};
|
1467
|
-
|
1468
|
-
// to be used by chaindata too
|
1469
|
-
const EvmUniswapV2TokenConfigSchema = z.strictObject({
|
1470
|
-
contractAddress: EvmUniswapV2TokenSchema.shape.contractAddress,
|
1471
|
-
...TokenConfigBaseSchema.shape
|
1472
|
-
});
|
1473
|
-
|
1474
|
-
const MODULE_TYPE$7 = SolNativeTokenSchema.shape.type.value;
|
1475
|
-
const PLATFORM$7 = SolNativeTokenSchema.shape.platform.value;
|
1476
|
-
|
1477
|
-
const fetchBalances$7 = async ({
|
1478
|
-
networkId,
|
1479
|
-
tokensWithAddresses,
|
1480
|
-
connector
|
1481
|
-
}) => {
|
1482
|
-
if (!tokensWithAddresses.length) return {
|
1483
|
-
success: [],
|
1484
|
-
errors: []
|
1485
|
-
};
|
1486
|
-
const connection = await connector.getConnection(networkId);
|
1487
|
-
if (!connection) throw new Error(`Could not get rpc provider for sol network ${networkId}`);
|
1488
|
-
for (const [token, addresses] of tokensWithAddresses) {
|
1489
|
-
if (token.type !== MODULE_TYPE$7 || token.networkId !== networkId) throw new Error(`Invalid token type or networkId for balance module: ${token.type} on ${token.networkId}`);
|
1490
|
-
for (const address of addresses) if (!isSolanaAddress(address)) throw new Error(`Invalid solana address for balance module: ${address} for token ${token.id}`);
|
1491
|
-
}
|
1492
|
-
const balanceDefs = getBalanceDefs(tokensWithAddresses);
|
1493
|
-
const results = await Promise.allSettled(balanceDefs.map(async ({
|
1494
|
-
token,
|
1495
|
-
address
|
1496
|
-
}) => {
|
1497
|
-
try {
|
1498
|
-
const publicKey = new PublicKey(address);
|
1499
|
-
const lamports = await connection.getBalance(publicKey);
|
1500
|
-
return {
|
1501
|
-
address: address,
|
1502
|
-
tokenId: token.id,
|
1503
|
-
value: lamports.toString(),
|
1504
|
-
source: MODULE_TYPE$7,
|
1505
|
-
networkId: token.networkId,
|
1506
|
-
status: "live"
|
1507
|
-
};
|
1508
|
-
} catch (err) {
|
1509
|
-
throw new BalanceFetchError(`Failed to get balance for token ${token.id} and address ${address} on chain ${networkId}`, token.id, address, err);
|
1510
|
-
}
|
1511
|
-
}));
|
1512
|
-
return results.reduce((acc, result) => {
|
1513
|
-
if (result.status === "fulfilled") acc.success.push(result.value);else {
|
1514
|
-
const error = result.reason;
|
1515
|
-
acc.errors.push({
|
1516
|
-
tokenId: error.tokenId,
|
1517
|
-
address: error.address,
|
1518
|
-
error
|
1519
|
-
});
|
1520
|
-
}
|
1521
|
-
return acc;
|
1522
|
-
}, {
|
1523
|
-
success: [],
|
1524
|
-
errors: []
|
1525
|
-
});
|
1526
|
-
};
|
1527
|
-
|
1528
|
-
const fetchTokens$7 = async ({
|
1529
|
-
networkId,
|
1530
|
-
tokens
|
1531
|
-
}) => {
|
1532
|
-
// assume there is one and only one token in the array
|
1533
|
-
if (tokens.length !== 1) throw new Error("EVM Native module expects the nativeCurrency to be passed as a single token in the array");
|
1534
|
-
const token = assign({
|
1535
|
-
id: solNativeTokenId(networkId),
|
1536
|
-
type: MODULE_TYPE$7,
|
1537
|
-
platform: PLATFORM$7,
|
1538
|
-
networkId,
|
1539
|
-
isDefault: true
|
1540
|
-
}, tokens[0]);
|
1541
|
-
const parsed = SolNativeTokenSchema.safeParse(token);
|
1542
|
-
if (!parsed.success) {
|
1543
|
-
log.warn("Ignoring token with invalid schema", token);
|
1544
|
-
return [];
|
1545
|
-
}
|
1546
|
-
return [parsed.data];
|
1547
|
-
};
|
1548
|
-
|
1549
|
-
const getMiniMetadata$7 = () => {
|
1550
|
-
throw new Error("MiniMetadata is not supported for sol-native tokens");
|
1551
|
-
};
|
1552
|
-
|
1553
|
-
const getTransferCallData$7 = ({
|
1554
|
-
from,
|
1555
|
-
to,
|
1556
|
-
value,
|
1557
|
-
token
|
1558
|
-
}) => {
|
1559
|
-
if (!isTokenOfType(token, MODULE_TYPE$7)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$7}.`);
|
1560
|
-
const fromPubkey = new PublicKey(from);
|
1561
|
-
const transferIx = SystemProgram.transfer({
|
1562
|
-
fromPubkey,
|
1563
|
-
toPubkey: new PublicKey(to),
|
1564
|
-
lamports: Number(value)
|
1565
|
-
});
|
1566
|
-
return [transferIx];
|
1567
|
-
};
|
1568
|
-
|
1569
|
-
const SUBSCRIPTION_INTERVAL$3 = 6_000;
|
1570
|
-
const subscribeBalances$7 = ({
|
1571
|
-
networkId,
|
1572
|
-
tokensWithAddresses,
|
1573
|
-
connector
|
1574
|
-
}) => {
|
1575
|
-
if (!tokensWithAddresses.length) return of({
|
1576
|
-
success: [],
|
1577
|
-
errors: []
|
1578
|
-
});
|
1579
|
-
return new Observable(subscriber => {
|
1580
|
-
const abortController = new AbortController();
|
1581
|
-
const poll = async () => {
|
1582
|
-
try {
|
1583
|
-
if (abortController.signal.aborted) return;
|
1584
|
-
const balances = await fetchBalances$7({
|
1585
|
-
networkId,
|
1586
|
-
tokensWithAddresses,
|
1587
|
-
connector
|
1588
|
-
});
|
1589
|
-
if (abortController.signal.aborted) return;
|
1590
|
-
subscriber.next(balances);
|
1591
|
-
setTimeout(poll, SUBSCRIPTION_INTERVAL$3);
|
1592
|
-
} catch (error) {
|
1593
|
-
log.error("Error", {
|
1594
|
-
module: MODULE_TYPE$7,
|
1595
|
-
networkId,
|
1596
|
-
tokensWithAddresses,
|
1597
|
-
error
|
1598
|
-
});
|
1599
|
-
subscriber.error(error);
|
1600
|
-
}
|
1601
|
-
};
|
1602
|
-
poll();
|
1603
|
-
return () => {
|
1604
|
-
abortController.abort();
|
1605
|
-
};
|
1606
|
-
}).pipe(distinctUntilChanged(isEqual));
|
1607
|
-
};
|
1608
|
-
|
1609
|
-
const SolNativeBalanceModule = {
|
1610
|
-
type: MODULE_TYPE$7,
|
1611
|
-
platform: PLATFORM$7,
|
1612
|
-
getMiniMetadata: getMiniMetadata$7,
|
1613
|
-
fetchTokens: fetchTokens$7,
|
1614
|
-
fetchBalances: fetchBalances$7,
|
1615
|
-
subscribeBalances: subscribeBalances$7,
|
1616
|
-
getTransferCallData: getTransferCallData$7
|
1617
|
-
};
|
1618
|
-
|
1619
|
-
// to be used by chaindata too
|
1620
|
-
const SolNativeTokenConfigSchema = z.strictObject({
|
1621
|
-
...TokenConfigBaseSchema.shape
|
1622
|
-
});
|
1623
|
-
|
1624
|
-
const MODULE_TYPE$6 = SolSplTokenSchema.shape.type.value;
|
1625
|
-
const PLATFORM$6 = SolSplTokenSchema.shape.platform.value;
|
1626
|
-
|
1627
|
-
const fetchRuntimeCallResult = async (connector, networkId, metadataRpc, apiName, method, args) => {
|
1628
|
-
const {
|
1629
|
-
builder
|
1630
|
-
} = parseMetadataRpc(metadataRpc);
|
1631
|
-
const call = builder.buildRuntimeCall(apiName, method);
|
1632
|
-
const hex = await connector.send(networkId, "state_call", [`${apiName}_${method}`, toHex(call.args.enc(args))]);
|
1633
|
-
return call.value.dec(hex);
|
1634
|
-
};
|
1635
|
-
|
1636
|
-
const hasStorageItem = (metadata, palletName, itemName) => {
|
1637
|
-
const pallet = metadata.pallets.find(p => p.name === palletName);
|
1638
|
-
if (!pallet || !pallet.storage) return false;
|
1639
|
-
return pallet.storage.items.some(item => item.name === itemName);
|
1640
|
-
};
|
1641
|
-
const hasStorageItems = (metadata, palletName, itemNames) => {
|
1642
|
-
const pallet = metadata.pallets.find(p => p.name === palletName);
|
1643
|
-
if (!pallet || !pallet.storage) return false;
|
1644
|
-
return itemNames.every(itemName => pallet.storage?.items.some(item => item.name === itemName));
|
1645
|
-
};
|
1646
|
-
const hasRuntimeApi = (metadata, apiName, method) => {
|
1647
|
-
const api = metadata.apis.find(api => api.name === apiName);
|
1648
|
-
if (!api || !api.methods) return false;
|
1649
|
-
return api.methods.some(m => m.name === method);
|
1650
|
-
};
|
1651
|
-
const getConstantValue = (metadataRpc, pallet, constant) => {
|
1652
|
-
const {
|
1653
|
-
unifiedMetadata,
|
1654
|
-
builder
|
1655
|
-
} = parseMetadataRpc(metadataRpc);
|
1656
|
-
const codec = builder.buildConstant(pallet, constant);
|
1657
|
-
const encodedValue = unifiedMetadata.pallets.find(({
|
1658
|
-
name
|
1659
|
-
}) => name === pallet)?.constants.find(({
|
1660
|
-
name
|
1661
|
-
}) => name === constant)?.value;
|
1662
|
-
if (!encodedValue) throw new Error(`Constant ${pallet}.${constant} not found`);
|
1663
|
-
return codec.dec(encodedValue);
|
1664
|
-
};
|
1665
|
-
const tryGetConstantValue = (metadataRpc, pallet, constant) => {
|
1666
|
-
const {
|
1667
|
-
unifiedMetadata,
|
1668
|
-
builder
|
1669
|
-
} = parseMetadataRpc(metadataRpc);
|
1670
|
-
const encodedValue = unifiedMetadata.pallets.find(({
|
1671
|
-
name
|
1672
|
-
}) => name === pallet)?.constants.find(({
|
1673
|
-
name
|
1674
|
-
}) => name === constant)?.value;
|
1675
|
-
if (!encodedValue) return null;
|
1676
|
-
const codec = builder.buildConstant(pallet, constant);
|
1677
|
-
return codec.dec(encodedValue);
|
1678
|
-
};
|
1679
|
-
|
1680
|
-
const fetchRpcQueryPack = async (connector, networkId, queries) => {
|
1681
|
-
const allStateKeys = queries.flatMap(({
|
1682
|
-
stateKeys
|
1683
|
-
}) => stateKeys).filter(isNotNil);
|
1684
|
-
|
1685
|
-
// doing a query without keys would throw an error => return early
|
1686
|
-
if (!allStateKeys.length) return queries.map(({
|
1687
|
-
stateKeys,
|
1688
|
-
decodeResult
|
1689
|
-
}) => decodeResult(stateKeys.map(() => null)));
|
1690
|
-
const [result] = await connector.send(networkId, "state_queryStorageAt", [allStateKeys]);
|
1691
|
-
return decodeRpcQueryPack(queries, result);
|
1692
|
-
};
|
1693
|
-
const getRpcQueryPack$ = (connector, networkId, queries, timeout = false) => {
|
1694
|
-
const allStateKeys = queries.flatMap(({
|
1695
|
-
stateKeys
|
1696
|
-
}) => stateKeys).filter(isNotNil);
|
1697
|
-
|
1698
|
-
// doing a query without keys would throw an error => return early
|
1699
|
-
if (!allStateKeys.length) return of(queries.map(({
|
1700
|
-
stateKeys,
|
1701
|
-
decodeResult
|
1702
|
-
}) => decodeResult(stateKeys.map(() => null))));
|
1703
|
-
return new Observable(subscriber => {
|
1704
|
-
// first subscription callback includes results for all state keys, but further callbacks will only include the ones that changed
|
1705
|
-
// => we need to keep all results in memory and update them after each callback, so we can emit the full result set each time
|
1706
|
-
const changesCache = {};
|
1707
|
-
const promUnsub = connector.subscribe(networkId, "state_subscribeStorage", "state_storage", [allStateKeys], (error, result) => {
|
1708
|
-
if (error) subscriber.error(error);else if (result) {
|
1709
|
-
// update the cache
|
1710
|
-
for (const [stateKey, encodedResult] of result.changes) changesCache[stateKey] = encodedResult;
|
1711
|
-
|
1712
|
-
// regenerate the full changes array
|
1713
|
-
const changes = toPairs(changesCache);
|
1714
|
-
|
1715
|
-
// decode and emit results for all queries
|
1716
|
-
subscriber.next(decodeRpcQueryPack(queries, {
|
1717
|
-
block: result.block,
|
1718
|
-
changes
|
1719
|
-
}));
|
1720
|
-
}
|
1721
|
-
}, timeout);
|
1722
|
-
return () => {
|
1723
|
-
promUnsub.then(unsub => unsub("state_unsubscribeStorage"));
|
1724
|
-
};
|
1725
|
-
});
|
1726
|
-
};
|
1727
|
-
const decodeRpcQueryPack = (queries, result) => {
|
1728
|
-
return queries.reduce((acc, {
|
1729
|
-
stateKeys,
|
1730
|
-
decodeResult
|
1731
|
-
}) => {
|
1732
|
-
const changes = stateKeys.map(stateKey => {
|
1733
|
-
if (!stateKey || !result) return null;
|
1734
|
-
const change = result.changes.find(([key]) => key === stateKey);
|
1735
|
-
if (!change) return null;
|
1736
|
-
return change[1];
|
1737
|
-
});
|
1738
|
-
acc.push(decodeResult(changes));
|
1739
|
-
return acc;
|
1740
|
-
}, []);
|
1741
|
-
};
|
1742
|
-
|
1743
|
-
const buildNetworkStorageCoders = (chainId, miniMetadata, coders) => {
|
1744
|
-
if (!miniMetadata.data) return null;
|
1745
|
-
const metadata = unifyMetadata(decAnyMetadata(miniMetadata.data));
|
1746
|
-
try {
|
1747
|
-
const scaleBuilder = getDynamicBuilder(getLookupFn(metadata));
|
1748
|
-
const builtCoders = Object.fromEntries(Object.entries(coders).flatMap(([key, moduleMethodOrFn]) => {
|
1749
|
-
const [module, method] = typeof moduleMethodOrFn === "function" ? moduleMethodOrFn({
|
1750
|
-
chainId
|
1751
|
-
}) : moduleMethodOrFn;
|
1752
|
-
try {
|
1753
|
-
return [[key, scaleBuilder.buildStorage(module, method)]];
|
1754
|
-
} catch (cause) {
|
1755
|
-
log.trace(`Failed to build SCALE coder for chain ${chainId} (${module}::${method})`, cause);
|
1756
|
-
return [];
|
1757
|
-
}
|
1758
|
-
}));
|
1759
|
-
return builtCoders;
|
1760
|
-
} catch (cause) {
|
1761
|
-
log.error(`Failed to build SCALE coders for chain ${chainId} (${JSON.stringify(coders)})`, cause);
|
1762
|
-
}
|
1763
|
-
return null;
|
1764
|
-
};
|
1765
|
-
|
1766
|
-
const SPL_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
|
1767
|
-
const fetchBalances$6 = async ({
|
1768
|
-
networkId,
|
1769
|
-
tokensWithAddresses,
|
1770
|
-
connector
|
1771
|
-
}) => {
|
1772
|
-
if (!tokensWithAddresses.length) return {
|
1773
|
-
success: [],
|
1774
|
-
errors: []
|
1775
|
-
};
|
1776
|
-
const connection = await connector.getConnection(networkId);
|
1777
|
-
if (!connection) throw new Error(`Could not get connection for Solana network ${networkId}`);
|
1778
|
-
const accountAddresses = uniq(tokensWithAddresses.flatMap(([, addresses]) => addresses));
|
1779
|
-
const balancesPerAddress = await Promise.all(accountAddresses.map(async address => {
|
1780
|
-
const tokenAccounts = await connection.getParsedTokenAccountsByOwner(new PublicKey(address), {
|
1781
|
-
programId: new PublicKey(SPL_PROGRAM_ID) // SPL Token Program ID
|
1782
|
-
});
|
1783
|
-
const balances = tokenAccounts.value.map(d => {
|
1784
|
-
try {
|
1785
|
-
const mintAddress = d.account.data.parsed.info.mint;
|
1786
|
-
const value = d.account.data.parsed.info.tokenAmount.amount ?? "0";
|
1787
|
-
return {
|
1788
|
-
tokenId: solSplTokenId(networkId, mintAddress),
|
1789
|
-
networkId,
|
1790
|
-
address,
|
1791
|
-
source: MODULE_TYPE$6,
|
1792
|
-
status: "live",
|
1793
|
-
value
|
1794
|
-
};
|
1795
|
-
} catch (err) {
|
1796
|
-
log.warn("Failed to parse token amount", {
|
1797
|
-
address,
|
1798
|
-
d
|
1799
|
-
});
|
1800
|
-
return null;
|
1801
|
-
}
|
1802
|
-
}).filter(isNotNil);
|
1803
|
-
return [address, balances];
|
1804
|
-
}));
|
1805
|
-
const allBalancesByKey = keyBy(balancesPerAddress.flatMap(([, addressBalances]) => addressBalances), b => getBalanceKey(b.tokenId, b.address));
|
1806
|
-
const balanceDefs = getBalanceDefs(tokensWithAddresses);
|
1807
|
-
|
1808
|
-
// return a balance entry for all token/address pairs that were requested
|
1809
|
-
const success = balanceDefs.map(bd => {
|
1810
|
-
const found = allBalancesByKey[getBalanceKey(bd.token.id, bd.address)];
|
1811
|
-
return found ?? {
|
1812
|
-
tokenId: bd.token.id,
|
1813
|
-
networkId: bd.token.networkId,
|
1814
|
-
address: bd.address,
|
1815
|
-
source: MODULE_TYPE$6,
|
1816
|
-
status: "live",
|
1817
|
-
value: "0"
|
1818
|
-
};
|
1819
|
-
});
|
1820
|
-
|
1821
|
-
// return only the balances that match the tokens we are interested in
|
1822
|
-
return {
|
1823
|
-
success,
|
1824
|
-
errors: []
|
1825
|
-
}; // TODO output errors if any
|
1826
|
-
};
|
1827
|
-
const getBalanceKey = (tokenId, address) => `${tokenId}:${address}`;
|
1828
|
-
|
1829
|
-
const TokenCacheSchema = z.discriminatedUnion("isValid", [z.strictObject({
|
1830
|
-
id: SolSplTokenSchema.shape.id,
|
1831
|
-
isValid: z.literal(true),
|
1832
|
-
...SolSplTokenSchema.pick({
|
1833
|
-
symbol: true,
|
1834
|
-
decimals: true,
|
1835
|
-
name: true,
|
1836
|
-
logo: true
|
1837
|
-
}).shape
|
1838
|
-
}), z.strictObject({
|
1839
|
-
id: SolSplTokenSchema.shape.id,
|
1840
|
-
isValid: z.literal(false)
|
1841
|
-
})]);
|
1842
|
-
const METAPLEX_PROGRAM_ID = new PublicKey("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s");
|
1843
|
-
const fetchTokens$6 = async ({
|
1844
|
-
networkId,
|
1845
|
-
tokens,
|
1846
|
-
connector,
|
1847
|
-
cache
|
1848
|
-
}) => {
|
1849
|
-
const result = [];
|
1850
|
-
for (const tokenConfig of tokens) {
|
1851
|
-
const tokenId = solSplTokenId(networkId, tokenConfig.mintAddress);
|
1852
|
-
let cached = cache[tokenId] && TokenCacheSchema.safeParse(cache[tokenId]).data;
|
1853
|
-
if (!cached) {
|
1854
|
-
const tokenInfo = await fetchOnChainTokenData(connector, tokenId);
|
1855
|
-
if (tokenInfo) cache[tokenId] = tokenInfo;
|
1361
|
+
isValid: false
|
1362
|
+
};
|
1363
|
+
} else {
|
1364
|
+
log.warn(`Failed to fetch UniswapV2 token data for ${tokenConfig.contractAddress}`, err.shortMessage);
|
1365
|
+
}
|
1366
|
+
continue;
|
1367
|
+
}
|
1856
1368
|
}
|
1857
|
-
cached = cache[tokenId] && TokenCacheSchema.safeParse(cache[tokenId]).data;
|
1858
|
-
if (cached?.isValid === false) continue;
|
1859
1369
|
const base = {
|
1860
1370
|
id: tokenId,
|
1861
1371
|
type: MODULE_TYPE$6,
|
1862
1372
|
platform: PLATFORM$6,
|
1863
1373
|
networkId
|
1864
1374
|
};
|
1865
|
-
const
|
1866
|
-
|
1375
|
+
const cached2 = cache[tokenId] && TokenCacheSchema.safeParse(cache[tokenId]).data;
|
1376
|
+
if (cached2?.isValid === false) continue;
|
1377
|
+
const token = assign(base, cached2?.isValid ? omit(cached2, ["isValid"]) : {}, tokenConfig);
|
1378
|
+
const parsed = EvmUniswapV2TokenSchema.safeParse(token);
|
1867
1379
|
if (!parsed.success) {
|
1868
|
-
log.warn("Ignoring token with invalid
|
1869
|
-
token
|
1870
|
-
});
|
1380
|
+
log.warn("Ignoring token with invalid schema", token);
|
1871
1381
|
continue;
|
1872
1382
|
}
|
1873
1383
|
result.push(parsed.data);
|
1874
1384
|
}
|
1875
1385
|
return result;
|
1876
1386
|
};
|
1877
|
-
const ERROR_NO_MINT = "No mint info available";
|
1878
|
-
const ERROR_NO_METADATA = "No metadata account found";
|
1879
|
-
const ERROR_INVALID_DATA = "Invalid on-chain data";
|
1880
|
-
const fetchOnChainTokenData = async (connector, tokenId) => {
|
1881
|
-
try {
|
1882
|
-
const {
|
1883
|
-
networkId,
|
1884
|
-
mintAddress
|
1885
|
-
} = parseSolSplTokenId(tokenId);
|
1886
|
-
const connection = await connector.getConnection(networkId);
|
1887
|
-
if (!connection) {
|
1888
|
-
log.warn(`No connection found for network ${networkId}`);
|
1889
|
-
return null;
|
1890
|
-
}
|
1891
|
-
const mintPubKey = new PublicKey(mintAddress);
|
1892
|
-
const mintInfo = await connection.getAccountInfo(mintPubKey);
|
1893
|
-
if (!mintInfo?.data) throw new Error(ERROR_NO_MINT);
|
1894
|
-
const mint = MintLayout.decode(mintInfo.data);
|
1895
|
-
const [metadataPDA] = PublicKey.findProgramAddressSync([Buffer.from("metadata"), METAPLEX_PROGRAM_ID.toBuffer(), mintPubKey.toBuffer()], METAPLEX_PROGRAM_ID);
|
1896
|
-
|
1897
|
-
// 3. Fetch metadata account directly (traditional way)
|
1898
|
-
const metadataAccount = await connection.getAccountInfo(new PublicKey(metadataPDA));
|
1899
|
-
if (!metadataAccount) throw new Error(ERROR_NO_METADATA);
|
1900
|
-
const metadata = deserializeMetadata({
|
1901
|
-
publicKey: publicKey(metadataPDA),
|
1902
|
-
executable: metadataAccount.executable,
|
1903
|
-
owner: publicKey(metadataAccount.owner),
|
1904
|
-
lamports: sol(metadataAccount.lamports),
|
1905
|
-
data: metadataAccount.data
|
1906
|
-
});
|
1907
|
-
const parsed = TokenCacheSchema.safeParse({
|
1908
|
-
id: tokenId,
|
1909
|
-
symbol: metadata.symbol.trim(),
|
1910
|
-
name: metadata.name.trim(),
|
1911
|
-
decimals: mint.decimals,
|
1912
|
-
isValid: true
|
1913
|
-
});
|
1914
|
-
if (!parsed.success) throw new Error(ERROR_INVALID_DATA);
|
1915
|
-
return parsed.data;
|
1916
|
-
} catch (err) {
|
1917
|
-
const msg = err.message;
|
1918
|
-
if ([ERROR_NO_MINT, ERROR_NO_METADATA, ERROR_INVALID_DATA].includes(msg)) return TokenCacheSchema.parse({
|
1919
|
-
id: tokenId,
|
1920
|
-
isValid: false
|
1921
|
-
});
|
1922
|
-
log.warn("Failed to fetch sol-spl token data for %s", tokenId, {
|
1923
|
-
err
|
1924
|
-
});
|
1925
|
-
}
|
1926
|
-
return null;
|
1927
|
-
};
|
1928
1387
|
|
1929
1388
|
const getMiniMetadata$6 = () => {
|
1930
|
-
throw new Error("MiniMetadata is not supported for
|
1389
|
+
throw new Error("MiniMetadata is not supported for ethereum tokens");
|
1931
1390
|
};
|
1932
1391
|
|
1933
|
-
const getTransferCallData$6 =
|
1392
|
+
const getTransferCallData$6 = ({
|
1934
1393
|
from,
|
1935
1394
|
to,
|
1936
1395
|
value,
|
1937
|
-
token
|
1938
|
-
connector
|
1396
|
+
token
|
1939
1397
|
}) => {
|
1940
1398
|
if (!isTokenOfType(token, MODULE_TYPE$6)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$6}.`);
|
1941
|
-
|
1942
|
-
|
1943
|
-
const
|
1944
|
-
|
1945
|
-
|
1946
|
-
|
1947
|
-
|
1948
|
-
|
1949
|
-
|
1950
|
-
|
1951
|
-
|
1952
|
-
|
1953
|
-
instructions.push(createAssociatedTokenAccountInstruction(fromWallet,
|
1954
|
-
// funder
|
1955
|
-
toTokenAccount, toWallet, mint));
|
1956
|
-
}
|
1957
|
-
|
1958
|
-
// Transfer the tokens
|
1959
|
-
instructions.push(createTransferInstruction(fromTokenAccount, toTokenAccount, fromWallet, BigInt(value), [], TOKEN_PROGRAM_ID));
|
1960
|
-
return instructions;
|
1961
|
-
};
|
1962
|
-
const tokenAccountExists = async (connection, address) => {
|
1963
|
-
try {
|
1964
|
-
await getAccount(connection, address);
|
1965
|
-
return true;
|
1966
|
-
} catch {
|
1967
|
-
return false;
|
1968
|
-
}
|
1399
|
+
if (!isEthereumAddress(from)) throw new Error("Invalid from address");
|
1400
|
+
if (!isEthereumAddress(to)) throw new Error("Invalid to address");
|
1401
|
+
const data = encodeFunctionData({
|
1402
|
+
abi: erc20Abi,
|
1403
|
+
functionName: "transfer",
|
1404
|
+
args: [to, BigInt(value)]
|
1405
|
+
});
|
1406
|
+
return {
|
1407
|
+
from,
|
1408
|
+
to: token.contractAddress,
|
1409
|
+
data
|
1410
|
+
};
|
1969
1411
|
};
|
1970
1412
|
|
1971
1413
|
const SUBSCRIPTION_INTERVAL$2 = 6_000;
|
@@ -2008,7 +1450,7 @@ const subscribeBalances$6 = ({
|
|
2008
1450
|
}).pipe(distinctUntilChanged(isEqual));
|
2009
1451
|
};
|
2010
1452
|
|
2011
|
-
const
|
1453
|
+
const EvmUniswapV2BalanceModule = {
|
2012
1454
|
type: MODULE_TYPE$6,
|
2013
1455
|
platform: PLATFORM$6,
|
2014
1456
|
getMiniMetadata: getMiniMetadata$6,
|
@@ -2019,14 +1461,153 @@ const SolSplBalanceModule = {
|
|
2019
1461
|
};
|
2020
1462
|
|
2021
1463
|
// to be used by chaindata too
|
2022
|
-
const
|
2023
|
-
|
1464
|
+
const EvmUniswapV2TokenConfigSchema = z.strictObject({
|
1465
|
+
contractAddress: EvmUniswapV2TokenSchema.shape.contractAddress,
|
2024
1466
|
...TokenConfigBaseSchema.shape
|
2025
1467
|
});
|
2026
1468
|
|
2027
1469
|
const MODULE_TYPE$5 = SubAssetsTokenSchema.shape.type.value;
|
2028
1470
|
const PLATFORM$5 = SubAssetsTokenSchema.shape.platform.value;
|
2029
1471
|
|
1472
|
+
const fetchRpcQueryPack = async (connector, networkId, queries) => {
|
1473
|
+
const allStateKeys = queries.flatMap(({
|
1474
|
+
stateKeys
|
1475
|
+
}) => stateKeys).filter(isNotNil);
|
1476
|
+
|
1477
|
+
// doing a query without keys would throw an error => return early
|
1478
|
+
if (!allStateKeys.length) return queries.map(({
|
1479
|
+
stateKeys,
|
1480
|
+
decodeResult
|
1481
|
+
}) => decodeResult(stateKeys.map(() => null)));
|
1482
|
+
const [result] = await connector.send(networkId, "state_queryStorageAt", [allStateKeys]);
|
1483
|
+
return decodeRpcQueryPack(queries, result);
|
1484
|
+
};
|
1485
|
+
const getRpcQueryPack$ = (connector, networkId, queries, timeout = false) => {
|
1486
|
+
const allStateKeys = queries.flatMap(({
|
1487
|
+
stateKeys
|
1488
|
+
}) => stateKeys).filter(isNotNil);
|
1489
|
+
|
1490
|
+
// doing a query without keys would throw an error => return early
|
1491
|
+
if (!allStateKeys.length) return of(queries.map(({
|
1492
|
+
stateKeys,
|
1493
|
+
decodeResult
|
1494
|
+
}) => decodeResult(stateKeys.map(() => null))));
|
1495
|
+
return new Observable(subscriber => {
|
1496
|
+
// first subscription callback includes results for all state keys, but further callbacks will only include the ones that changed
|
1497
|
+
// => we need to keep all results in memory and update them after each callback, so we can emit the full result set each time
|
1498
|
+
const changesCache = {};
|
1499
|
+
const promUnsub = connector.subscribe(networkId, "state_subscribeStorage", "state_storage", [allStateKeys], (error, result) => {
|
1500
|
+
if (error) subscriber.error(error);else if (result) {
|
1501
|
+
// update the cache
|
1502
|
+
for (const [stateKey, encodedResult] of result.changes) changesCache[stateKey] = encodedResult;
|
1503
|
+
|
1504
|
+
// regenerate the full changes array
|
1505
|
+
const changes = toPairs(changesCache);
|
1506
|
+
|
1507
|
+
// decode and emit results for all queries
|
1508
|
+
subscriber.next(decodeRpcQueryPack(queries, {
|
1509
|
+
block: result.block,
|
1510
|
+
changes
|
1511
|
+
}));
|
1512
|
+
}
|
1513
|
+
}, timeout);
|
1514
|
+
return () => {
|
1515
|
+
promUnsub.then(unsub => unsub("state_unsubscribeStorage"));
|
1516
|
+
};
|
1517
|
+
});
|
1518
|
+
};
|
1519
|
+
const decodeRpcQueryPack = (queries, result) => {
|
1520
|
+
return queries.reduce((acc, {
|
1521
|
+
stateKeys,
|
1522
|
+
decodeResult
|
1523
|
+
}) => {
|
1524
|
+
const changes = stateKeys.map(stateKey => {
|
1525
|
+
if (!stateKey || !result) return null;
|
1526
|
+
const change = result.changes.find(([key]) => key === stateKey);
|
1527
|
+
if (!change) return null;
|
1528
|
+
return change[1];
|
1529
|
+
});
|
1530
|
+
acc.push(decodeResult(changes));
|
1531
|
+
return acc;
|
1532
|
+
}, []);
|
1533
|
+
};
|
1534
|
+
|
1535
|
+
const fetchRuntimeCallResult = async (connector, networkId, metadataRpc, apiName, method, args) => {
|
1536
|
+
const {
|
1537
|
+
builder
|
1538
|
+
} = parseMetadataRpc(metadataRpc);
|
1539
|
+
const call = builder.buildRuntimeCall(apiName, method);
|
1540
|
+
const hex = await connector.send(networkId, "state_call", [`${apiName}_${method}`, toHex(call.args.enc(args))]);
|
1541
|
+
return call.value.dec(hex);
|
1542
|
+
};
|
1543
|
+
|
1544
|
+
const hasStorageItem = (metadata, palletName, itemName) => {
|
1545
|
+
const pallet = metadata.pallets.find(p => p.name === palletName);
|
1546
|
+
if (!pallet || !pallet.storage) return false;
|
1547
|
+
return pallet.storage.items.some(item => item.name === itemName);
|
1548
|
+
};
|
1549
|
+
const hasStorageItems = (metadata, palletName, itemNames) => {
|
1550
|
+
const pallet = metadata.pallets.find(p => p.name === palletName);
|
1551
|
+
if (!pallet || !pallet.storage) return false;
|
1552
|
+
return itemNames.every(itemName => pallet.storage?.items.some(item => item.name === itemName));
|
1553
|
+
};
|
1554
|
+
const hasRuntimeApi = (metadata, apiName, method) => {
|
1555
|
+
const api = metadata.apis.find(api => api.name === apiName);
|
1556
|
+
if (!api || !api.methods) return false;
|
1557
|
+
return api.methods.some(m => m.name === method);
|
1558
|
+
};
|
1559
|
+
const getConstantValue = (metadataRpc, pallet, constant) => {
|
1560
|
+
const {
|
1561
|
+
unifiedMetadata,
|
1562
|
+
builder
|
1563
|
+
} = parseMetadataRpc(metadataRpc);
|
1564
|
+
const codec = builder.buildConstant(pallet, constant);
|
1565
|
+
const encodedValue = unifiedMetadata.pallets.find(({
|
1566
|
+
name
|
1567
|
+
}) => name === pallet)?.constants.find(({
|
1568
|
+
name
|
1569
|
+
}) => name === constant)?.value;
|
1570
|
+
if (!encodedValue) throw new Error(`Constant ${pallet}.${constant} not found`);
|
1571
|
+
return codec.dec(encodedValue);
|
1572
|
+
};
|
1573
|
+
const tryGetConstantValue = (metadataRpc, pallet, constant) => {
|
1574
|
+
const {
|
1575
|
+
unifiedMetadata,
|
1576
|
+
builder
|
1577
|
+
} = parseMetadataRpc(metadataRpc);
|
1578
|
+
const encodedValue = unifiedMetadata.pallets.find(({
|
1579
|
+
name
|
1580
|
+
}) => name === pallet)?.constants.find(({
|
1581
|
+
name
|
1582
|
+
}) => name === constant)?.value;
|
1583
|
+
if (!encodedValue) return null;
|
1584
|
+
const codec = builder.buildConstant(pallet, constant);
|
1585
|
+
return codec.dec(encodedValue);
|
1586
|
+
};
|
1587
|
+
|
1588
|
+
const buildNetworkStorageCoders = (chainId, miniMetadata, coders) => {
|
1589
|
+
if (!miniMetadata.data) return null;
|
1590
|
+
const metadata = unifyMetadata(decAnyMetadata(miniMetadata.data));
|
1591
|
+
try {
|
1592
|
+
const scaleBuilder = getDynamicBuilder(getLookupFn(metadata));
|
1593
|
+
const builtCoders = Object.fromEntries(Object.entries(coders).flatMap(([key, moduleMethodOrFn]) => {
|
1594
|
+
const [module, method] = typeof moduleMethodOrFn === "function" ? moduleMethodOrFn({
|
1595
|
+
chainId
|
1596
|
+
}) : moduleMethodOrFn;
|
1597
|
+
try {
|
1598
|
+
return [[key, scaleBuilder.buildStorage(module, method)]];
|
1599
|
+
} catch (cause) {
|
1600
|
+
log.trace(`Failed to build SCALE coder for chain ${chainId} (${module}::${method})`, cause);
|
1601
|
+
return [];
|
1602
|
+
}
|
1603
|
+
}));
|
1604
|
+
return builtCoders;
|
1605
|
+
} catch (cause) {
|
1606
|
+
log.error(`Failed to build SCALE coders for chain ${chainId} (${JSON.stringify(coders)})`, cause);
|
1607
|
+
}
|
1608
|
+
return null;
|
1609
|
+
};
|
1610
|
+
|
2030
1611
|
const buildQueries$2 = (networkId, balanceDefs, miniMetadata) => {
|
2031
1612
|
const networkStorageCoders = buildNetworkStorageCoders(networkId, miniMetadata, {
|
2032
1613
|
storage: ["Assets", "Account"]
|
@@ -2262,6 +1843,11 @@ function includeInTotalExtraAmount(extra) {
|
|
2262
1843
|
return extra.filter(extra => extra.includeInTotal).map(extra => extra.amount.planck).reduce((a, b) => a + b, 0n);
|
2263
1844
|
}
|
2264
1845
|
|
1846
|
+
/**
|
1847
|
+
* Have the importing library define its Token and BalanceJson enums (as a sum type of all plugins) and pass them into some
|
1848
|
+
* internal global typescript context, which is then picked up on by this module.
|
1849
|
+
*/
|
1850
|
+
|
2265
1851
|
/** A utility type used to extract the underlying `BalanceType` of a specific source from a generalised `BalanceJson` */
|
2266
1852
|
|
2267
1853
|
/** TODO: Remove this in favour of a frontend-friendly `ChaindataProvider` */
|
@@ -2998,6 +2584,8 @@ const getValueId = amount => {
|
|
2998
2584
|
|
2999
2585
|
/** A labelled extra amount of a balance */
|
3000
2586
|
|
2587
|
+
/** Used by plugins to help define their custom `BalanceType` */
|
2588
|
+
|
3001
2589
|
/** For fast db access, you can calculate the primary key for a miniMetadata using this method */
|
3002
2590
|
const deriveMiniMetadataId = ({
|
3003
2591
|
source,
|
@@ -6554,7 +6142,7 @@ const SubTokensMiniMetadataExtraSchema = z.strictObject({
|
|
6554
6142
|
palletId: z.string()
|
6555
6143
|
});
|
6556
6144
|
|
6557
|
-
const BALANCE_MODULES = [SubNativeBalanceModule, SubAssetsBalanceModule, SubHydrationBalanceModule, SubForeignAssetsBalanceModule, SubPsp22BalanceModule, SubTokensBalanceModule, EvmErc20BalanceModule, EvmUniswapV2BalanceModule, EvmNativeBalanceModule
|
6145
|
+
const BALANCE_MODULES = [SubNativeBalanceModule, SubAssetsBalanceModule, SubHydrationBalanceModule, SubForeignAssetsBalanceModule, SubPsp22BalanceModule, SubTokensBalanceModule, EvmErc20BalanceModule, EvmUniswapV2BalanceModule, EvmNativeBalanceModule];
|
6558
6146
|
|
6559
6147
|
// share requests as all modules will call this at once
|
6560
6148
|
const CACHE$1 = new Map();
|
@@ -6732,25 +6320,10 @@ class BalancesProvider {
|
|
6732
6320
|
{
|
6733
6321
|
return this.getEthereumNetworkModuleBalances$(networkId, tokensWithAddresses, mod);
|
6734
6322
|
}
|
6735
|
-
case "solana":
|
6736
|
-
{
|
6737
|
-
return this.getSolanaNetworkModuleBalances$(networkId, tokensWithAddresses, mod);
|
6738
|
-
}
|
6739
6323
|
case "polkadot":
|
6740
6324
|
{
|
6741
6325
|
return this.getPolkadotNetworkModuleBalances$(networkId, tokensWithAddresses, mod);
|
6742
6326
|
}
|
6743
|
-
default:
|
6744
|
-
{
|
6745
|
-
log.warn("[balances] Unsupported network platform for module", {
|
6746
|
-
networkId,
|
6747
|
-
mod
|
6748
|
-
});
|
6749
|
-
return of({
|
6750
|
-
status: "live",
|
6751
|
-
balances: []
|
6752
|
-
});
|
6753
|
-
}
|
6754
6327
|
}
|
6755
6328
|
}));
|
6756
6329
|
}), map(results => {
|
@@ -6780,7 +6353,7 @@ class BalancesProvider {
|
|
6780
6353
|
address
|
6781
6354
|
})));
|
6782
6355
|
if (!this.#chainConnectors.substrate) {
|
6783
|
-
log.
|
6356
|
+
log.debug("[balances] no substrate connector or miniMetadata for module", mod.type);
|
6784
6357
|
return defer(() => of({
|
6785
6358
|
status: "initialising",
|
6786
6359
|
balances: this.getStoredBalances(moduleAddressesByTokenId)
|
@@ -6831,7 +6404,7 @@ class BalancesProvider {
|
|
6831
6404
|
address
|
6832
6405
|
})));
|
6833
6406
|
if (!this.#chainConnectors.evm) {
|
6834
|
-
log.
|
6407
|
+
log.debug("[balances] no ethereum connector for module", mod.type);
|
6835
6408
|
return defer(() => of({
|
6836
6409
|
status: "initialising",
|
6837
6410
|
balances: this.getStoredBalances(moduleAddressesByTokenId)
|
@@ -6863,56 +6436,6 @@ class BalancesProvider {
|
|
6863
6436
|
})));
|
6864
6437
|
});
|
6865
6438
|
}
|
6866
|
-
getSolanaNetworkModuleBalances$(networkId, tokensWithAddresses, mod) {
|
6867
|
-
return getSharedObservable(`BalancesProvider.getSolanaNetworkModuleBalances$`, {
|
6868
|
-
networkId,
|
6869
|
-
mod,
|
6870
|
-
tokensWithAddresses
|
6871
|
-
}, () => {
|
6872
|
-
if (!tokensWithAddresses.length) return of({
|
6873
|
-
status: "live",
|
6874
|
-
balances: []
|
6875
|
-
});
|
6876
|
-
const moduleAddressesByTokenId = fromPairs(tokensWithAddresses.map(([token, addresses]) => [token.id, addresses]));
|
6877
|
-
|
6878
|
-
// all balance ids expected in result set
|
6879
|
-
const balanceIds = toPairs(moduleAddressesByTokenId).flatMap(([tokenId, addresses]) => addresses.map(address => getBalanceId({
|
6880
|
-
tokenId,
|
6881
|
-
address
|
6882
|
-
})));
|
6883
|
-
if (!this.#chainConnectors.solana) {
|
6884
|
-
log.warn("[balances] no solana connector for module", mod.type);
|
6885
|
-
return defer(() => of({
|
6886
|
-
status: "initialising",
|
6887
|
-
balances: this.getStoredBalances(moduleAddressesByTokenId)
|
6888
|
-
}));
|
6889
|
-
}
|
6890
|
-
const moduleBalances$ = mod.subscribeBalances({
|
6891
|
-
networkId,
|
6892
|
-
tokensWithAddresses,
|
6893
|
-
connector: this.#chainConnectors.solana
|
6894
|
-
}).pipe(catchError(() => EMPTY),
|
6895
|
-
// don't emit, let provider mark balances stale
|
6896
|
-
map(results => ({
|
6897
|
-
status: "live",
|
6898
|
-
// exclude zero balances
|
6899
|
-
balances: results.success.filter(b => new Balance(b).total.planck > 0n)
|
6900
|
-
})), tap(results => {
|
6901
|
-
this.updateStorage$(balanceIds, results);
|
6902
|
-
}),
|
6903
|
-
// shareReplay + keepAlive(0) keep the subscription alive while root observable is being unsubscribed+resubscribed, in case any input change
|
6904
|
-
shareReplay({
|
6905
|
-
refCount: true,
|
6906
|
-
bufferSize: 1
|
6907
|
-
}), keepAlive(0));
|
6908
|
-
|
6909
|
-
// defer the startWith call to start with up to date balances each time the observable is re-subscribed to
|
6910
|
-
return defer(() => moduleBalances$.pipe(startWith({
|
6911
|
-
status: "initialising",
|
6912
|
-
balances: this.getStoredBalances(moduleAddressesByTokenId)
|
6913
|
-
})));
|
6914
|
-
});
|
6915
|
-
}
|
6916
6439
|
updateStorage$(balanceIds, balancesResult) {
|
6917
6440
|
if (balancesResult.status !== "live") return;
|
6918
6441
|
const storage = this.#storage.getValue();
|
@@ -7023,42 +6546,18 @@ class BalancesProvider {
|
|
7023
6546
|
}));
|
7024
6547
|
}
|
7025
6548
|
}
|
7026
|
-
const
|
6549
|
+
const isAddressCompatibleWithNetwork = (network, address) => {
|
7027
6550
|
switch (network.platform) {
|
7028
6551
|
case "ethereum":
|
7029
|
-
return
|
7030
|
-
case "solana":
|
7031
|
-
return platform === "solana";
|
6552
|
+
return isEthereumAddress(address);
|
7032
6553
|
case "polkadot":
|
7033
|
-
|
7034
|
-
switch (network.account) {
|
7035
|
-
case "secp256k1":
|
7036
|
-
return platform === "ethereum";
|
7037
|
-
case "*25519":
|
7038
|
-
return platform === "polkadot";
|
7039
|
-
default:
|
7040
|
-
throw new Error(`Unsupported polkadot network account type ${network.account}`);
|
7041
|
-
}
|
7042
|
-
}
|
6554
|
+
return isEthereumAddress(address) ? network.account === "secp256k1" : network.account !== "secp256k1";
|
7043
6555
|
default:
|
7044
6556
|
log.warn("Unsupported network platform", network);
|
7045
6557
|
throw new Error("Unsupported network platform");
|
7046
6558
|
}
|
7047
6559
|
};
|
7048
|
-
|
7049
|
-
/**
|
7050
|
-
* If this is the address of an account, use isAccountCompatibleWithChain instead.
|
7051
|
-
* Otherwise it could lead to a loss of funds
|
7052
|
-
* @param chain
|
7053
|
-
* @param address
|
7054
|
-
* @returns
|
7055
|
-
*/
|
7056
|
-
const isAddressCompatibleWithNetwork = (network, address) => {
|
7057
|
-
// TODO try with return true to check if wallet filters correctly upfront
|
7058
|
-
const accountPlatform = getAccountPlatformFromAddress(address);
|
7059
|
-
return isAccountPlatformCompatibleWithNetwork(network, accountPlatform);
|
7060
|
-
};
|
7061
6560
|
const sortByBalanceId = (a, b) => getBalanceId(a).localeCompare(getBalanceId(b));
|
7062
6561
|
const sortByMiniMetadataId = (a, b) => a.id.localeCompare(b.id);
|
7063
6562
|
|
7064
|
-
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,
|
6563
|
+
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, uniswapV2PairAbi };
|