@talismn/balances 0.0.0-pr2130-20250807071025 → 0.0.0-pr2134-20250813091030
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/declarations/src/BalancesProvider.d.ts +1 -0
- 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 +23 -0
- 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/sol-native/config.d.ts +3 -0
- package/dist/declarations/src/modules/sol-native/fetchBalances.d.ts +3 -0
- package/dist/declarations/src/modules/sol-native/fetchTokens.d.ts +3 -0
- package/dist/declarations/src/modules/sol-native/getMiniMetadata.d.ts +3 -0
- package/dist/declarations/src/modules/sol-native/getTransferCallData.d.ts +3 -0
- package/dist/declarations/src/modules/sol-native/index.d.ts +2 -0
- package/dist/declarations/src/modules/sol-native/module.d.ts +3 -0
- package/dist/declarations/src/modules/sol-native/subscribeBalances.d.ts +3 -0
- package/dist/declarations/src/modules/sol-native/types.d.ts +13 -0
- package/dist/declarations/src/modules/sol-spl/config.d.ts +3 -0
- package/dist/declarations/src/modules/sol-spl/fetchBalances.d.ts +3 -0
- package/dist/declarations/src/modules/sol-spl/fetchTokens.d.ts +3 -0
- package/dist/declarations/src/modules/sol-spl/getMiniMetadata.d.ts +3 -0
- package/dist/declarations/src/modules/sol-spl/getTransferCallData.d.ts +3 -0
- package/dist/declarations/src/modules/sol-spl/index.d.ts +2 -0
- package/dist/declarations/src/modules/sol-spl/module.d.ts +3 -0
- package/dist/declarations/src/modules/sol-spl/subscribeBalances.d.ts +3 -0
- package/dist/declarations/src/modules/sol-spl/types.d.ts +14 -0
- 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 +26 -19
- package/dist/declarations/src/types/balances.d.ts +52 -4
- package/dist/declarations/src/types/balancetypes.d.ts +0 -4
- package/dist/declarations/src/types/chainConnectors.d.ts +4 -4
- package/dist/talismn-balances.cjs.dev.js +750 -245
- package/dist/talismn-balances.cjs.prod.js +750 -245
- package/dist/talismn-balances.esm.js +740 -239
- package/package.json +13 -8
@@ -1,14 +1,19 @@
|
|
1
1
|
'use strict';
|
2
2
|
|
3
3
|
var chaindataProvider = require('@talismn/chaindata-provider');
|
4
|
-
var
|
4
|
+
var crypto = require('@talismn/crypto');
|
5
5
|
var viem = require('viem');
|
6
6
|
var lodashEs = require('lodash-es');
|
7
7
|
var z = require('zod/v4');
|
8
8
|
var anylogger = require('anylogger');
|
9
9
|
var rxjs = require('rxjs');
|
10
10
|
var BigNumber = require('bignumber.js');
|
11
|
+
var web3_js = require('@solana/web3.js');
|
12
|
+
var util = require('@talismn/util');
|
11
13
|
var scale = require('@talismn/scale');
|
14
|
+
var mplTokenMetadata = require('@metaplex-foundation/mpl-token-metadata');
|
15
|
+
var umi = require('@metaplex-foundation/umi');
|
16
|
+
var splToken = require('@solana/spl-token');
|
12
17
|
var tokenRates = require('@talismn/token-rates');
|
13
18
|
var utils = require('@polkadot-api/utils');
|
14
19
|
var polkadotApi = require('polkadot-api');
|
@@ -28,8 +33,8 @@ var BigNumber__default = /*#__PURE__*/_interopDefault(BigNumber);
|
|
28
33
|
var upperFirst__default = /*#__PURE__*/_interopDefault(upperFirst);
|
29
34
|
var PQueue__default = /*#__PURE__*/_interopDefault(PQueue);
|
30
35
|
|
31
|
-
const MODULE_TYPE$
|
32
|
-
const PLATFORM$
|
36
|
+
const MODULE_TYPE$a = chaindataProvider.EvmErc20TokenSchema.shape.type.value;
|
37
|
+
const PLATFORM$a = chaindataProvider.EvmErc20TokenSchema.shape.platform.value;
|
33
38
|
|
34
39
|
const abiMulticall = viem.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)"]);
|
35
40
|
|
@@ -625,7 +630,7 @@ const getBalanceDefs = addressesByToken => {
|
|
625
630
|
// if there is at least one storage entry, the results will be an array with a single object
|
626
631
|
// if the storage has no entries in it (ex: Assets on ewx or moonbeam), the response will be an empty array
|
627
632
|
|
628
|
-
const fetchBalances$
|
633
|
+
const fetchBalances$a = async ({
|
629
634
|
networkId,
|
630
635
|
tokensWithAddresses,
|
631
636
|
connector
|
@@ -637,8 +642,8 @@ const fetchBalances$8 = async ({
|
|
637
642
|
const client = await connector.getPublicClientForEvmNetwork(networkId);
|
638
643
|
if (!client) throw new Error(`Could not get rpc provider for evm network ${networkId}`);
|
639
644
|
for (const [token, addresses] of tokensWithAddresses) {
|
640
|
-
if (token.type !== MODULE_TYPE$
|
641
|
-
for (const address of addresses) if (!
|
645
|
+
if (token.type !== MODULE_TYPE$a || token.networkId !== networkId) throw new Error(`Invalid token type or networkId for EVM ERC20 balance module: ${token.type} on ${token.networkId}`);
|
646
|
+
for (const address of addresses) if (!crypto.isEthereumAddress(address)) throw new Error(`Invalid ethereum address for EVM ERC20 balance module: ${address} for token ${token.id}`);
|
642
647
|
}
|
643
648
|
const balanceDefs = getBalanceDefs(tokensWithAddresses);
|
644
649
|
if (client.chain?.contracts?.erc20Aggregator && balanceDefs.length > 1) {
|
@@ -667,7 +672,7 @@ const fetchWithoutAggregator = async (client, balanceDefs) => {
|
|
667
672
|
address,
|
668
673
|
tokenId: token.id,
|
669
674
|
value: result.toString(),
|
670
|
-
source: MODULE_TYPE$
|
675
|
+
source: MODULE_TYPE$a,
|
671
676
|
networkId: chaindataProvider.parseEvmErc20TokenId(token.id).networkId,
|
672
677
|
status: "live"
|
673
678
|
};
|
@@ -710,7 +715,7 @@ const fetchWithAggregator = async (client, balanceDefs, erc20BalancesAggregatorA
|
|
710
715
|
address: balanceDef.address,
|
711
716
|
tokenId: balanceDef.token.id,
|
712
717
|
value: erc20Balances[index].toString(),
|
713
|
-
source: MODULE_TYPE$
|
718
|
+
source: MODULE_TYPE$a,
|
714
719
|
networkId: chaindataProvider.parseTokenId(balanceDef.token.id).networkId,
|
715
720
|
status: "live"
|
716
721
|
}));
|
@@ -767,7 +772,7 @@ const getTypedContract$1 = (client, abi, contractAddress) => viem.getContract({
|
|
767
772
|
}
|
768
773
|
});
|
769
774
|
|
770
|
-
const TokenCacheSchema$
|
775
|
+
const TokenCacheSchema$2 = z__default.default.discriminatedUnion("isValid", [z__default.default.strictObject({
|
771
776
|
id: chaindataProvider.EvmErc20TokenSchema.shape.id,
|
772
777
|
isValid: z__default.default.literal(true),
|
773
778
|
...chaindataProvider.EvmErc20TokenSchema.pick({
|
@@ -779,7 +784,7 @@ const TokenCacheSchema$1 = z__default.default.discriminatedUnion("isValid", [z__
|
|
779
784
|
id: chaindataProvider.EvmErc20TokenSchema.shape.id,
|
780
785
|
isValid: z__default.default.literal(false)
|
781
786
|
})]);
|
782
|
-
const fetchTokens$
|
787
|
+
const fetchTokens$a = async ({
|
783
788
|
networkId,
|
784
789
|
tokens,
|
785
790
|
connector,
|
@@ -788,7 +793,7 @@ const fetchTokens$8 = async ({
|
|
788
793
|
const result = [];
|
789
794
|
for (const tokenConfig of tokens) {
|
790
795
|
const tokenId = chaindataProvider.evmErc20TokenId(networkId, tokenConfig.contractAddress);
|
791
|
-
const cached = cache[tokenId] && TokenCacheSchema$
|
796
|
+
const cached = cache[tokenId] && TokenCacheSchema$2.safeParse(cache[tokenId]).data;
|
792
797
|
if (!cached) {
|
793
798
|
const client = await connector.getPublicClientForEvmNetwork(networkId);
|
794
799
|
if (!client) {
|
@@ -801,7 +806,7 @@ const fetchTokens$8 = async ({
|
|
801
806
|
decimals,
|
802
807
|
symbol
|
803
808
|
} = await getErc20ContractData$1(client, tokenConfig.contractAddress);
|
804
|
-
cache[tokenId] = TokenCacheSchema$
|
809
|
+
cache[tokenId] = TokenCacheSchema$2.parse({
|
805
810
|
id: tokenId,
|
806
811
|
symbol,
|
807
812
|
decimals,
|
@@ -819,11 +824,11 @@ const fetchTokens$8 = async ({
|
|
819
824
|
}
|
820
825
|
const base = {
|
821
826
|
id: tokenId,
|
822
|
-
type: MODULE_TYPE$
|
823
|
-
platform: PLATFORM$
|
827
|
+
type: MODULE_TYPE$a,
|
828
|
+
platform: PLATFORM$a,
|
824
829
|
networkId
|
825
830
|
};
|
826
|
-
const cached2 = cache[tokenId] && TokenCacheSchema$
|
831
|
+
const cached2 = cache[tokenId] && TokenCacheSchema$2.safeParse(cache[tokenId]).data;
|
827
832
|
if (cached2?.isValid === false) continue;
|
828
833
|
const token = lodashEs.assign(base, cached2?.isValid ? lodashEs.omit(cached2, ["isValid"]) : {}, tokenConfig);
|
829
834
|
const parsed = chaindataProvider.EvmErc20TokenSchema.safeParse(token);
|
@@ -838,19 +843,19 @@ const fetchTokens$8 = async ({
|
|
838
843
|
return result;
|
839
844
|
};
|
840
845
|
|
841
|
-
const getMiniMetadata$
|
846
|
+
const getMiniMetadata$a = () => {
|
842
847
|
throw new Error("MiniMetadata is not supported for ethereum tokens");
|
843
848
|
};
|
844
849
|
|
845
|
-
const getTransferCallData$
|
850
|
+
const getTransferCallData$a = ({
|
846
851
|
from,
|
847
852
|
to,
|
848
853
|
value,
|
849
854
|
token
|
850
855
|
}) => {
|
851
|
-
if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$
|
852
|
-
if (!
|
853
|
-
if (!
|
856
|
+
if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$a)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$a}.`);
|
857
|
+
if (!crypto.isEthereumAddress(from)) throw new Error("Invalid from address");
|
858
|
+
if (!crypto.isEthereumAddress(to)) throw new Error("Invalid to address");
|
854
859
|
const data = viem.encodeFunctionData({
|
855
860
|
abi: viem.erc20Abi,
|
856
861
|
functionName: "transfer",
|
@@ -863,8 +868,8 @@ const getTransferCallData$8 = ({
|
|
863
868
|
};
|
864
869
|
};
|
865
870
|
|
866
|
-
const SUBSCRIPTION_INTERVAL$
|
867
|
-
const subscribeBalances$
|
871
|
+
const SUBSCRIPTION_INTERVAL$6 = 6_000;
|
872
|
+
const subscribeBalances$a = ({
|
868
873
|
networkId,
|
869
874
|
tokensWithAddresses,
|
870
875
|
connector
|
@@ -878,17 +883,17 @@ const subscribeBalances$8 = ({
|
|
878
883
|
const poll = async () => {
|
879
884
|
try {
|
880
885
|
if (abortController.signal.aborted) return;
|
881
|
-
const balances = await fetchBalances$
|
886
|
+
const balances = await fetchBalances$a({
|
882
887
|
networkId,
|
883
888
|
tokensWithAddresses: tokensWithAddresses,
|
884
889
|
connector
|
885
890
|
});
|
886
891
|
if (abortController.signal.aborted) return;
|
887
892
|
subscriber.next(balances);
|
888
|
-
setTimeout(poll, SUBSCRIPTION_INTERVAL$
|
893
|
+
setTimeout(poll, SUBSCRIPTION_INTERVAL$6);
|
889
894
|
} catch (error) {
|
890
895
|
log.error("Error", {
|
891
|
-
module: MODULE_TYPE$
|
896
|
+
module: MODULE_TYPE$a,
|
892
897
|
networkId,
|
893
898
|
addressesByToken: tokensWithAddresses,
|
894
899
|
error
|
@@ -904,13 +909,13 @@ const subscribeBalances$8 = ({
|
|
904
909
|
};
|
905
910
|
|
906
911
|
const EvmErc20BalanceModule = {
|
907
|
-
type: MODULE_TYPE$
|
908
|
-
platform: PLATFORM$
|
909
|
-
getMiniMetadata: getMiniMetadata$
|
910
|
-
fetchTokens: fetchTokens$
|
911
|
-
fetchBalances: fetchBalances$
|
912
|
-
subscribeBalances: subscribeBalances$
|
913
|
-
getTransferCallData: getTransferCallData$
|
912
|
+
type: MODULE_TYPE$a,
|
913
|
+
platform: PLATFORM$a,
|
914
|
+
getMiniMetadata: getMiniMetadata$a,
|
915
|
+
fetchTokens: fetchTokens$a,
|
916
|
+
fetchBalances: fetchBalances$a,
|
917
|
+
subscribeBalances: subscribeBalances$a,
|
918
|
+
getTransferCallData: getTransferCallData$a
|
914
919
|
};
|
915
920
|
|
916
921
|
const TokenConfigBaseSchema = chaindataProvider.TokenBaseSchema.partial().omit({
|
@@ -923,10 +928,10 @@ const EvmErc20TokenConfigSchema = z__default.default.strictObject({
|
|
923
928
|
...TokenConfigBaseSchema.shape
|
924
929
|
});
|
925
930
|
|
926
|
-
const MODULE_TYPE$
|
927
|
-
const PLATFORM$
|
931
|
+
const MODULE_TYPE$9 = chaindataProvider.EvmNativeTokenSchema.shape.type.value;
|
932
|
+
const PLATFORM$9 = chaindataProvider.EvmNativeTokenSchema.shape.platform.value;
|
928
933
|
|
929
|
-
const fetchBalances$
|
934
|
+
const fetchBalances$9 = async ({
|
930
935
|
networkId,
|
931
936
|
tokensWithAddresses,
|
932
937
|
connector
|
@@ -938,8 +943,8 @@ const fetchBalances$7 = async ({
|
|
938
943
|
const client = await connector.getPublicClientForEvmNetwork(networkId);
|
939
944
|
if (!client) throw new Error(`Could not get rpc provider for evm network ${networkId}`);
|
940
945
|
for (const [token, addresses] of tokensWithAddresses) {
|
941
|
-
if (token.type !== MODULE_TYPE$
|
942
|
-
for (const address of addresses) if (!
|
946
|
+
if (token.type !== MODULE_TYPE$9 || token.networkId !== networkId) throw new Error(`Invalid token type or networkId for EVM ERC20 balance module: ${token.type} on ${token.networkId}`);
|
947
|
+
for (const address of addresses) if (!crypto.isEthereumAddress(address)) throw new Error(`Invalid ethereum address for EVM ERC20 balance module: ${address} for token ${token.id}`);
|
943
948
|
}
|
944
949
|
const balanceDefs = getBalanceDefs(tokensWithAddresses);
|
945
950
|
if (client.chain?.contracts?.multicall3 && balanceDefs.length > 1) {
|
@@ -965,7 +970,7 @@ const fetchWithoutMulticall = async (client, balanceDefs) => {
|
|
965
970
|
address,
|
966
971
|
tokenId: token.id,
|
967
972
|
value: result.toString(),
|
968
|
-
source: MODULE_TYPE$
|
973
|
+
source: MODULE_TYPE$9,
|
969
974
|
networkId: chaindataProvider.parseTokenId(token.id).networkId,
|
970
975
|
status: "live"
|
971
976
|
};
|
@@ -1011,7 +1016,7 @@ const fetchWithMulticall = async (client, balanceDefs, multicall3Address) => {
|
|
1011
1016
|
address: balanceDefs[index].address,
|
1012
1017
|
tokenId: balanceDefs[index].token.id,
|
1013
1018
|
value: result.result.toString(),
|
1014
|
-
source: MODULE_TYPE$
|
1019
|
+
source: MODULE_TYPE$9,
|
1015
1020
|
networkId: chaindataProvider.parseTokenId(balanceDefs[index].token.id).networkId,
|
1016
1021
|
status: "live"
|
1017
1022
|
});
|
@@ -1041,7 +1046,7 @@ const fetchWithMulticall = async (client, balanceDefs, multicall3Address) => {
|
|
1041
1046
|
}
|
1042
1047
|
};
|
1043
1048
|
|
1044
|
-
const fetchTokens$
|
1049
|
+
const fetchTokens$9 = async ({
|
1045
1050
|
networkId,
|
1046
1051
|
tokens
|
1047
1052
|
}) => {
|
@@ -1049,8 +1054,8 @@ const fetchTokens$7 = async ({
|
|
1049
1054
|
if (tokens.length !== 1) throw new Error("EVM Native module expects the nativeCurrency to be passed as a single token in the array");
|
1050
1055
|
const token = lodashEs.assign({
|
1051
1056
|
id: chaindataProvider.evmNativeTokenId(networkId),
|
1052
|
-
type: MODULE_TYPE$
|
1053
|
-
platform: PLATFORM$
|
1057
|
+
type: MODULE_TYPE$9,
|
1058
|
+
platform: PLATFORM$9,
|
1054
1059
|
networkId,
|
1055
1060
|
isDefault: true
|
1056
1061
|
}, tokens[0]);
|
@@ -1062,19 +1067,19 @@ const fetchTokens$7 = async ({
|
|
1062
1067
|
return [parsed.data];
|
1063
1068
|
};
|
1064
1069
|
|
1065
|
-
const getMiniMetadata$
|
1070
|
+
const getMiniMetadata$9 = () => {
|
1066
1071
|
throw new Error("MiniMetadata is not supported for ethereum tokens");
|
1067
1072
|
};
|
1068
1073
|
|
1069
|
-
const getTransferCallData$
|
1074
|
+
const getTransferCallData$9 = ({
|
1070
1075
|
from,
|
1071
1076
|
to,
|
1072
1077
|
value,
|
1073
1078
|
token
|
1074
1079
|
}) => {
|
1075
|
-
if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$
|
1076
|
-
if (!
|
1077
|
-
if (!
|
1080
|
+
if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$9)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$9}.`);
|
1081
|
+
if (!crypto.isEthereumAddress(from)) throw new Error("Invalid from address");
|
1082
|
+
if (!crypto.isEthereumAddress(to)) throw new Error("Invalid to address");
|
1078
1083
|
return {
|
1079
1084
|
from,
|
1080
1085
|
to,
|
@@ -1083,8 +1088,8 @@ const getTransferCallData$7 = ({
|
|
1083
1088
|
};
|
1084
1089
|
};
|
1085
1090
|
|
1086
|
-
const SUBSCRIPTION_INTERVAL$
|
1087
|
-
const subscribeBalances$
|
1091
|
+
const SUBSCRIPTION_INTERVAL$5 = 6_000;
|
1092
|
+
const subscribeBalances$9 = ({
|
1088
1093
|
networkId,
|
1089
1094
|
tokensWithAddresses,
|
1090
1095
|
connector
|
@@ -1098,17 +1103,17 @@ const subscribeBalances$7 = ({
|
|
1098
1103
|
const poll = async () => {
|
1099
1104
|
try {
|
1100
1105
|
if (abortController.signal.aborted) return;
|
1101
|
-
const balances = await fetchBalances$
|
1106
|
+
const balances = await fetchBalances$9({
|
1102
1107
|
networkId,
|
1103
1108
|
tokensWithAddresses: tokensWithAddresses,
|
1104
1109
|
connector
|
1105
1110
|
});
|
1106
1111
|
if (abortController.signal.aborted) return;
|
1107
1112
|
subscriber.next(balances);
|
1108
|
-
setTimeout(poll, SUBSCRIPTION_INTERVAL$
|
1113
|
+
setTimeout(poll, SUBSCRIPTION_INTERVAL$5);
|
1109
1114
|
} catch (error) {
|
1110
1115
|
log.error("Error", {
|
1111
|
-
module: MODULE_TYPE$
|
1116
|
+
module: MODULE_TYPE$9,
|
1112
1117
|
networkId,
|
1113
1118
|
addressesByToken: tokensWithAddresses,
|
1114
1119
|
error
|
@@ -1124,13 +1129,13 @@ const subscribeBalances$7 = ({
|
|
1124
1129
|
};
|
1125
1130
|
|
1126
1131
|
const EvmNativeBalanceModule = {
|
1127
|
-
type: MODULE_TYPE$
|
1128
|
-
platform: PLATFORM$
|
1129
|
-
getMiniMetadata: getMiniMetadata$
|
1130
|
-
fetchTokens: fetchTokens$
|
1131
|
-
fetchBalances: fetchBalances$
|
1132
|
-
subscribeBalances: subscribeBalances$
|
1133
|
-
getTransferCallData: getTransferCallData$
|
1132
|
+
type: MODULE_TYPE$9,
|
1133
|
+
platform: PLATFORM$9,
|
1134
|
+
getMiniMetadata: getMiniMetadata$9,
|
1135
|
+
fetchTokens: fetchTokens$9,
|
1136
|
+
fetchBalances: fetchBalances$9,
|
1137
|
+
subscribeBalances: subscribeBalances$9,
|
1138
|
+
getTransferCallData: getTransferCallData$9
|
1134
1139
|
};
|
1135
1140
|
|
1136
1141
|
// to be used by chaindata too
|
@@ -1138,10 +1143,10 @@ const EvmNativeTokenConfigSchema = z__default.default.strictObject({
|
|
1138
1143
|
...TokenConfigBaseSchema.shape
|
1139
1144
|
});
|
1140
1145
|
|
1141
|
-
const MODULE_TYPE$
|
1142
|
-
const PLATFORM$
|
1146
|
+
const MODULE_TYPE$8 = chaindataProvider.EvmUniswapV2TokenSchema.shape.type.value;
|
1147
|
+
const PLATFORM$8 = chaindataProvider.EvmUniswapV2TokenSchema.shape.platform.value;
|
1143
1148
|
|
1144
|
-
const fetchBalances$
|
1149
|
+
const fetchBalances$8 = async ({
|
1145
1150
|
networkId,
|
1146
1151
|
tokensWithAddresses,
|
1147
1152
|
connector
|
@@ -1153,8 +1158,8 @@ const fetchBalances$6 = async ({
|
|
1153
1158
|
const client = await connector.getPublicClientForEvmNetwork(networkId);
|
1154
1159
|
if (!client) throw new Error(`Could not get rpc provider for evm network ${networkId}`);
|
1155
1160
|
for (const [token, addresses] of tokensWithAddresses) {
|
1156
|
-
if (token.type !== MODULE_TYPE$
|
1157
|
-
for (const address of addresses) if (!
|
1161
|
+
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}`);
|
1162
|
+
for (const address of addresses) if (!crypto.isEthereumAddress(address)) throw new Error(`Invalid ethereum address for EVM ERC20 balance module: ${address} for token ${token.id}`);
|
1158
1163
|
}
|
1159
1164
|
const balanceDefs = getBalanceDefs(tokensWithAddresses);
|
1160
1165
|
return fetchPoolBalances(client, balanceDefs);
|
@@ -1240,7 +1245,7 @@ const fetchPoolBalances = async (client, balanceDefs) => {
|
|
1240
1245
|
acc.success.push({
|
1241
1246
|
address,
|
1242
1247
|
tokenId: token.id,
|
1243
|
-
source: MODULE_TYPE$
|
1248
|
+
source: MODULE_TYPE$8,
|
1244
1249
|
networkId: chaindataProvider.parseTokenId(token.id).networkId,
|
1245
1250
|
status: "live",
|
1246
1251
|
values: [{
|
@@ -1300,7 +1305,7 @@ const getUniswapV2PairContractData = async (client, contractAddress) => {
|
|
1300
1305
|
};
|
1301
1306
|
};
|
1302
1307
|
|
1303
|
-
const TokenCacheSchema = z__default.default.discriminatedUnion("isValid", [z__default.default.strictObject({
|
1308
|
+
const TokenCacheSchema$1 = z__default.default.discriminatedUnion("isValid", [z__default.default.strictObject({
|
1304
1309
|
id: chaindataProvider.EvmUniswapV2TokenSchema.shape.id,
|
1305
1310
|
isValid: z__default.default.literal(true),
|
1306
1311
|
...chaindataProvider.EvmUniswapV2TokenSchema.pick({
|
@@ -1318,7 +1323,7 @@ const TokenCacheSchema = z__default.default.discriminatedUnion("isValid", [z__de
|
|
1318
1323
|
id: chaindataProvider.EvmUniswapV2TokenSchema.shape.id,
|
1319
1324
|
isValid: z__default.default.literal(false)
|
1320
1325
|
})]);
|
1321
|
-
const fetchTokens$
|
1326
|
+
const fetchTokens$8 = async ({
|
1322
1327
|
networkId,
|
1323
1328
|
tokens,
|
1324
1329
|
connector,
|
@@ -1327,7 +1332,7 @@ const fetchTokens$6 = async ({
|
|
1327
1332
|
const result = [];
|
1328
1333
|
for (const tokenConfig of tokens) {
|
1329
1334
|
const tokenId = chaindataProvider.evmUniswapV2TokenId(networkId, tokenConfig.contractAddress);
|
1330
|
-
const cached = cache[tokenId] && TokenCacheSchema.safeParse(cache[tokenId]).data;
|
1335
|
+
const cached = cache[tokenId] && TokenCacheSchema$1.safeParse(cache[tokenId]).data;
|
1331
1336
|
if (!cached) {
|
1332
1337
|
const client = await connector.getPublicClientForEvmNetwork(networkId);
|
1333
1338
|
if (!client) {
|
@@ -1349,7 +1354,7 @@ const fetchTokens$6 = async ({
|
|
1349
1354
|
symbol: symbol1,
|
1350
1355
|
decimals: decimals1
|
1351
1356
|
} = await getErc20ContractData(client, token1);
|
1352
|
-
cache[tokenId] = TokenCacheSchema.parse({
|
1357
|
+
cache[tokenId] = TokenCacheSchema$1.parse({
|
1353
1358
|
id: tokenId,
|
1354
1359
|
symbol: `${symbol0}/${symbol1}`,
|
1355
1360
|
decimals,
|
@@ -1375,48 +1380,601 @@ const fetchTokens$6 = async ({
|
|
1375
1380
|
continue;
|
1376
1381
|
}
|
1377
1382
|
}
|
1383
|
+
const base = {
|
1384
|
+
id: tokenId,
|
1385
|
+
type: MODULE_TYPE$8,
|
1386
|
+
platform: PLATFORM$8,
|
1387
|
+
networkId
|
1388
|
+
};
|
1389
|
+
const cached2 = cache[tokenId] && TokenCacheSchema$1.safeParse(cache[tokenId]).data;
|
1390
|
+
if (cached2?.isValid === false) continue;
|
1391
|
+
const token = lodashEs.assign(base, cached2?.isValid ? lodashEs.omit(cached2, ["isValid"]) : {}, tokenConfig);
|
1392
|
+
const parsed = chaindataProvider.EvmUniswapV2TokenSchema.safeParse(token);
|
1393
|
+
if (!parsed.success) {
|
1394
|
+
log.warn("Ignoring token with invalid schema", token);
|
1395
|
+
continue;
|
1396
|
+
}
|
1397
|
+
result.push(parsed.data);
|
1398
|
+
}
|
1399
|
+
return result;
|
1400
|
+
};
|
1401
|
+
|
1402
|
+
const getMiniMetadata$8 = () => {
|
1403
|
+
throw new Error("MiniMetadata is not supported for ethereum tokens");
|
1404
|
+
};
|
1405
|
+
|
1406
|
+
const getTransferCallData$8 = ({
|
1407
|
+
from,
|
1408
|
+
to,
|
1409
|
+
value,
|
1410
|
+
token
|
1411
|
+
}) => {
|
1412
|
+
if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$8)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$8}.`);
|
1413
|
+
if (!crypto.isEthereumAddress(from)) throw new Error("Invalid from address");
|
1414
|
+
if (!crypto.isEthereumAddress(to)) throw new Error("Invalid to address");
|
1415
|
+
const data = viem.encodeFunctionData({
|
1416
|
+
abi: viem.erc20Abi,
|
1417
|
+
functionName: "transfer",
|
1418
|
+
args: [to, BigInt(value)]
|
1419
|
+
});
|
1420
|
+
return {
|
1421
|
+
from,
|
1422
|
+
to: token.contractAddress,
|
1423
|
+
data
|
1424
|
+
};
|
1425
|
+
};
|
1426
|
+
|
1427
|
+
const SUBSCRIPTION_INTERVAL$4 = 6_000;
|
1428
|
+
const subscribeBalances$8 = ({
|
1429
|
+
networkId,
|
1430
|
+
tokensWithAddresses,
|
1431
|
+
connector
|
1432
|
+
}) => {
|
1433
|
+
if (!tokensWithAddresses.length) return rxjs.of({
|
1434
|
+
success: [],
|
1435
|
+
errors: []
|
1436
|
+
});
|
1437
|
+
return new rxjs.Observable(subscriber => {
|
1438
|
+
const abortController = new AbortController();
|
1439
|
+
const poll = async () => {
|
1440
|
+
try {
|
1441
|
+
if (abortController.signal.aborted) return;
|
1442
|
+
const balances = await fetchBalances$8({
|
1443
|
+
networkId,
|
1444
|
+
tokensWithAddresses: tokensWithAddresses,
|
1445
|
+
connector
|
1446
|
+
});
|
1447
|
+
if (abortController.signal.aborted) return;
|
1448
|
+
subscriber.next(balances);
|
1449
|
+
setTimeout(poll, SUBSCRIPTION_INTERVAL$4);
|
1450
|
+
} catch (error) {
|
1451
|
+
log.error("Error", {
|
1452
|
+
module: MODULE_TYPE$8,
|
1453
|
+
networkId,
|
1454
|
+
addressesByToken: tokensWithAddresses,
|
1455
|
+
error
|
1456
|
+
});
|
1457
|
+
subscriber.error(error);
|
1458
|
+
}
|
1459
|
+
};
|
1460
|
+
poll();
|
1461
|
+
return () => {
|
1462
|
+
abortController.abort();
|
1463
|
+
};
|
1464
|
+
}).pipe(rxjs.distinctUntilChanged(lodashEs.isEqual));
|
1465
|
+
};
|
1466
|
+
|
1467
|
+
const EvmUniswapV2BalanceModule = {
|
1468
|
+
type: MODULE_TYPE$8,
|
1469
|
+
platform: PLATFORM$8,
|
1470
|
+
getMiniMetadata: getMiniMetadata$8,
|
1471
|
+
fetchTokens: fetchTokens$8,
|
1472
|
+
fetchBalances: fetchBalances$8,
|
1473
|
+
subscribeBalances: subscribeBalances$8,
|
1474
|
+
getTransferCallData: getTransferCallData$8
|
1475
|
+
};
|
1476
|
+
|
1477
|
+
// to be used by chaindata too
|
1478
|
+
const EvmUniswapV2TokenConfigSchema = z__default.default.strictObject({
|
1479
|
+
contractAddress: chaindataProvider.EvmUniswapV2TokenSchema.shape.contractAddress,
|
1480
|
+
...TokenConfigBaseSchema.shape
|
1481
|
+
});
|
1482
|
+
|
1483
|
+
const MODULE_TYPE$7 = chaindataProvider.SolNativeTokenSchema.shape.type.value;
|
1484
|
+
const PLATFORM$7 = chaindataProvider.SolNativeTokenSchema.shape.platform.value;
|
1485
|
+
|
1486
|
+
const fetchBalances$7 = async ({
|
1487
|
+
networkId,
|
1488
|
+
tokensWithAddresses,
|
1489
|
+
connector
|
1490
|
+
}) => {
|
1491
|
+
if (!tokensWithAddresses.length) return {
|
1492
|
+
success: [],
|
1493
|
+
errors: []
|
1494
|
+
};
|
1495
|
+
const connection = await connector.getConnection(networkId);
|
1496
|
+
if (!connection) throw new Error(`Could not get rpc provider for sol network ${networkId}`);
|
1497
|
+
for (const [token, addresses] of tokensWithAddresses) {
|
1498
|
+
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}`);
|
1499
|
+
for (const address of addresses) if (!crypto.isSolanaAddress(address)) throw new Error(`Invalid solana address for balance module: ${address} for token ${token.id}`);
|
1500
|
+
}
|
1501
|
+
const balanceDefs = getBalanceDefs(tokensWithAddresses);
|
1502
|
+
const results = await Promise.allSettled(balanceDefs.map(async ({
|
1503
|
+
token,
|
1504
|
+
address
|
1505
|
+
}) => {
|
1506
|
+
try {
|
1507
|
+
const publicKey = new web3_js.PublicKey(address);
|
1508
|
+
const lamports = await connection.getBalance(publicKey);
|
1509
|
+
return {
|
1510
|
+
address: address,
|
1511
|
+
tokenId: token.id,
|
1512
|
+
value: lamports.toString(),
|
1513
|
+
source: MODULE_TYPE$7,
|
1514
|
+
networkId: token.networkId,
|
1515
|
+
status: "live"
|
1516
|
+
};
|
1517
|
+
} catch (err) {
|
1518
|
+
throw new BalanceFetchError(`Failed to get balance for token ${token.id} and address ${address} on chain ${networkId}`, token.id, address, err);
|
1519
|
+
}
|
1520
|
+
}));
|
1521
|
+
return results.reduce((acc, result) => {
|
1522
|
+
if (result.status === "fulfilled") acc.success.push(result.value);else {
|
1523
|
+
const error = result.reason;
|
1524
|
+
acc.errors.push({
|
1525
|
+
tokenId: error.tokenId,
|
1526
|
+
address: error.address,
|
1527
|
+
error
|
1528
|
+
});
|
1529
|
+
}
|
1530
|
+
return acc;
|
1531
|
+
}, {
|
1532
|
+
success: [],
|
1533
|
+
errors: []
|
1534
|
+
});
|
1535
|
+
};
|
1536
|
+
|
1537
|
+
const fetchTokens$7 = async ({
|
1538
|
+
networkId,
|
1539
|
+
tokens
|
1540
|
+
}) => {
|
1541
|
+
// assume there is one and only one token in the array
|
1542
|
+
if (tokens.length !== 1) throw new Error("EVM Native module expects the nativeCurrency to be passed as a single token in the array");
|
1543
|
+
const token = lodashEs.assign({
|
1544
|
+
id: chaindataProvider.solNativeTokenId(networkId),
|
1545
|
+
type: MODULE_TYPE$7,
|
1546
|
+
platform: PLATFORM$7,
|
1547
|
+
networkId,
|
1548
|
+
isDefault: true
|
1549
|
+
}, tokens[0]);
|
1550
|
+
const parsed = chaindataProvider.SolNativeTokenSchema.safeParse(token);
|
1551
|
+
if (!parsed.success) {
|
1552
|
+
log.warn("Ignoring token with invalid schema", token);
|
1553
|
+
return [];
|
1554
|
+
}
|
1555
|
+
return [parsed.data];
|
1556
|
+
};
|
1557
|
+
|
1558
|
+
const getMiniMetadata$7 = () => {
|
1559
|
+
throw new Error("MiniMetadata is not supported for sol-native tokens");
|
1560
|
+
};
|
1561
|
+
|
1562
|
+
const getTransferCallData$7 = ({
|
1563
|
+
from,
|
1564
|
+
to,
|
1565
|
+
value,
|
1566
|
+
token
|
1567
|
+
}) => {
|
1568
|
+
if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$7)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$7}.`);
|
1569
|
+
const fromPubkey = new web3_js.PublicKey(from);
|
1570
|
+
const transferIx = web3_js.SystemProgram.transfer({
|
1571
|
+
fromPubkey,
|
1572
|
+
toPubkey: new web3_js.PublicKey(to),
|
1573
|
+
lamports: Number(value)
|
1574
|
+
});
|
1575
|
+
return [transferIx];
|
1576
|
+
};
|
1577
|
+
|
1578
|
+
const SUBSCRIPTION_INTERVAL$3 = 6_000;
|
1579
|
+
const subscribeBalances$7 = ({
|
1580
|
+
networkId,
|
1581
|
+
tokensWithAddresses,
|
1582
|
+
connector
|
1583
|
+
}) => {
|
1584
|
+
if (!tokensWithAddresses.length) return rxjs.of({
|
1585
|
+
success: [],
|
1586
|
+
errors: []
|
1587
|
+
});
|
1588
|
+
return new rxjs.Observable(subscriber => {
|
1589
|
+
const abortController = new AbortController();
|
1590
|
+
const poll = async () => {
|
1591
|
+
try {
|
1592
|
+
if (abortController.signal.aborted) return;
|
1593
|
+
const balances = await fetchBalances$7({
|
1594
|
+
networkId,
|
1595
|
+
tokensWithAddresses,
|
1596
|
+
connector
|
1597
|
+
});
|
1598
|
+
if (abortController.signal.aborted) return;
|
1599
|
+
subscriber.next(balances);
|
1600
|
+
setTimeout(poll, SUBSCRIPTION_INTERVAL$3);
|
1601
|
+
} catch (error) {
|
1602
|
+
log.error("Error", {
|
1603
|
+
module: MODULE_TYPE$7,
|
1604
|
+
networkId,
|
1605
|
+
tokensWithAddresses,
|
1606
|
+
error
|
1607
|
+
});
|
1608
|
+
subscriber.error(error);
|
1609
|
+
}
|
1610
|
+
};
|
1611
|
+
poll();
|
1612
|
+
return () => {
|
1613
|
+
abortController.abort();
|
1614
|
+
};
|
1615
|
+
}).pipe(rxjs.distinctUntilChanged(lodashEs.isEqual));
|
1616
|
+
};
|
1617
|
+
|
1618
|
+
const SolNativeBalanceModule = {
|
1619
|
+
type: MODULE_TYPE$7,
|
1620
|
+
platform: PLATFORM$7,
|
1621
|
+
getMiniMetadata: getMiniMetadata$7,
|
1622
|
+
fetchTokens: fetchTokens$7,
|
1623
|
+
fetchBalances: fetchBalances$7,
|
1624
|
+
subscribeBalances: subscribeBalances$7,
|
1625
|
+
getTransferCallData: getTransferCallData$7
|
1626
|
+
};
|
1627
|
+
|
1628
|
+
// to be used by chaindata too
|
1629
|
+
const SolNativeTokenConfigSchema = z__default.default.strictObject({
|
1630
|
+
...TokenConfigBaseSchema.shape
|
1631
|
+
});
|
1632
|
+
|
1633
|
+
const MODULE_TYPE$6 = chaindataProvider.SolSplTokenSchema.shape.type.value;
|
1634
|
+
const PLATFORM$6 = chaindataProvider.SolSplTokenSchema.shape.platform.value;
|
1635
|
+
|
1636
|
+
const fetchRuntimeCallResult = async (connector, networkId, metadataRpc, apiName, method, args) => {
|
1637
|
+
const {
|
1638
|
+
builder
|
1639
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
1640
|
+
const call = builder.buildRuntimeCall(apiName, method);
|
1641
|
+
const hex = await connector.send(networkId, "state_call", [`${apiName}_${method}`, scale.toHex(call.args.enc(args))]);
|
1642
|
+
return call.value.dec(hex);
|
1643
|
+
};
|
1644
|
+
|
1645
|
+
const hasStorageItem = (metadata, palletName, itemName) => {
|
1646
|
+
const pallet = metadata.pallets.find(p => p.name === palletName);
|
1647
|
+
if (!pallet || !pallet.storage) return false;
|
1648
|
+
return pallet.storage.items.some(item => item.name === itemName);
|
1649
|
+
};
|
1650
|
+
const hasStorageItems = (metadata, palletName, itemNames) => {
|
1651
|
+
const pallet = metadata.pallets.find(p => p.name === palletName);
|
1652
|
+
if (!pallet || !pallet.storage) return false;
|
1653
|
+
return itemNames.every(itemName => pallet.storage?.items.some(item => item.name === itemName));
|
1654
|
+
};
|
1655
|
+
const hasRuntimeApi = (metadata, apiName, method) => {
|
1656
|
+
const api = metadata.apis.find(api => api.name === apiName);
|
1657
|
+
if (!api || !api.methods) return false;
|
1658
|
+
return api.methods.some(m => m.name === method);
|
1659
|
+
};
|
1660
|
+
const getConstantValue = (metadataRpc, pallet, constant) => {
|
1661
|
+
const {
|
1662
|
+
unifiedMetadata,
|
1663
|
+
builder
|
1664
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
1665
|
+
const codec = builder.buildConstant(pallet, constant);
|
1666
|
+
const encodedValue = unifiedMetadata.pallets.find(({
|
1667
|
+
name
|
1668
|
+
}) => name === pallet)?.constants.find(({
|
1669
|
+
name
|
1670
|
+
}) => name === constant)?.value;
|
1671
|
+
if (!encodedValue) throw new Error(`Constant ${pallet}.${constant} not found`);
|
1672
|
+
return codec.dec(encodedValue);
|
1673
|
+
};
|
1674
|
+
const tryGetConstantValue = (metadataRpc, pallet, constant) => {
|
1675
|
+
const {
|
1676
|
+
unifiedMetadata,
|
1677
|
+
builder
|
1678
|
+
} = scale.parseMetadataRpc(metadataRpc);
|
1679
|
+
const encodedValue = unifiedMetadata.pallets.find(({
|
1680
|
+
name
|
1681
|
+
}) => name === pallet)?.constants.find(({
|
1682
|
+
name
|
1683
|
+
}) => name === constant)?.value;
|
1684
|
+
if (!encodedValue) return null;
|
1685
|
+
const codec = builder.buildConstant(pallet, constant);
|
1686
|
+
return codec.dec(encodedValue);
|
1687
|
+
};
|
1688
|
+
|
1689
|
+
const fetchRpcQueryPack = async (connector, networkId, queries) => {
|
1690
|
+
const allStateKeys = queries.flatMap(({
|
1691
|
+
stateKeys
|
1692
|
+
}) => stateKeys).filter(util.isNotNil);
|
1693
|
+
|
1694
|
+
// doing a query without keys would throw an error => return early
|
1695
|
+
if (!allStateKeys.length) return queries.map(({
|
1696
|
+
stateKeys,
|
1697
|
+
decodeResult
|
1698
|
+
}) => decodeResult(stateKeys.map(() => null)));
|
1699
|
+
const [result] = await connector.send(networkId, "state_queryStorageAt", [allStateKeys]);
|
1700
|
+
return decodeRpcQueryPack(queries, result);
|
1701
|
+
};
|
1702
|
+
const getRpcQueryPack$ = (connector, networkId, queries, timeout = false) => {
|
1703
|
+
const allStateKeys = queries.flatMap(({
|
1704
|
+
stateKeys
|
1705
|
+
}) => stateKeys).filter(util.isNotNil);
|
1706
|
+
|
1707
|
+
// doing a query without keys would throw an error => return early
|
1708
|
+
if (!allStateKeys.length) return rxjs.of(queries.map(({
|
1709
|
+
stateKeys,
|
1710
|
+
decodeResult
|
1711
|
+
}) => decodeResult(stateKeys.map(() => null))));
|
1712
|
+
return new rxjs.Observable(subscriber => {
|
1713
|
+
// first subscription callback includes results for all state keys, but further callbacks will only include the ones that changed
|
1714
|
+
// => we need to keep all results in memory and update them after each callback, so we can emit the full result set each time
|
1715
|
+
const changesCache = {};
|
1716
|
+
const promUnsub = connector.subscribe(networkId, "state_subscribeStorage", "state_storage", [allStateKeys], (error, result) => {
|
1717
|
+
if (error) subscriber.error(error);else if (result) {
|
1718
|
+
// update the cache
|
1719
|
+
for (const [stateKey, encodedResult] of result.changes) changesCache[stateKey] = encodedResult;
|
1720
|
+
|
1721
|
+
// regenerate the full changes array
|
1722
|
+
const changes = lodashEs.toPairs(changesCache);
|
1723
|
+
|
1724
|
+
// decode and emit results for all queries
|
1725
|
+
subscriber.next(decodeRpcQueryPack(queries, {
|
1726
|
+
block: result.block,
|
1727
|
+
changes
|
1728
|
+
}));
|
1729
|
+
}
|
1730
|
+
}, timeout);
|
1731
|
+
return () => {
|
1732
|
+
promUnsub.then(unsub => unsub("state_unsubscribeStorage"));
|
1733
|
+
};
|
1734
|
+
});
|
1735
|
+
};
|
1736
|
+
const decodeRpcQueryPack = (queries, result) => {
|
1737
|
+
return queries.reduce((acc, {
|
1738
|
+
stateKeys,
|
1739
|
+
decodeResult
|
1740
|
+
}) => {
|
1741
|
+
const changes = stateKeys.map(stateKey => {
|
1742
|
+
if (!stateKey || !result) return null;
|
1743
|
+
const change = result.changes.find(([key]) => key === stateKey);
|
1744
|
+
if (!change) return null;
|
1745
|
+
return change[1];
|
1746
|
+
});
|
1747
|
+
acc.push(decodeResult(changes));
|
1748
|
+
return acc;
|
1749
|
+
}, []);
|
1750
|
+
};
|
1751
|
+
|
1752
|
+
const buildNetworkStorageCoders = (chainId, miniMetadata, coders) => {
|
1753
|
+
if (!miniMetadata.data) return null;
|
1754
|
+
const metadata = scale.unifyMetadata(scale.decAnyMetadata(miniMetadata.data));
|
1755
|
+
try {
|
1756
|
+
const scaleBuilder = scale.getDynamicBuilder(scale.getLookupFn(metadata));
|
1757
|
+
const builtCoders = Object.fromEntries(Object.entries(coders).flatMap(([key, moduleMethodOrFn]) => {
|
1758
|
+
const [module, method] = typeof moduleMethodOrFn === "function" ? moduleMethodOrFn({
|
1759
|
+
chainId
|
1760
|
+
}) : moduleMethodOrFn;
|
1761
|
+
try {
|
1762
|
+
return [[key, scaleBuilder.buildStorage(module, method)]];
|
1763
|
+
} catch (cause) {
|
1764
|
+
log.trace(`Failed to build SCALE coder for chain ${chainId} (${module}::${method})`, cause);
|
1765
|
+
return [];
|
1766
|
+
}
|
1767
|
+
}));
|
1768
|
+
return builtCoders;
|
1769
|
+
} catch (cause) {
|
1770
|
+
log.error(`Failed to build SCALE coders for chain ${chainId} (${JSON.stringify(coders)})`, cause);
|
1771
|
+
}
|
1772
|
+
return null;
|
1773
|
+
};
|
1774
|
+
|
1775
|
+
const SPL_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
|
1776
|
+
const fetchBalances$6 = async ({
|
1777
|
+
networkId,
|
1778
|
+
tokensWithAddresses,
|
1779
|
+
connector
|
1780
|
+
}) => {
|
1781
|
+
if (!tokensWithAddresses.length) return {
|
1782
|
+
success: [],
|
1783
|
+
errors: []
|
1784
|
+
};
|
1785
|
+
const connection = await connector.getConnection(networkId);
|
1786
|
+
if (!connection) throw new Error(`Could not get connection for Solana network ${networkId}`);
|
1787
|
+
const accountAddresses = lodashEs.uniq(tokensWithAddresses.flatMap(([, addresses]) => addresses));
|
1788
|
+
const balancesPerAddress = await Promise.all(accountAddresses.map(async address => {
|
1789
|
+
const tokenAccounts = await connection.getParsedTokenAccountsByOwner(new web3_js.PublicKey(address), {
|
1790
|
+
programId: new web3_js.PublicKey(SPL_PROGRAM_ID) // SPL Token Program ID
|
1791
|
+
});
|
1792
|
+
const balances = tokenAccounts.value.map(d => {
|
1793
|
+
try {
|
1794
|
+
const mintAddress = d.account.data.parsed.info.mint;
|
1795
|
+
const value = d.account.data.parsed.info.tokenAmount.amount ?? "0";
|
1796
|
+
return {
|
1797
|
+
tokenId: chaindataProvider.solSplTokenId(networkId, mintAddress),
|
1798
|
+
networkId,
|
1799
|
+
address,
|
1800
|
+
source: MODULE_TYPE$6,
|
1801
|
+
status: "live",
|
1802
|
+
value
|
1803
|
+
};
|
1804
|
+
} catch (err) {
|
1805
|
+
log.warn("Failed to parse token amount", {
|
1806
|
+
address,
|
1807
|
+
d
|
1808
|
+
});
|
1809
|
+
return null;
|
1810
|
+
}
|
1811
|
+
}).filter(util.isNotNil);
|
1812
|
+
return [address, balances];
|
1813
|
+
}));
|
1814
|
+
const allBalancesByKey = lodashEs.keyBy(balancesPerAddress.flatMap(([, addressBalances]) => addressBalances), b => getBalanceKey(b.tokenId, b.address));
|
1815
|
+
const balanceDefs = getBalanceDefs(tokensWithAddresses);
|
1816
|
+
|
1817
|
+
// return a balance entry for all token/address pairs that were requested
|
1818
|
+
const success = balanceDefs.map(bd => {
|
1819
|
+
const found = allBalancesByKey[getBalanceKey(bd.token.id, bd.address)];
|
1820
|
+
return found ?? {
|
1821
|
+
tokenId: bd.token.id,
|
1822
|
+
networkId: bd.token.networkId,
|
1823
|
+
address: bd.address,
|
1824
|
+
source: MODULE_TYPE$6,
|
1825
|
+
status: "live",
|
1826
|
+
value: "0"
|
1827
|
+
};
|
1828
|
+
});
|
1829
|
+
|
1830
|
+
// return only the balances that match the tokens we are interested in
|
1831
|
+
return {
|
1832
|
+
success,
|
1833
|
+
errors: []
|
1834
|
+
}; // TODO output errors if any
|
1835
|
+
};
|
1836
|
+
const getBalanceKey = (tokenId, address) => `${tokenId}:${address}`;
|
1837
|
+
|
1838
|
+
const TokenCacheSchema = z__default.default.discriminatedUnion("isValid", [z__default.default.strictObject({
|
1839
|
+
id: chaindataProvider.SolSplTokenSchema.shape.id,
|
1840
|
+
isValid: z__default.default.literal(true),
|
1841
|
+
...chaindataProvider.SolSplTokenSchema.pick({
|
1842
|
+
symbol: true,
|
1843
|
+
decimals: true,
|
1844
|
+
name: true,
|
1845
|
+
logo: true
|
1846
|
+
}).shape
|
1847
|
+
}), z__default.default.strictObject({
|
1848
|
+
id: chaindataProvider.SolSplTokenSchema.shape.id,
|
1849
|
+
isValid: z__default.default.literal(false)
|
1850
|
+
})]);
|
1851
|
+
const METAPLEX_PROGRAM_ID = new web3_js.PublicKey("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s");
|
1852
|
+
const fetchTokens$6 = async ({
|
1853
|
+
networkId,
|
1854
|
+
tokens,
|
1855
|
+
connector,
|
1856
|
+
cache
|
1857
|
+
}) => {
|
1858
|
+
const result = [];
|
1859
|
+
for (const tokenConfig of tokens) {
|
1860
|
+
const tokenId = chaindataProvider.solSplTokenId(networkId, tokenConfig.mintAddress);
|
1861
|
+
let cached = cache[tokenId] && TokenCacheSchema.safeParse(cache[tokenId]).data;
|
1862
|
+
if (!cached) {
|
1863
|
+
const tokenInfo = await fetchOnChainTokenData(connector, tokenId);
|
1864
|
+
if (tokenInfo) cache[tokenId] = tokenInfo;
|
1865
|
+
}
|
1866
|
+
cached = cache[tokenId] && TokenCacheSchema.safeParse(cache[tokenId]).data;
|
1867
|
+
if (cached?.isValid === false) continue;
|
1378
1868
|
const base = {
|
1379
1869
|
id: tokenId,
|
1380
1870
|
type: MODULE_TYPE$6,
|
1381
1871
|
platform: PLATFORM$6,
|
1382
1872
|
networkId
|
1383
1873
|
};
|
1384
|
-
const
|
1385
|
-
|
1386
|
-
const token = lodashEs.assign(base, cached2?.isValid ? lodashEs.omit(cached2, ["isValid"]) : {}, tokenConfig);
|
1387
|
-
const parsed = chaindataProvider.EvmUniswapV2TokenSchema.safeParse(token);
|
1874
|
+
const token = lodashEs.assign(base, cached?.isValid ? lodashEs.omit(cached, ["isValid"]) : {}, tokenConfig);
|
1875
|
+
const parsed = chaindataProvider.SolSplTokenSchema.safeParse(token);
|
1388
1876
|
if (!parsed.success) {
|
1389
|
-
log.warn("Ignoring token with invalid
|
1877
|
+
log.warn("Ignoring token with invalid SolSplTokenSchema", {
|
1878
|
+
token
|
1879
|
+
});
|
1390
1880
|
continue;
|
1391
1881
|
}
|
1392
1882
|
result.push(parsed.data);
|
1393
1883
|
}
|
1394
1884
|
return result;
|
1395
1885
|
};
|
1886
|
+
const ERROR_NO_MINT = "No mint info available";
|
1887
|
+
const ERROR_NO_METADATA = "No metadata account found";
|
1888
|
+
const ERROR_INVALID_DATA = "Invalid on-chain data";
|
1889
|
+
const fetchOnChainTokenData = async (connector, tokenId) => {
|
1890
|
+
try {
|
1891
|
+
const {
|
1892
|
+
networkId,
|
1893
|
+
mintAddress
|
1894
|
+
} = chaindataProvider.parseSolSplTokenId(tokenId);
|
1895
|
+
const connection = await connector.getConnection(networkId);
|
1896
|
+
if (!connection) {
|
1897
|
+
log.warn(`No connection found for network ${networkId}`);
|
1898
|
+
return null;
|
1899
|
+
}
|
1900
|
+
const mintPubKey = new web3_js.PublicKey(mintAddress);
|
1901
|
+
const mintInfo = await connection.getAccountInfo(mintPubKey);
|
1902
|
+
if (!mintInfo?.data) throw new Error(ERROR_NO_MINT);
|
1903
|
+
const mint = splToken.MintLayout.decode(mintInfo.data);
|
1904
|
+
const [metadataPDA] = web3_js.PublicKey.findProgramAddressSync([Buffer.from("metadata"), METAPLEX_PROGRAM_ID.toBuffer(), mintPubKey.toBuffer()], METAPLEX_PROGRAM_ID);
|
1905
|
+
|
1906
|
+
// 3. Fetch metadata account directly (traditional way)
|
1907
|
+
const metadataAccount = await connection.getAccountInfo(new web3_js.PublicKey(metadataPDA));
|
1908
|
+
if (!metadataAccount) throw new Error(ERROR_NO_METADATA);
|
1909
|
+
const metadata = mplTokenMetadata.deserializeMetadata({
|
1910
|
+
publicKey: umi.publicKey(metadataPDA),
|
1911
|
+
executable: metadataAccount.executable,
|
1912
|
+
owner: umi.publicKey(metadataAccount.owner),
|
1913
|
+
lamports: umi.sol(metadataAccount.lamports),
|
1914
|
+
data: metadataAccount.data
|
1915
|
+
});
|
1916
|
+
const parsed = TokenCacheSchema.safeParse({
|
1917
|
+
id: tokenId,
|
1918
|
+
symbol: metadata.symbol.trim(),
|
1919
|
+
name: metadata.name.trim(),
|
1920
|
+
decimals: mint.decimals,
|
1921
|
+
isValid: true
|
1922
|
+
});
|
1923
|
+
if (!parsed.success) throw new Error(ERROR_INVALID_DATA);
|
1924
|
+
return parsed.data;
|
1925
|
+
} catch (err) {
|
1926
|
+
const msg = err.message;
|
1927
|
+
if ([ERROR_NO_MINT, ERROR_NO_METADATA, ERROR_INVALID_DATA].includes(msg)) return TokenCacheSchema.parse({
|
1928
|
+
id: tokenId,
|
1929
|
+
isValid: false
|
1930
|
+
});
|
1931
|
+
log.warn("Failed to fetch sol-spl token data for %s", tokenId, {
|
1932
|
+
err
|
1933
|
+
});
|
1934
|
+
}
|
1935
|
+
return null;
|
1936
|
+
};
|
1396
1937
|
|
1397
1938
|
const getMiniMetadata$6 = () => {
|
1398
|
-
throw new Error("MiniMetadata is not supported for
|
1939
|
+
throw new Error("MiniMetadata is not supported for solana tokens");
|
1399
1940
|
};
|
1400
1941
|
|
1401
|
-
const getTransferCallData$6 = ({
|
1942
|
+
const getTransferCallData$6 = async ({
|
1402
1943
|
from,
|
1403
1944
|
to,
|
1404
1945
|
value,
|
1405
|
-
token
|
1946
|
+
token,
|
1947
|
+
connector
|
1406
1948
|
}) => {
|
1407
1949
|
if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$6)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$6}.`);
|
1408
|
-
|
1409
|
-
|
1410
|
-
const
|
1411
|
-
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1417
|
-
|
1418
|
-
|
1419
|
-
|
1950
|
+
const connection = await connector.getConnection(token.networkId);
|
1951
|
+
const instructions = [];
|
1952
|
+
const mint = new web3_js.PublicKey(token.mintAddress);
|
1953
|
+
const fromWallet = new web3_js.PublicKey(from);
|
1954
|
+
const toWallet = new web3_js.PublicKey(to);
|
1955
|
+
|
1956
|
+
// Get associated token accounts
|
1957
|
+
const fromTokenAccount = await splToken.getAssociatedTokenAddress(mint, fromWallet);
|
1958
|
+
const toTokenAccount = await splToken.getAssociatedTokenAddress(mint, toWallet);
|
1959
|
+
|
1960
|
+
// Create the target token account if it doesn't exist
|
1961
|
+
if (!(await tokenAccountExists(connection, toTokenAccount))) {
|
1962
|
+
instructions.push(splToken.createAssociatedTokenAccountInstruction(fromWallet,
|
1963
|
+
// funder
|
1964
|
+
toTokenAccount, toWallet, mint));
|
1965
|
+
}
|
1966
|
+
|
1967
|
+
// Transfer the tokens
|
1968
|
+
instructions.push(splToken.createTransferInstruction(fromTokenAccount, toTokenAccount, fromWallet, BigInt(value), [], splToken.TOKEN_PROGRAM_ID));
|
1969
|
+
return instructions;
|
1970
|
+
};
|
1971
|
+
const tokenAccountExists = async (connection, address) => {
|
1972
|
+
try {
|
1973
|
+
await splToken.getAccount(connection, address);
|
1974
|
+
return true;
|
1975
|
+
} catch {
|
1976
|
+
return false;
|
1977
|
+
}
|
1420
1978
|
};
|
1421
1979
|
|
1422
1980
|
const SUBSCRIPTION_INTERVAL$2 = 6_000;
|
@@ -1459,7 +2017,7 @@ const subscribeBalances$6 = ({
|
|
1459
2017
|
}).pipe(rxjs.distinctUntilChanged(lodashEs.isEqual));
|
1460
2018
|
};
|
1461
2019
|
|
1462
|
-
const
|
2020
|
+
const SolSplBalanceModule = {
|
1463
2021
|
type: MODULE_TYPE$6,
|
1464
2022
|
platform: PLATFORM$6,
|
1465
2023
|
getMiniMetadata: getMiniMetadata$6,
|
@@ -1470,153 +2028,14 @@ const EvmUniswapV2BalanceModule = {
|
|
1470
2028
|
};
|
1471
2029
|
|
1472
2030
|
// to be used by chaindata too
|
1473
|
-
const
|
1474
|
-
|
2031
|
+
const SolSplTokenConfigSchema = z__default.default.strictObject({
|
2032
|
+
mintAddress: chaindataProvider.SolSplTokenSchema.shape.mintAddress,
|
1475
2033
|
...TokenConfigBaseSchema.shape
|
1476
2034
|
});
|
1477
2035
|
|
1478
2036
|
const MODULE_TYPE$5 = chaindataProvider.SubAssetsTokenSchema.shape.type.value;
|
1479
2037
|
const PLATFORM$5 = chaindataProvider.SubAssetsTokenSchema.shape.platform.value;
|
1480
2038
|
|
1481
|
-
const fetchRpcQueryPack = async (connector, networkId, queries) => {
|
1482
|
-
const allStateKeys = queries.flatMap(({
|
1483
|
-
stateKeys
|
1484
|
-
}) => stateKeys).filter(util.isNotNil);
|
1485
|
-
|
1486
|
-
// doing a query without keys would throw an error => return early
|
1487
|
-
if (!allStateKeys.length) return queries.map(({
|
1488
|
-
stateKeys,
|
1489
|
-
decodeResult
|
1490
|
-
}) => decodeResult(stateKeys.map(() => null)));
|
1491
|
-
const [result] = await connector.send(networkId, "state_queryStorageAt", [allStateKeys]);
|
1492
|
-
return decodeRpcQueryPack(queries, result);
|
1493
|
-
};
|
1494
|
-
const getRpcQueryPack$ = (connector, networkId, queries, timeout = false) => {
|
1495
|
-
const allStateKeys = queries.flatMap(({
|
1496
|
-
stateKeys
|
1497
|
-
}) => stateKeys).filter(util.isNotNil);
|
1498
|
-
|
1499
|
-
// doing a query without keys would throw an error => return early
|
1500
|
-
if (!allStateKeys.length) return rxjs.of(queries.map(({
|
1501
|
-
stateKeys,
|
1502
|
-
decodeResult
|
1503
|
-
}) => decodeResult(stateKeys.map(() => null))));
|
1504
|
-
return new rxjs.Observable(subscriber => {
|
1505
|
-
// first subscription callback includes results for all state keys, but further callbacks will only include the ones that changed
|
1506
|
-
// => we need to keep all results in memory and update them after each callback, so we can emit the full result set each time
|
1507
|
-
const changesCache = {};
|
1508
|
-
const promUnsub = connector.subscribe(networkId, "state_subscribeStorage", "state_storage", [allStateKeys], (error, result) => {
|
1509
|
-
if (error) subscriber.error(error);else if (result) {
|
1510
|
-
// update the cache
|
1511
|
-
for (const [stateKey, encodedResult] of result.changes) changesCache[stateKey] = encodedResult;
|
1512
|
-
|
1513
|
-
// regenerate the full changes array
|
1514
|
-
const changes = lodashEs.toPairs(changesCache);
|
1515
|
-
|
1516
|
-
// decode and emit results for all queries
|
1517
|
-
subscriber.next(decodeRpcQueryPack(queries, {
|
1518
|
-
block: result.block,
|
1519
|
-
changes
|
1520
|
-
}));
|
1521
|
-
}
|
1522
|
-
}, timeout);
|
1523
|
-
return () => {
|
1524
|
-
promUnsub.then(unsub => unsub("state_unsubscribeStorage"));
|
1525
|
-
};
|
1526
|
-
});
|
1527
|
-
};
|
1528
|
-
const decodeRpcQueryPack = (queries, result) => {
|
1529
|
-
return queries.reduce((acc, {
|
1530
|
-
stateKeys,
|
1531
|
-
decodeResult
|
1532
|
-
}) => {
|
1533
|
-
const changes = stateKeys.map(stateKey => {
|
1534
|
-
if (!stateKey || !result) return null;
|
1535
|
-
const change = result.changes.find(([key]) => key === stateKey);
|
1536
|
-
if (!change) return null;
|
1537
|
-
return change[1];
|
1538
|
-
});
|
1539
|
-
acc.push(decodeResult(changes));
|
1540
|
-
return acc;
|
1541
|
-
}, []);
|
1542
|
-
};
|
1543
|
-
|
1544
|
-
const fetchRuntimeCallResult = async (connector, networkId, metadataRpc, apiName, method, args) => {
|
1545
|
-
const {
|
1546
|
-
builder
|
1547
|
-
} = scale.parseMetadataRpc(metadataRpc);
|
1548
|
-
const call = builder.buildRuntimeCall(apiName, method);
|
1549
|
-
const hex = await connector.send(networkId, "state_call", [`${apiName}_${method}`, scale.toHex(call.args.enc(args))]);
|
1550
|
-
return call.value.dec(hex);
|
1551
|
-
};
|
1552
|
-
|
1553
|
-
const hasStorageItem = (metadata, palletName, itemName) => {
|
1554
|
-
const pallet = metadata.pallets.find(p => p.name === palletName);
|
1555
|
-
if (!pallet || !pallet.storage) return false;
|
1556
|
-
return pallet.storage.items.some(item => item.name === itemName);
|
1557
|
-
};
|
1558
|
-
const hasStorageItems = (metadata, palletName, itemNames) => {
|
1559
|
-
const pallet = metadata.pallets.find(p => p.name === palletName);
|
1560
|
-
if (!pallet || !pallet.storage) return false;
|
1561
|
-
return itemNames.every(itemName => pallet.storage?.items.some(item => item.name === itemName));
|
1562
|
-
};
|
1563
|
-
const hasRuntimeApi = (metadata, apiName, method) => {
|
1564
|
-
const api = metadata.apis.find(api => api.name === apiName);
|
1565
|
-
if (!api || !api.methods) return false;
|
1566
|
-
return api.methods.some(m => m.name === method);
|
1567
|
-
};
|
1568
|
-
const getConstantValue = (metadataRpc, pallet, constant) => {
|
1569
|
-
const {
|
1570
|
-
unifiedMetadata,
|
1571
|
-
builder
|
1572
|
-
} = scale.parseMetadataRpc(metadataRpc);
|
1573
|
-
const codec = builder.buildConstant(pallet, constant);
|
1574
|
-
const encodedValue = unifiedMetadata.pallets.find(({
|
1575
|
-
name
|
1576
|
-
}) => name === pallet)?.constants.find(({
|
1577
|
-
name
|
1578
|
-
}) => name === constant)?.value;
|
1579
|
-
if (!encodedValue) throw new Error(`Constant ${pallet}.${constant} not found`);
|
1580
|
-
return codec.dec(encodedValue);
|
1581
|
-
};
|
1582
|
-
const tryGetConstantValue = (metadataRpc, pallet, constant) => {
|
1583
|
-
const {
|
1584
|
-
unifiedMetadata,
|
1585
|
-
builder
|
1586
|
-
} = scale.parseMetadataRpc(metadataRpc);
|
1587
|
-
const encodedValue = unifiedMetadata.pallets.find(({
|
1588
|
-
name
|
1589
|
-
}) => name === pallet)?.constants.find(({
|
1590
|
-
name
|
1591
|
-
}) => name === constant)?.value;
|
1592
|
-
if (!encodedValue) return null;
|
1593
|
-
const codec = builder.buildConstant(pallet, constant);
|
1594
|
-
return codec.dec(encodedValue);
|
1595
|
-
};
|
1596
|
-
|
1597
|
-
const buildNetworkStorageCoders = (chainId, miniMetadata, coders) => {
|
1598
|
-
if (!miniMetadata.data) return null;
|
1599
|
-
const metadata = scale.unifyMetadata(scale.decAnyMetadata(miniMetadata.data));
|
1600
|
-
try {
|
1601
|
-
const scaleBuilder = scale.getDynamicBuilder(scale.getLookupFn(metadata));
|
1602
|
-
const builtCoders = Object.fromEntries(Object.entries(coders).flatMap(([key, moduleMethodOrFn]) => {
|
1603
|
-
const [module, method] = typeof moduleMethodOrFn === "function" ? moduleMethodOrFn({
|
1604
|
-
chainId
|
1605
|
-
}) : moduleMethodOrFn;
|
1606
|
-
try {
|
1607
|
-
return [[key, scaleBuilder.buildStorage(module, method)]];
|
1608
|
-
} catch (cause) {
|
1609
|
-
log.trace(`Failed to build SCALE coder for chain ${chainId} (${module}::${method})`, cause);
|
1610
|
-
return [];
|
1611
|
-
}
|
1612
|
-
}));
|
1613
|
-
return builtCoders;
|
1614
|
-
} catch (cause) {
|
1615
|
-
log.error(`Failed to build SCALE coders for chain ${chainId} (${JSON.stringify(coders)})`, cause);
|
1616
|
-
}
|
1617
|
-
return null;
|
1618
|
-
};
|
1619
|
-
|
1620
2039
|
const buildQueries$2 = (networkId, balanceDefs, miniMetadata) => {
|
1621
2040
|
const networkStorageCoders = buildNetworkStorageCoders(networkId, miniMetadata, {
|
1622
2041
|
storage: ["Assets", "Account"]
|
@@ -1852,11 +2271,6 @@ function includeInTotalExtraAmount(extra) {
|
|
1852
2271
|
return extra.filter(extra => extra.includeInTotal).map(extra => extra.amount.planck).reduce((a, b) => a + b, 0n);
|
1853
2272
|
}
|
1854
2273
|
|
1855
|
-
/**
|
1856
|
-
* Have the importing library define its Token and BalanceJson enums (as a sum type of all plugins) and pass them into some
|
1857
|
-
* internal global typescript context, which is then picked up on by this module.
|
1858
|
-
*/
|
1859
|
-
|
1860
2274
|
/** A utility type used to extract the underlying `BalanceType` of a specific source from a generalised `BalanceJson` */
|
1861
2275
|
|
1862
2276
|
/** TODO: Remove this in favour of a frontend-friendly `ChaindataProvider` */
|
@@ -2593,8 +3007,6 @@ const getValueId = amount => {
|
|
2593
3007
|
|
2594
3008
|
/** A labelled extra amount of a balance */
|
2595
3009
|
|
2596
|
-
/** Used by plugins to help define their custom `BalanceType` */
|
2597
|
-
|
2598
3010
|
/** For fast db access, you can calculate the primary key for a miniMetadata using this method */
|
2599
3011
|
const deriveMiniMetadataId = ({
|
2600
3012
|
source,
|
@@ -6151,7 +6563,7 @@ const SubTokensMiniMetadataExtraSchema = z__default.default.strictObject({
|
|
6151
6563
|
palletId: z__default.default.string()
|
6152
6564
|
});
|
6153
6565
|
|
6154
|
-
const BALANCE_MODULES = [SubNativeBalanceModule, SubAssetsBalanceModule, SubHydrationBalanceModule, SubForeignAssetsBalanceModule, SubPsp22BalanceModule, SubTokensBalanceModule, EvmErc20BalanceModule, EvmUniswapV2BalanceModule, EvmNativeBalanceModule];
|
6566
|
+
const BALANCE_MODULES = [SubNativeBalanceModule, SubAssetsBalanceModule, SubHydrationBalanceModule, SubForeignAssetsBalanceModule, SubPsp22BalanceModule, SubTokensBalanceModule, EvmErc20BalanceModule, EvmUniswapV2BalanceModule, EvmNativeBalanceModule, SolNativeBalanceModule, SolSplBalanceModule];
|
6155
6567
|
|
6156
6568
|
// share requests as all modules will call this at once
|
6157
6569
|
const CACHE$1 = new Map();
|
@@ -6329,10 +6741,25 @@ class BalancesProvider {
|
|
6329
6741
|
{
|
6330
6742
|
return this.getEthereumNetworkModuleBalances$(networkId, tokensWithAddresses, mod);
|
6331
6743
|
}
|
6744
|
+
case "solana":
|
6745
|
+
{
|
6746
|
+
return this.getSolanaNetworkModuleBalances$(networkId, tokensWithAddresses, mod);
|
6747
|
+
}
|
6332
6748
|
case "polkadot":
|
6333
6749
|
{
|
6334
6750
|
return this.getPolkadotNetworkModuleBalances$(networkId, tokensWithAddresses, mod);
|
6335
6751
|
}
|
6752
|
+
default:
|
6753
|
+
{
|
6754
|
+
log.warn("[balances] Unsupported network platform for module", {
|
6755
|
+
networkId,
|
6756
|
+
mod
|
6757
|
+
});
|
6758
|
+
return rxjs.of({
|
6759
|
+
status: "live",
|
6760
|
+
balances: []
|
6761
|
+
});
|
6762
|
+
}
|
6336
6763
|
}
|
6337
6764
|
}));
|
6338
6765
|
}), rxjs.map(results => {
|
@@ -6362,7 +6789,7 @@ class BalancesProvider {
|
|
6362
6789
|
address
|
6363
6790
|
})));
|
6364
6791
|
if (!this.#chainConnectors.substrate) {
|
6365
|
-
log.
|
6792
|
+
log.warn("[balances] no substrate connector or miniMetadata for module", mod.type);
|
6366
6793
|
return rxjs.defer(() => rxjs.of({
|
6367
6794
|
status: "initialising",
|
6368
6795
|
balances: this.getStoredBalances(moduleAddressesByTokenId)
|
@@ -6413,7 +6840,7 @@ class BalancesProvider {
|
|
6413
6840
|
address
|
6414
6841
|
})));
|
6415
6842
|
if (!this.#chainConnectors.evm) {
|
6416
|
-
log.
|
6843
|
+
log.warn("[balances] no ethereum connector for module", mod.type);
|
6417
6844
|
return rxjs.defer(() => rxjs.of({
|
6418
6845
|
status: "initialising",
|
6419
6846
|
balances: this.getStoredBalances(moduleAddressesByTokenId)
|
@@ -6445,6 +6872,56 @@ class BalancesProvider {
|
|
6445
6872
|
})));
|
6446
6873
|
});
|
6447
6874
|
}
|
6875
|
+
getSolanaNetworkModuleBalances$(networkId, tokensWithAddresses, mod) {
|
6876
|
+
return util.getSharedObservable(`BalancesProvider.getSolanaNetworkModuleBalances$`, {
|
6877
|
+
networkId,
|
6878
|
+
mod,
|
6879
|
+
tokensWithAddresses
|
6880
|
+
}, () => {
|
6881
|
+
if (!tokensWithAddresses.length) return rxjs.of({
|
6882
|
+
status: "live",
|
6883
|
+
balances: []
|
6884
|
+
});
|
6885
|
+
const moduleAddressesByTokenId = lodashEs.fromPairs(tokensWithAddresses.map(([token, addresses]) => [token.id, addresses]));
|
6886
|
+
|
6887
|
+
// all balance ids expected in result set
|
6888
|
+
const balanceIds = lodashEs.toPairs(moduleAddressesByTokenId).flatMap(([tokenId, addresses]) => addresses.map(address => getBalanceId({
|
6889
|
+
tokenId,
|
6890
|
+
address
|
6891
|
+
})));
|
6892
|
+
if (!this.#chainConnectors.solana) {
|
6893
|
+
log.warn("[balances] no solana connector for module", mod.type);
|
6894
|
+
return rxjs.defer(() => rxjs.of({
|
6895
|
+
status: "initialising",
|
6896
|
+
balances: this.getStoredBalances(moduleAddressesByTokenId)
|
6897
|
+
}));
|
6898
|
+
}
|
6899
|
+
const moduleBalances$ = mod.subscribeBalances({
|
6900
|
+
networkId,
|
6901
|
+
tokensWithAddresses,
|
6902
|
+
connector: this.#chainConnectors.solana
|
6903
|
+
}).pipe(rxjs.catchError(() => rxjs.EMPTY),
|
6904
|
+
// don't emit, let provider mark balances stale
|
6905
|
+
rxjs.map(results => ({
|
6906
|
+
status: "live",
|
6907
|
+
// exclude zero balances
|
6908
|
+
balances: results.success.filter(b => new Balance(b).total.planck > 0n)
|
6909
|
+
})), rxjs.tap(results => {
|
6910
|
+
this.updateStorage$(balanceIds, results);
|
6911
|
+
}),
|
6912
|
+
// shareReplay + keepAlive(0) keep the subscription alive while root observable is being unsubscribed+resubscribed, in case any input change
|
6913
|
+
rxjs.shareReplay({
|
6914
|
+
refCount: true,
|
6915
|
+
bufferSize: 1
|
6916
|
+
}), util.keepAlive(0));
|
6917
|
+
|
6918
|
+
// defer the startWith call to start with up to date balances each time the observable is re-subscribed to
|
6919
|
+
return rxjs.defer(() => moduleBalances$.pipe(rxjs.startWith({
|
6920
|
+
status: "initialising",
|
6921
|
+
balances: this.getStoredBalances(moduleAddressesByTokenId)
|
6922
|
+
})));
|
6923
|
+
});
|
6924
|
+
}
|
6448
6925
|
updateStorage$(balanceIds, balancesResult) {
|
6449
6926
|
if (balancesResult.status !== "live") return;
|
6450
6927
|
const storage = this.#storage.getValue();
|
@@ -6550,22 +7027,46 @@ class BalancesProvider {
|
|
6550
7027
|
return lodashEs.fromPairs(lodashEs.toPairs(addressesByTokenId).map(([tokenId, addresses]) => {
|
6551
7028
|
const networkId = chaindataProvider.parseTokenId(tokenId).networkId;
|
6552
7029
|
const network = networksById[networkId];
|
6553
|
-
return [tokenId, lodashEs.uniq(addresses.map(
|
7030
|
+
return [tokenId, lodashEs.uniq(addresses.map(crypto.normalizeAddress)).filter(address => network && isAddressCompatibleWithNetwork(network, address))];
|
6554
7031
|
}).filter(([, addresses]) => addresses.length > 0));
|
6555
7032
|
}));
|
6556
7033
|
}
|
6557
7034
|
}
|
6558
|
-
const
|
7035
|
+
const isAccountPlatformCompatibleWithNetwork = (network, platform) => {
|
6559
7036
|
switch (network.platform) {
|
6560
7037
|
case "ethereum":
|
6561
|
-
return
|
7038
|
+
return platform === "ethereum";
|
7039
|
+
case "solana":
|
7040
|
+
return platform === "solana";
|
6562
7041
|
case "polkadot":
|
6563
|
-
|
7042
|
+
{
|
7043
|
+
switch (network.account) {
|
7044
|
+
case "secp256k1":
|
7045
|
+
return platform === "ethereum";
|
7046
|
+
case "*25519":
|
7047
|
+
return platform === "polkadot";
|
7048
|
+
default:
|
7049
|
+
throw new Error(`Unsupported polkadot network account type ${network.account}`);
|
7050
|
+
}
|
7051
|
+
}
|
6564
7052
|
default:
|
6565
7053
|
log.warn("Unsupported network platform", network);
|
6566
7054
|
throw new Error("Unsupported network platform");
|
6567
7055
|
}
|
6568
7056
|
};
|
7057
|
+
|
7058
|
+
/**
|
7059
|
+
* If this is the address of an account, use isAccountCompatibleWithChain instead.
|
7060
|
+
* Otherwise it could lead to a loss of funds
|
7061
|
+
* @param chain
|
7062
|
+
* @param address
|
7063
|
+
* @returns
|
7064
|
+
*/
|
7065
|
+
const isAddressCompatibleWithNetwork = (network, address) => {
|
7066
|
+
// TODO try with return true to check if wallet filters correctly upfront
|
7067
|
+
const accountPlatform = crypto.getAccountPlatformFromAddress(address);
|
7068
|
+
return isAccountPlatformCompatibleWithNetwork(network, accountPlatform);
|
7069
|
+
};
|
6569
7070
|
const sortByBalanceId = (a, b) => getBalanceId(a).localeCompare(getBalanceId(b));
|
6570
7071
|
const sortByMiniMetadataId = (a, b) => a.id.localeCompare(b.id);
|
6571
7072
|
|
@@ -6592,6 +7093,10 @@ exports.PlanckSumBalancesFormatter = PlanckSumBalancesFormatter;
|
|
6592
7093
|
exports.SCALE_FACTOR = SCALE_FACTOR;
|
6593
7094
|
exports.SUBTENSOR_MIN_STAKE_AMOUNT_PLANK = SUBTENSOR_MIN_STAKE_AMOUNT_PLANK;
|
6594
7095
|
exports.SUBTENSOR_ROOT_NETUID = SUBTENSOR_ROOT_NETUID;
|
7096
|
+
exports.SolNativeBalanceModule = SolNativeBalanceModule;
|
7097
|
+
exports.SolNativeTokenConfigSchema = SolNativeTokenConfigSchema;
|
7098
|
+
exports.SolSplBalanceModule = SolSplBalanceModule;
|
7099
|
+
exports.SolSplTokenConfigSchema = SolSplTokenConfigSchema;
|
6595
7100
|
exports.SubAssetsBalanceModule = SubAssetsBalanceModule;
|
6596
7101
|
exports.SubAssetsTokenConfigSchema = SubAssetsTokenConfigSchema;
|
6597
7102
|
exports.SubForeignAssetsBalanceModule = SubForeignAssetsBalanceModule;
|