@talismn/balances 0.0.0-pr2075-20250703111149 → 0.0.0-pr2075-20250707042608

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.
Files changed (106) hide show
  1. package/dist/declarations/src/NewBalanceModules.d.ts +99 -0
  2. package/dist/declarations/src/index.d.ts +2 -0
  3. package/dist/declarations/src/modules/EvmErc20Module.d.ts +1 -1
  4. package/dist/declarations/src/modules/IBalanceModule.d.ts +100 -0
  5. package/dist/declarations/src/modules/abis/index.d.ts +2 -0
  6. package/dist/declarations/src/modules/evm-erc20/config.d.ts +16 -0
  7. package/dist/declarations/src/modules/evm-erc20/fetchBalances.d.ts +3 -0
  8. package/dist/declarations/src/modules/evm-erc20/fetchTokens.d.ts +3 -0
  9. package/dist/declarations/src/modules/evm-erc20/getMiniMetadata.d.ts +3 -0
  10. package/dist/declarations/src/modules/evm-erc20/getTransferCallData.d.ts +3 -0
  11. package/dist/declarations/src/modules/evm-erc20/index.d.ts +1 -0
  12. package/dist/declarations/src/modules/evm-erc20/module.d.ts +3 -0
  13. package/dist/declarations/src/modules/evm-erc20/subscribeBalances.d.ts +3 -0
  14. package/dist/declarations/src/modules/evm-erc20/utils.d.ts +6 -0
  15. package/dist/declarations/src/modules/evm-native/config.d.ts +15 -0
  16. package/dist/declarations/src/modules/evm-native/fetchBalances.d.ts +3 -0
  17. package/dist/declarations/src/modules/evm-native/fetchTokens.d.ts +3 -0
  18. package/dist/declarations/src/modules/evm-native/getMiniMetadata.d.ts +3 -0
  19. package/dist/declarations/src/modules/evm-native/getTransferCallData.d.ts +3 -0
  20. package/dist/declarations/src/modules/evm-native/index.d.ts +1 -0
  21. package/dist/declarations/src/modules/evm-native/module.d.ts +3 -0
  22. package/dist/declarations/src/modules/evm-native/subscribeBalances.d.ts +3 -0
  23. package/dist/declarations/src/modules/evm-uniswapv2/config.d.ts +16 -0
  24. package/dist/declarations/src/modules/evm-uniswapv2/fetchBalances.d.ts +3 -0
  25. package/dist/declarations/src/modules/evm-uniswapv2/fetchTokens.d.ts +3 -0
  26. package/dist/declarations/src/modules/evm-uniswapv2/getMiniMetadata.d.ts +3 -0
  27. package/dist/declarations/src/modules/evm-uniswapv2/getTransferCallData.d.ts +3 -0
  28. package/dist/declarations/src/modules/evm-uniswapv2/index.d.ts +1 -0
  29. package/dist/declarations/src/modules/evm-uniswapv2/module.d.ts +3 -0
  30. package/dist/declarations/src/modules/evm-uniswapv2/subscribeBalances.d.ts +3 -0
  31. package/dist/declarations/src/modules/evm-uniswapv2/utils.d.ts +12 -0
  32. package/dist/declarations/src/modules/index.d.ts +2 -1
  33. package/dist/declarations/src/modules/shared/errors.d.ts +11 -0
  34. package/dist/declarations/src/modules/shared/fetchRuntimeCallResult.d.ts +2 -0
  35. package/dist/declarations/src/modules/shared/getContantValue.d.ts +1 -0
  36. package/dist/declarations/src/modules/shared/hasConstantValue.d.ts +427 -0
  37. package/dist/declarations/src/modules/shared/index.d.ts +7 -0
  38. package/dist/declarations/src/modules/shared/tryGetConstantValue.d.ts +1 -0
  39. package/dist/declarations/src/modules/shared/types.d.ts +10 -0
  40. package/dist/declarations/src/modules/shared/utils.d.ts +4 -0
  41. package/dist/declarations/src/modules/substrate-assets/config.d.ts +16 -0
  42. package/dist/declarations/src/modules/substrate-assets/fetchBalances.d.ts +3 -0
  43. package/dist/declarations/src/modules/substrate-assets/fetchTokens.d.ts +3 -0
  44. package/dist/declarations/src/modules/substrate-assets/getMiniMetadata.d.ts +3 -0
  45. package/dist/declarations/src/modules/substrate-assets/getTransferCallData.d.ts +3 -0
  46. package/dist/declarations/src/modules/substrate-assets/index.d.ts +1 -0
  47. package/dist/declarations/src/modules/substrate-assets/module.d.ts +3 -0
  48. package/dist/declarations/src/modules/substrate-assets/subscribeBalances.d.ts +3 -0
  49. package/dist/declarations/src/modules/substrate-foreignassets/config.d.ts +16 -0
  50. package/dist/declarations/src/modules/substrate-foreignassets/fetchBalances.d.ts +3 -0
  51. package/dist/declarations/src/modules/substrate-foreignassets/fetchTokens.d.ts +3 -0
  52. package/dist/declarations/src/modules/substrate-foreignassets/getMiniMetadata.d.ts +3 -0
  53. package/dist/declarations/src/modules/substrate-foreignassets/getTransferCallData.d.ts +3 -0
  54. package/dist/declarations/src/modules/substrate-foreignassets/index.d.ts +1 -0
  55. package/dist/declarations/src/modules/substrate-foreignassets/module.d.ts +3 -0
  56. package/dist/declarations/src/modules/substrate-foreignassets/subscribeBalances.d.ts +3 -0
  57. package/dist/declarations/src/modules/substrate-hydration/config.d.ts +2 -0
  58. package/dist/declarations/src/modules/substrate-hydration/fetchBalances.d.ts +3 -0
  59. package/dist/declarations/src/modules/substrate-hydration/fetchTokens.d.ts +4 -0
  60. package/dist/declarations/src/modules/substrate-hydration/getMiniMetadata.d.ts +3 -0
  61. package/dist/declarations/src/modules/substrate-hydration/getTransferCallData.d.ts +3 -0
  62. package/dist/declarations/src/modules/substrate-hydration/index.d.ts +2 -0
  63. package/dist/declarations/src/modules/substrate-hydration/module.d.ts +4 -0
  64. package/dist/declarations/src/modules/substrate-hydration/subscribeBalances.d.ts +3 -0
  65. package/dist/declarations/src/modules/substrate-hydration/types.d.ts +14 -0
  66. package/dist/declarations/src/modules/substrate-native/bittensor/getSubtensorStakingBalances.d.ts +9 -0
  67. package/dist/declarations/src/modules/substrate-native/bittensor/subtensor.d.ts +20 -0
  68. package/dist/declarations/src/modules/substrate-native/config.d.ts +25 -0
  69. package/dist/declarations/src/modules/substrate-native/fetchBalances.d.ts +3 -0
  70. package/dist/declarations/src/modules/substrate-native/fetchTokens.d.ts +8 -0
  71. package/dist/declarations/src/modules/substrate-native/getMiniMetadata.d.ts +3 -0
  72. package/dist/declarations/src/modules/substrate-native/getTransferCallData.d.ts +3 -0
  73. package/dist/declarations/src/modules/substrate-native/index.d.ts +1 -0
  74. package/dist/declarations/src/modules/substrate-native/module.d.ts +3 -0
  75. package/dist/declarations/src/modules/substrate-native/queries/buildBaseQueries.d.ts +20 -0
  76. package/dist/declarations/src/modules/substrate-native/queries/buildNomPoolQueries.d.ts +8 -0
  77. package/dist/declarations/src/modules/substrate-native/subscribeBalances.d.ts +3 -0
  78. package/dist/declarations/src/modules/substrate-native/util/lockTypes.d.ts +15 -0
  79. package/dist/declarations/src/modules/substrate-native/util/nompoolAccountId.d.ts +5 -0
  80. package/dist/declarations/src/modules/substrate-psp22/config.d.ts +16 -0
  81. package/dist/declarations/src/modules/substrate-psp22/fetchBalances.d.ts +3 -0
  82. package/dist/declarations/src/modules/substrate-psp22/fetchTokens.d.ts +3 -0
  83. package/dist/declarations/src/modules/substrate-psp22/getMiniMetadata.d.ts +3 -0
  84. package/dist/declarations/src/modules/substrate-psp22/getTransferCallData.d.ts +3 -0
  85. package/dist/declarations/src/modules/substrate-psp22/index.d.ts +1 -0
  86. package/dist/declarations/src/modules/substrate-psp22/module.d.ts +3 -0
  87. package/dist/declarations/src/modules/substrate-psp22/subscribeBalances.d.ts +3 -0
  88. package/dist/declarations/src/modules/substrate-tokens/config.d.ts +23 -0
  89. package/dist/declarations/src/modules/substrate-tokens/fetchBalances.d.ts +3 -0
  90. package/dist/declarations/src/modules/substrate-tokens/fetchTokens.d.ts +3 -0
  91. package/dist/declarations/src/modules/substrate-tokens/getMiniMetadata.d.ts +3 -0
  92. package/dist/declarations/src/modules/substrate-tokens/getTransferCallData.d.ts +3 -0
  93. package/dist/declarations/src/modules/substrate-tokens/index.d.ts +1 -0
  94. package/dist/declarations/src/modules/substrate-tokens/module.d.ts +3 -0
  95. package/dist/declarations/src/modules/substrate-tokens/subscribeBalances.d.ts +3 -0
  96. package/dist/declarations/src/modules/util/RpcStateQueriesHelper.d.ts +12 -0
  97. package/dist/declarations/src/modules/util/buildStorageCoders.d.ts +2 -2
  98. package/dist/declarations/src/types/balances.d.ts +2 -1
  99. package/dist/declarations/src/types/minimetadatas.d.ts +1 -1
  100. package/dist/declarations/src/version.d.ts +1 -0
  101. package/dist/talismn-balances.cjs.dev.js +3901 -331
  102. package/dist/talismn-balances.cjs.prod.js +3901 -331
  103. package/dist/talismn-balances.esm.js +3887 -323
  104. package/package.json +8 -8
  105. package/dist/declarations/src/libVersion.d.ts +0 -1
  106. package/dist/declarations/src/modules/abis/erc20.d.ts +0 -227
@@ -1,27 +1,29 @@
1
1
  import { Dexie } from 'dexie';
2
2
  import anylogger from 'anylogger';
3
- import { evmErc20TokenId, TokenBaseSchema, EvmErc20TokenSchema, networkIdFromTokenId, EvmUniswapV2TokenSchema, evmUniswapV2TokenId, getGithubTokenLogoUrl, DotNetworkBalancesConfigSchema, SubAssetsTokenSchema, parseSubAssetTokenId, subAssetTokenId, SubForeignAssetsTokenSchema, parseSubForeignAssetTokenId, subForeignAssetTokenId, parseTokenId, subNativeTokenId, SubPsp22TokenSchema, subPsp22TokenId, SubTokensTokenSchema, parseSubTokensTokenId, subTokensTokenId } from '@talismn/chaindata-provider';
3
+ import { evmErc20TokenId, MINIMETADATA_VERSION, TokenBaseSchema, EvmErc20TokenSchema, networkIdFromTokenId, EvmUniswapV2TokenSchema, evmUniswapV2TokenId, getGithubTokenLogoUrl, DotNetworkBalancesConfigSchema, SubAssetsTokenSchema, parseSubAssetTokenId, subAssetTokenId, SubForeignAssetsTokenSchema, parseSubForeignAssetTokenId, subForeignAssetTokenId, parseTokenId, subNativeTokenId, SubPsp22TokenSchema, subPsp22TokenId, SubTokensTokenSchema, parseSubTokensTokenId, subTokensTokenId, parseEvmErc20TokenId, isTokenOfType, EvmNativeTokenSchema, evmNativeTokenId, SubHydrationTokenSchema, subHydrationTokenId, SubNativeTokenSchema } from '@talismn/chaindata-provider';
4
+ export { MINIMETADATA_VERSION } from '@talismn/chaindata-provider';
4
5
  import { newTokenRates } from '@talismn/token-rates';
5
6
  import { isBigInt, BigMath, planckToTokens, isArrayOf, isTruthy, isEthereumAddress, hasOwnProperty, isAbortError, isNotNil, decodeAnyAddress, blake2Concat, Deferred } from '@talismn/util';
6
7
  import BigNumber from 'bignumber.js';
7
8
  import { u8aToHex, assert, stringCamelCase, u8aConcatStrict, arrayChunk, u8aToString, hexToNumber, hexToU8a } from '@polkadot/util';
8
9
  import { xxhashAsU8a } from '@polkadot/util-crypto';
9
10
  import pako from 'pako';
11
+ import { parseAbi, erc20Abi, isHex, hexToBigInt, getContract, ContractFunctionExecutionError, hexToString, erc20Abi_bytes32, encodeFunctionData, withRetry } from 'viem';
12
+ export { erc20Abi } from 'viem';
10
13
  import z from 'zod/v4';
11
- import { parseAbi, isHex, hexToBigInt } from 'viem';
12
- import { fromPairs, toPairs, keys, groupBy as groupBy$1 } from 'lodash';
14
+ import { fromPairs, toPairs, keys, groupBy as groupBy$1, assign, isEqual as isEqual$1, keyBy, uniq, values } from 'lodash';
13
15
  import isEqual from 'lodash/isEqual';
14
16
  import { defineMethod } from '@substrate/txwrapper-core';
15
- import { unifyMetadata, decAnyMetadata, getDynamicBuilder, getLookupFn, compactMetadata, encodeMetadata, decodeScale, papiParse, getMetadataVersion, encodeStateKey } from '@talismn/scale';
17
+ import { unifyMetadata, decAnyMetadata, getDynamicBuilder, getLookupFn, compactMetadata, encodeMetadata, decodeScale, papiParse, getMetadataVersion, encodeStateKey, parseMetadataRpc, getStorageKeyPrefix, papiStringify, toHex as toHex$1 } from '@talismn/scale';
16
18
  import camelCase from 'lodash/camelCase';
17
19
  import PQueue from 'p-queue';
18
20
  import { fetchBestMetadata, getScaleApi } from '@talismn/sapi';
19
21
  import { Metadata, TypeRegistry } from '@polkadot/types';
20
22
  import groupBy from 'lodash/groupBy';
21
23
  import { mergeUint8, toHex } from '@polkadot-api/utils';
22
- import { Binary, AccountId } from 'polkadot-api';
24
+ import { Binary, AccountId, Enum } from 'polkadot-api';
23
25
  import { ChainConnectionError } from '@talismn/chain-connector';
24
- import { Observable, scan, share, map, switchAll, combineLatest, from, mergeMap, toArray, interval, startWith, exhaustMap, BehaviorSubject, debounceTime, takeUntil, distinctUntilChanged, switchMap, withLatestFrom, concatMap } from 'rxjs';
26
+ import { Observable, scan, share, map, switchAll, combineLatest, from, mergeMap, toArray, interval, startWith, exhaustMap, BehaviorSubject, debounceTime, takeUntil, distinctUntilChanged, switchMap, withLatestFrom, concatMap, of, timer, firstValueFrom } from 'rxjs';
25
27
  import { u32, Struct, u128 } from 'scale-ts';
26
28
  import upperFirst from 'lodash/upperFirst';
27
29
  import { Abi } from '@polkadot/api-contract';
@@ -59,11 +61,10 @@ const DefaultBalanceModule = type => ({
59
61
  // internal
60
62
  //
61
63
 
62
- var pkg = {
63
- name: "@talismn/balances",
64
- version: "0.0.0-pr2075-20250703111149"};
64
+ var packageJson = {
65
+ name: "@talismn/balances"};
65
66
 
66
- var log = anylogger(pkg.name);
67
+ var log = anylogger(packageJson.name);
67
68
 
68
69
  function excludeFromTransferableAmount(locks) {
69
70
  if (typeof locks === "string") return BigInt(locks);
@@ -847,9 +848,8 @@ const getValueId = amount => {
847
848
  const deriveMiniMetadataId = ({
848
849
  source,
849
850
  chainId,
850
- specVersion,
851
- libVersion
852
- }) => u8aToHex(xxhashAsU8a(new TextEncoder().encode(`${source}${chainId}${specVersion}${libVersion}`), 64), undefined, false);
851
+ specVersion
852
+ }) => u8aToHex(xxhashAsU8a(new TextEncoder().encode(`${source}${chainId}${specVersion}${MINIMETADATA_VERSION}`), 64), undefined, false);
853
853
 
854
854
  // for DB version 3, Wallet version 1.21.0
855
855
  const upgradeRemoveSymbolFromNativeTokenId = async tx => {
@@ -948,234 +948,6 @@ const TokenConfigBaseSchema = TokenBaseSchema.partial().omit({
948
948
  id: true
949
949
  });
950
950
 
951
- const erc20Abi = [{
952
- constant: true,
953
- inputs: [],
954
- name: "name",
955
- outputs: [{
956
- name: "",
957
- type: "string"
958
- }],
959
- payable: false,
960
- stateMutability: "view",
961
- type: "function"
962
- }, {
963
- constant: false,
964
- inputs: [{
965
- name: "_spender",
966
- type: "address"
967
- }, {
968
- name: "_value",
969
- type: "uint256"
970
- }],
971
- name: "approve",
972
- outputs: [{
973
- name: "",
974
- type: "bool"
975
- }],
976
- payable: false,
977
- stateMutability: "nonpayable",
978
- type: "function"
979
- }, {
980
- constant: true,
981
- inputs: [],
982
- name: "totalSupply",
983
- outputs: [{
984
- name: "",
985
- type: "uint256"
986
- }],
987
- payable: false,
988
- stateMutability: "view",
989
- type: "function"
990
- }, {
991
- constant: false,
992
- inputs: [{
993
- name: "_from",
994
- type: "address"
995
- }, {
996
- name: "_to",
997
- type: "address"
998
- }, {
999
- name: "_value",
1000
- type: "uint256"
1001
- }],
1002
- name: "transferFrom",
1003
- outputs: [{
1004
- name: "",
1005
- type: "bool"
1006
- }],
1007
- payable: false,
1008
- stateMutability: "nonpayable",
1009
- type: "function"
1010
- }, {
1011
- constant: true,
1012
- inputs: [],
1013
- name: "decimals",
1014
- outputs: [{
1015
- name: "",
1016
- type: "uint8"
1017
- }],
1018
- payable: false,
1019
- stateMutability: "view",
1020
- type: "function"
1021
- }, {
1022
- constant: false,
1023
- inputs: [{
1024
- name: "_to",
1025
- type: "address"
1026
- }, {
1027
- name: "_value",
1028
- type: "uint256"
1029
- }, {
1030
- name: "_data",
1031
- type: "bytes"
1032
- }],
1033
- name: "transferAndCall",
1034
- outputs: [{
1035
- name: "success",
1036
- type: "bool"
1037
- }],
1038
- payable: false,
1039
- stateMutability: "nonpayable",
1040
- type: "function"
1041
- }, {
1042
- constant: false,
1043
- inputs: [{
1044
- name: "_spender",
1045
- type: "address"
1046
- }, {
1047
- name: "_subtractedValue",
1048
- type: "uint256"
1049
- }],
1050
- name: "decreaseApproval",
1051
- outputs: [{
1052
- name: "success",
1053
- type: "bool"
1054
- }],
1055
- payable: false,
1056
- stateMutability: "nonpayable",
1057
- type: "function"
1058
- }, {
1059
- constant: true,
1060
- inputs: [{
1061
- name: "_owner",
1062
- type: "address"
1063
- }],
1064
- name: "balanceOf",
1065
- outputs: [{
1066
- name: "balance",
1067
- type: "uint256"
1068
- }],
1069
- payable: false,
1070
- stateMutability: "view",
1071
- type: "function"
1072
- }, {
1073
- constant: true,
1074
- inputs: [],
1075
- name: "symbol",
1076
- outputs: [{
1077
- name: "",
1078
- type: "string"
1079
- }],
1080
- payable: false,
1081
- stateMutability: "view",
1082
- type: "function"
1083
- }, {
1084
- constant: false,
1085
- inputs: [{
1086
- name: "_to",
1087
- type: "address"
1088
- }, {
1089
- name: "_value",
1090
- type: "uint256"
1091
- }],
1092
- name: "transfer",
1093
- outputs: [{
1094
- name: "success",
1095
- type: "bool"
1096
- }],
1097
- payable: false,
1098
- stateMutability: "nonpayable",
1099
- type: "function"
1100
- }, {
1101
- constant: false,
1102
- inputs: [{
1103
- name: "_spender",
1104
- type: "address"
1105
- }, {
1106
- name: "_addedValue",
1107
- type: "uint256"
1108
- }],
1109
- name: "increaseApproval",
1110
- outputs: [{
1111
- name: "success",
1112
- type: "bool"
1113
- }],
1114
- payable: false,
1115
- stateMutability: "nonpayable",
1116
- type: "function"
1117
- }, {
1118
- constant: true,
1119
- inputs: [{
1120
- name: "_owner",
1121
- type: "address"
1122
- }, {
1123
- name: "_spender",
1124
- type: "address"
1125
- }],
1126
- name: "allowance",
1127
- outputs: [{
1128
- name: "remaining",
1129
- type: "uint256"
1130
- }],
1131
- payable: false,
1132
- stateMutability: "view",
1133
- type: "function"
1134
- }, {
1135
- inputs: [],
1136
- payable: false,
1137
- stateMutability: "nonpayable",
1138
- type: "constructor"
1139
- }, {
1140
- anonymous: false,
1141
- inputs: [{
1142
- indexed: true,
1143
- name: "from",
1144
- type: "address"
1145
- }, {
1146
- indexed: true,
1147
- name: "to",
1148
- type: "address"
1149
- }, {
1150
- indexed: false,
1151
- name: "value",
1152
- type: "uint256"
1153
- }, {
1154
- indexed: false,
1155
- name: "data",
1156
- type: "bytes"
1157
- }],
1158
- name: "Transfer",
1159
- type: "event"
1160
- }, {
1161
- anonymous: false,
1162
- inputs: [{
1163
- indexed: true,
1164
- name: "owner",
1165
- type: "address"
1166
- }, {
1167
- indexed: true,
1168
- name: "spender",
1169
- type: "address"
1170
- }, {
1171
- indexed: false,
1172
- name: "value",
1173
- type: "uint256"
1174
- }],
1175
- name: "Approval",
1176
- type: "event"
1177
- }];
1178
-
1179
951
  const erc20BalancesAggregatorAbi = parseAbi(["struct AccountToken {address account; address token;}", "function balances(AccountToken[] memory accountTokens) public view returns (uint256[] memory)"]);
1180
952
 
1181
953
  const moduleType$7 = "evm-erc20";
@@ -1331,7 +1103,7 @@ const EvmErc20Module = hydrate => {
1331
1103
  const {
1332
1104
  errors,
1333
1105
  results
1334
- } = await fetchBalances$3(chainConnectors.evm, {
1106
+ } = await fetchBalances$c(chainConnectors.evm, {
1335
1107
  [evmNetworkId]: fetchesPerNetwork[evmNetworkId]
1336
1108
  }, aggregators);
1337
1109
 
@@ -1389,7 +1161,7 @@ const EvmErc20Module = hydrate => {
1389
1161
  if (!chainConnectors.evm) throw new Error(`This module requires an evm chain connector`);
1390
1162
  const [aggregators, tokens] = await Promise.all([getErc20Aggregators(), getModuleTokens()]);
1391
1163
  const fetchesPerNetwork = await prepareFetchParameters(addressesByToken, tokens);
1392
- const balances = await fetchBalances$3(chainConnectors.evm, fetchesPerNetwork, aggregators);
1164
+ const balances = await fetchBalances$c(chainConnectors.evm, fetchesPerNetwork, aggregators);
1393
1165
  return new Balances(balances.results);
1394
1166
  }
1395
1167
  };
@@ -1411,7 +1183,7 @@ class EvmErc20NetworkError extends Error {
1411
1183
  this.evmNetworkId = evmNetworkId;
1412
1184
  }
1413
1185
  }
1414
- const fetchBalances$3 = async (evmChainConnector, tokenAddressesByNetwork, erc20Aggregators = {}) => {
1186
+ const fetchBalances$c = async (evmChainConnector, tokenAddressesByNetwork, erc20Aggregators = {}) => {
1415
1187
  const result = {
1416
1188
  results: [],
1417
1189
  errors: []
@@ -1586,7 +1358,7 @@ const EvmNativeModule = hydrate => {
1586
1358
  if (!tokenId) throw new Error(`No native token for evm network ${evmNetworkId}`);
1587
1359
  try {
1588
1360
  if (!chainConnectors.evm) throw new Error(`This module requires an evm chain connector`);
1589
- const balances = await fetchBalances$2(chainConnectors.evm, {
1361
+ const balances = await fetchBalances$b(chainConnectors.evm, {
1590
1362
  [tokenId]: addresses
1591
1363
  }, tokens);
1592
1364
  const resultBalances = [];
@@ -1628,7 +1400,7 @@ const EvmNativeModule = hydrate => {
1628
1400
  async fetchBalances(addressesByToken) {
1629
1401
  if (!chainConnectors.evm) throw new Error(`This module requires an evm chain connector`);
1630
1402
  const tokens = await getModuleTokens();
1631
- const balanceResults = await fetchBalances$2(chainConnectors.evm, addressesByToken, tokens);
1403
+ const balanceResults = await fetchBalances$b(chainConnectors.evm, addressesByToken, tokens);
1632
1404
  const pureBalances = balanceResults.flat().filter(b => !(b instanceof EvmNativeBalanceError) && BigInt(b.value) > 0n);
1633
1405
  return new Balances(pureBalances);
1634
1406
  }
@@ -1644,7 +1416,7 @@ class EvmNativeBalanceError extends Error {
1644
1416
  }
1645
1417
  }
1646
1418
  }
1647
- const fetchBalances$2 = async (evmChainConnector, addressesByToken, tokens) => {
1419
+ const fetchBalances$b = async (evmChainConnector, addressesByToken, tokens) => {
1648
1420
  if (!evmChainConnector) throw new Error(`This module requires an evm chain connector`);
1649
1421
  return Promise.all(Object.entries(addressesByToken).map(async ([tokenId, addresses]) => {
1650
1422
  const token = tokens[tokenId];
@@ -2396,7 +2168,7 @@ const EvmUniswapV2Module = hydrate => {
2396
2168
  }
2397
2169
  try {
2398
2170
  if (!chainConnectors.evm) throw new Error(`This module requires an evm chain connector`);
2399
- const balances = await fetchBalances$1(chainConnectors.evm, evmNetworks, tokens, addressesByToken);
2171
+ const balances = await fetchBalances$a(chainConnectors.evm, evmNetworks, tokens, addressesByToken);
2400
2172
 
2401
2173
  // Don't call callback with balances which have not changed since the last poll.
2402
2174
  const json = balances.toJSON();
@@ -2425,11 +2197,11 @@ const EvmUniswapV2Module = hydrate => {
2425
2197
  if (!chainConnectors.evm) throw new Error(`This module requires an evm chain connector`);
2426
2198
  const evmNetworks = await chaindataProvider.getNetworksMapById("ethereum");
2427
2199
  const tokens = await chaindataProvider.getTokensMapById();
2428
- return fetchBalances$1(chainConnectors.evm, evmNetworks, tokens, addressesByToken);
2200
+ return fetchBalances$a(chainConnectors.evm, evmNetworks, tokens, addressesByToken);
2429
2201
  }
2430
2202
  };
2431
2203
  };
2432
- const fetchBalances$1 = async (evmChainConnector, evmNetworks, tokens, addressesByToken) => {
2204
+ const fetchBalances$a = async (evmChainConnector, evmNetworks, tokens, addressesByToken) => {
2433
2205
  const addressesByTokenGroupedByEvmNetwork = groupAddressesByTokenByEvmNetwork(addressesByToken, tokens);
2434
2206
  const balances = (await Promise.allSettled(Object.entries(addressesByTokenGroupedByEvmNetwork).map(async ([networkId, addressesByToken]) => {
2435
2207
  if (!evmChainConnector) throw new Error(`This module requires an evm chain connector`);
@@ -2569,8 +2341,6 @@ async function getPoolBalance(publicClient, contractAddress, accountAddress) {
2569
2341
  }
2570
2342
  }
2571
2343
 
2572
- const libVersion = pkg.version;
2573
-
2574
2344
  // cache the promise so it can be shared across multiple calls
2575
2345
  const CACHE_GET_SPEC_VERSION = new Map();
2576
2346
  const fetchSpecVersion = async (chainConnector, networkId) => {
@@ -2671,13 +2441,12 @@ const fetchMiniMetadatas = async (chainConnector, chaindataProvider, chainId, sp
2671
2441
  id: deriveMiniMetadataId({
2672
2442
  source,
2673
2443
  chainId,
2674
- specVersion,
2675
- libVersion
2444
+ specVersion
2676
2445
  }),
2677
2446
  source,
2678
2447
  chainId,
2679
2448
  specVersion,
2680
- libVersion,
2449
+ version: MINIMETADATA_VERSION,
2681
2450
  data: chainMeta?.miniMetadata ?? null,
2682
2451
  extra: chainMeta?.extra ?? null
2683
2452
  };
@@ -2699,14 +2468,13 @@ const getUpdatedMiniMetadatas = async (chainConnector, chaindataProvider, chainI
2699
2468
  return miniMetadatas;
2700
2469
  };
2701
2470
 
2702
- const getMiniMetadata = async (chaindataProvider, chainConnector, chainId, source, signal) => {
2471
+ const getMiniMetadata$9 = async (chaindataProvider, chainConnector, chainId, source, signal) => {
2703
2472
  const specVersion = await getSpecVersion(chainConnector, chainId);
2704
2473
  signal?.throwIfAborted();
2705
2474
  const miniMetadataId = deriveMiniMetadataId({
2706
2475
  source,
2707
2476
  chainId,
2708
- specVersion,
2709
- libVersion
2477
+ specVersion
2710
2478
  });
2711
2479
 
2712
2480
  // lookup local ones
@@ -2724,7 +2492,7 @@ const getMiniMetadata = async (chaindataProvider, chainConnector, chainId, sourc
2724
2492
  source,
2725
2493
  chainId,
2726
2494
  specVersion,
2727
- libVersion,
2495
+ version: MINIMETADATA_VERSION,
2728
2496
  miniMetadataId,
2729
2497
  miniMetadatas
2730
2498
  });
@@ -2780,6 +2548,8 @@ const buildStorageCoders = ({
2780
2548
  return [];
2781
2549
  }
2782
2550
  }));
2551
+ // type StorageCoder<TCoders extends NetworkCoders> = ReturnType<ReturnType<typeof getDynamicBuilder>["buildStorage"]>[keyof TCoders]
2552
+
2783
2553
  const buildNetworkStorageCoders = (chainId, miniMetadata, coders) => {
2784
2554
  if (!miniMetadata.data) return null;
2785
2555
  const metadata = unifyMetadata(decAnyMetadata(miniMetadata.data));
@@ -3038,8 +2808,8 @@ const SubAssetsModule = hydrate => {
3038
2808
  for (const tokenConfig of tokens ?? []) {
3039
2809
  try {
3040
2810
  const assetId = String(tokenConfig.assetId);
3041
- const assetStateKey = tryEncode(assetCoder, BigInt(assetId)) ?? tryEncode(assetCoder, assetId);
3042
- const metadataStateKey = tryEncode(metadataCoder, BigInt(assetId)) ?? tryEncode(metadataCoder, assetId);
2811
+ const assetStateKey = tryEncode$1(assetCoder, BigInt(assetId)) ?? tryEncode$1(assetCoder, assetId);
2812
+ const metadataStateKey = tryEncode$1(metadataCoder, BigInt(assetId)) ?? tryEncode$1(metadataCoder, assetId);
3043
2813
  if (assetStateKey === null || metadataStateKey === null) throw new Error(`Failed to encode stateKey for asset ${assetId} on chain ${chainId}`);
3044
2814
  const [assetsAsset, assetsMetadata] = await Promise.all([chainConnector.send(chainId, "state_getStorage", [assetStateKey]).then(result => assetCoder.value.dec(result) ?? null), chainConnector.send(chainId, "state_getStorage", [metadataStateKey]).then(result => metadataCoder.value.dec(result) ?? null)]);
3045
2815
  const existentialDeposit = assetsAsset?.min_balance?.toString?.() ?? "0";
@@ -3059,6 +2829,7 @@ const SubAssetsModule = hydrate => {
3059
2829
  logo: tokenConfig?.logo,
3060
2830
  existentialDeposit,
3061
2831
  assetId,
2832
+ isSufficient: false,
3062
2833
  isFrozen,
3063
2834
  networkId: chainId
3064
2835
  };
@@ -3111,7 +2882,7 @@ const SubAssetsModule = hydrate => {
3111
2882
  },
3112
2883
  async fetchBalances(addressesByToken) {
3113
2884
  assert(chainConnectors.substrate, "This module requires a substrate chain connector");
3114
- const queries = await buildQueries$3(chainConnector, chaindataProvider, addressesByToken);
2885
+ const queries = await buildQueries$6(chainConnector, chaindataProvider, addressesByToken);
3115
2886
  const result = await new RpcStateQueryHelper(chainConnectors.substrate, queries).fetch();
3116
2887
  const balances = result?.filter(b => b !== null) ?? [];
3117
2888
  return new Balances(balances);
@@ -3181,7 +2952,7 @@ const SubAssetsModule = hydrate => {
3181
2952
  };
3182
2953
  };
3183
2954
  async function buildNetworkQueries$2(networkId, chainConnector, chaindataProvider, addressesByToken, signal) {
3184
- const miniMetadata = await getMiniMetadata(chaindataProvider, chainConnector, networkId, moduleType$4, signal);
2955
+ const miniMetadata = await getMiniMetadata$9(chaindataProvider, chainConnector, networkId, moduleType$4, signal);
3185
2956
  const chain = await chaindataProvider.getNetworkById(networkId, "polkadot");
3186
2957
  const tokensById = await chaindataProvider.getTokensMapById();
3187
2958
  signal?.throwIfAborted();
@@ -3205,7 +2976,7 @@ async function buildNetworkQueries$2(networkId, chainConnector, chaindataProvide
3205
2976
  }
3206
2977
  return addresses.flatMap(address => {
3207
2978
  const scaleCoder = networkStorageCoders?.storage;
3208
- const stateKey = tryEncode(scaleCoder, Number(token.assetId), address) ?? tryEncode(scaleCoder, BigInt(token.assetId), address);
2979
+ const stateKey = tryEncode$1(scaleCoder, Number(token.assetId), address) ?? tryEncode$1(scaleCoder, BigInt(token.assetId), address);
3209
2980
  if (!stateKey) {
3210
2981
  log.warn(`Invalid assetId / address in ${networkId} storage query ${token.assetId} / ${address}`);
3211
2982
  return [];
@@ -3260,7 +3031,7 @@ async function buildNetworkQueries$2(networkId, chainConnector, chaindataProvide
3260
3031
  });
3261
3032
  });
3262
3033
  }
3263
- async function buildQueries$3(chainConnector, chaindataProvider, addressesByToken, signal) {
3034
+ async function buildQueries$6(chainConnector, chaindataProvider, addressesByToken, signal) {
3264
3035
  const byNetwork = keys(addressesByToken).reduce((acc, tokenId) => {
3265
3036
  const networkId = parseSubAssetTokenId(tokenId).networkId;
3266
3037
  if (!acc[networkId]) acc[networkId] = {};
@@ -3275,7 +3046,7 @@ async function buildQueries$3(chainConnector, chaindataProvider, addressesByToke
3275
3046
  // E.g. Polkadot Asset Hub needs it to be a string, Astar needs it to be a bigint
3276
3047
  //
3277
3048
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
3278
- const tryEncode = (scaleCoder, ...args) => {
3049
+ const tryEncode$1 = (scaleCoder, ...args) => {
3279
3050
  try {
3280
3051
  return scaleCoder?.keys?.enc?.(...args);
3281
3052
  } catch {
@@ -3358,6 +3129,7 @@ const SubForeignAssetsModule = hydrate => {
3358
3129
  logo: tokenConfig?.logo,
3359
3130
  existentialDeposit,
3360
3131
  onChainId: tokenConfig.onChainId,
3132
+ isSufficient: assetsAsset?.is_sufficient ?? false,
3361
3133
  isFrozen,
3362
3134
  networkId: chainId
3363
3135
  };
@@ -3406,7 +3178,7 @@ const SubForeignAssetsModule = hydrate => {
3406
3178
  },
3407
3179
  async fetchBalances(addressesByToken) {
3408
3180
  assert(chainConnectors.substrate, "This module requires a substrate chain connector");
3409
- const queries = await buildQueries$2(chainConnector, chaindataProvider, addressesByToken);
3181
+ const queries = await buildQueries$5(chainConnector, chaindataProvider, addressesByToken);
3410
3182
  const result = await new RpcStateQueryHelper(chainConnectors.substrate, queries).fetch();
3411
3183
  const balances = result?.filter(b => b !== null) ?? [];
3412
3184
  return new Balances(balances);
@@ -3462,7 +3234,7 @@ const SubForeignAssetsModule = hydrate => {
3462
3234
  };
3463
3235
  };
3464
3236
  async function buildNetworkQueries$1(networkId, chainConnector, chaindataProvider, addressesByToken, signal) {
3465
- const miniMetadata = await getMiniMetadata(chaindataProvider, chainConnector, networkId, moduleType$3, signal);
3237
+ const miniMetadata = await getMiniMetadata$9(chaindataProvider, chainConnector, networkId, moduleType$3, signal);
3466
3238
  const chain = await chaindataProvider.getNetworkById(networkId, "polkadot");
3467
3239
  const tokensById = await chaindataProvider.getTokensMapById();
3468
3240
  signal?.throwIfAborted();
@@ -3544,7 +3316,7 @@ async function buildNetworkQueries$1(networkId, chainConnector, chaindataProvide
3544
3316
  });
3545
3317
  });
3546
3318
  }
3547
- async function buildQueries$2(chainConnector, chaindataProvider, addressesByToken, signal) {
3319
+ async function buildQueries$5(chainConnector, chaindataProvider, addressesByToken, signal) {
3548
3320
  const byNetwork = keys(addressesByToken).reduce((acc, tokenId) => {
3549
3321
  const networkId = parseSubForeignAssetTokenId(tokenId).networkId;
3550
3322
  if (!acc[networkId]) acc[networkId] = {};
@@ -3598,7 +3370,7 @@ const asObservable = handler => (...args) => new Observable(subscriber => {
3598
3370
  * Each nominationPool in the nominationPools pallet has access to some accountIds which have no
3599
3371
  * associated private key. Instead, they are derived from this function.
3600
3372
  */
3601
- const nompoolAccountId = (palletId, poolId, index) => {
3373
+ const nompoolAccountId$1 = (palletId, poolId, index) => {
3602
3374
  const utf8Encoder = new TextEncoder();
3603
3375
  const encModPrefix = utf8Encoder.encode("modl");
3604
3376
  const encPalletId = utf8Encoder.encode(palletId);
@@ -3611,7 +3383,7 @@ const nompoolAccountId = (palletId, poolId, index) => {
3611
3383
  return AccountId().dec(bytes);
3612
3384
  };
3613
3385
  /** The stash account for the nomination pool */
3614
- const nompoolStashAccountId = (palletId, poolId) => nompoolAccountId(palletId, poolId, 0);
3386
+ const nompoolStashAccountId$1 = (palletId, poolId) => nompoolAccountId$1(palletId, poolId, 0);
3615
3387
 
3616
3388
  // TODO make this method chain-specific
3617
3389
  async function subscribeNompoolStaking(chaindataProvider, chainConnector, addressesByToken, callback, signal) {
@@ -3623,7 +3395,7 @@ async function subscribeNompoolStaking(chaindataProvider, chainConnector, addres
3623
3395
  const networkIds = keys(addressesByToken).map(tokenId => parseTokenId(tokenId).networkId);
3624
3396
  const miniMetadatas = new Map();
3625
3397
  for (const networkId of networkIds) {
3626
- const miniMetadata = await getMiniMetadata(chaindataProvider, chainConnector, networkId, "substrate-native");
3398
+ const miniMetadata = await getMiniMetadata$9(chaindataProvider, chainConnector, networkId, "substrate-native");
3627
3399
  miniMetadatas.set(networkId, miniMetadata);
3628
3400
  }
3629
3401
  signal?.throwIfAborted();
@@ -3749,7 +3521,7 @@ async function subscribeNompoolStaking(chaindataProvider, chainConnector, addres
3749
3521
  const scaleCoder = chainStorageCoders.get(chainId)?.ledger;
3750
3522
  const queries = poolIds.flatMap(poolId => {
3751
3523
  if (!nominationPoolsPalletId) return [];
3752
- const stashAddress = nompoolStashAccountId(nominationPoolsPalletId, poolId);
3524
+ const stashAddress = nompoolStashAccountId$1(nominationPoolsPalletId, poolId);
3753
3525
  const stateKey = encodeStateKey(scaleCoder, `Invalid address in ${chainId} ledger query ${stashAddress}`, stashAddress);
3754
3526
  if (!stateKey) return [];
3755
3527
  const decodeResult = change => {
@@ -3902,12 +3674,12 @@ async function subscribeNompoolStaking(chaindataProvider, chainConnector, addres
3902
3674
  }
3903
3675
  }
3904
3676
 
3905
- const SUBTENSOR_ROOT_NETUID = 0;
3906
- const SUBTENSOR_MIN_STAKE_AMOUNT_PLANK = 1000000n;
3907
- const TAO_DECIMALS = 9n;
3908
- const SCALE_FACTOR = 10n ** TAO_DECIMALS; // Equivalent to 10e9 for precision
3909
- const ONE_ALPHA_TOKEN = SCALE_FACTOR;
3910
- const calculateAlphaPrice = ({
3677
+ const SUBTENSOR_ROOT_NETUID$1 = 0;
3678
+ const SUBTENSOR_MIN_STAKE_AMOUNT_PLANK$1 = 1000000n;
3679
+ const TAO_DECIMALS$1 = 9n;
3680
+ const SCALE_FACTOR$1 = 10n ** TAO_DECIMALS$1; // Equivalent to 10e9 for precision
3681
+ const ONE_ALPHA_TOKEN$1 = SCALE_FACTOR$1;
3682
+ const calculateAlphaPrice$1 = ({
3911
3683
  dynamicInfo
3912
3684
  }) => {
3913
3685
  if (!dynamicInfo) return 0n;
@@ -3917,25 +3689,25 @@ const calculateAlphaPrice = ({
3917
3689
  } = dynamicInfo;
3918
3690
 
3919
3691
  // Scale taoIn before division to preserve precision
3920
- const result = tao_in * SCALE_FACTOR / alpha_in;
3692
+ const result = tao_in * SCALE_FACTOR$1 / alpha_in;
3921
3693
  return result; // Scaled price as bigint
3922
3694
  };
3923
- const calculateTaoAmountFromAlpha = ({
3695
+ const calculateTaoAmountFromAlpha$1 = ({
3924
3696
  alphaPrice,
3925
3697
  alphaStaked
3926
3698
  }) => {
3927
3699
  if (!alphaStaked || !alphaPrice) return 0n;
3928
3700
  const expectedAlpha = alphaStaked * alphaPrice;
3929
- return expectedAlpha / SCALE_FACTOR;
3701
+ return expectedAlpha / SCALE_FACTOR$1;
3930
3702
  };
3931
- const calculateTaoFromDynamicInfo = ({
3703
+ const calculateTaoFromDynamicInfo$1 = ({
3932
3704
  dynamicInfo,
3933
3705
  alphaStaked
3934
3706
  }) => {
3935
- const alphaPrice = calculateAlphaPrice({
3707
+ const alphaPrice = calculateAlphaPrice$1({
3936
3708
  dynamicInfo
3937
3709
  });
3938
- return calculateTaoAmountFromAlpha({
3710
+ return calculateTaoAmountFromAlpha$1({
3939
3711
  alphaPrice,
3940
3712
  alphaStaked
3941
3713
  });
@@ -3951,7 +3723,7 @@ async function subscribeSubtensorStaking(chaindataProvider, chainConnector, addr
3951
3723
  const networkIds = keys(addressesByToken).map(tokenId => parseTokenId(tokenId).networkId);
3952
3724
  const miniMetadatas = new Map();
3953
3725
  for (const networkId of networkIds) {
3954
- const miniMetadata = await getMiniMetadata(chaindataProvider, chainConnector, networkId, "substrate-native", signal);
3726
+ const miniMetadata = await getMiniMetadata$9(chaindataProvider, chainConnector, networkId, "substrate-native", signal);
3955
3727
  miniMetadatas.set(networkId, miniMetadata);
3956
3728
  }
3957
3729
  signal?.throwIfAborted();
@@ -4042,7 +3814,7 @@ async function subscribeSubtensorStaking(chaindataProvider, chainConnector, addr
4042
3814
  const params = [address];
4043
3815
  const result = await scaleApi.getRuntimeCallValue("StakeInfoRuntimeApi", "get_stake_info_for_coldkey", params);
4044
3816
  if (!Array.isArray(result)) return [];
4045
- const uniqueNetuids = Array.from(new Set(result.map(item => Number(item.netuid)).filter(netuid => netuid !== SUBTENSOR_ROOT_NETUID)));
3817
+ const uniqueNetuids = Array.from(new Set(result.map(item => Number(item.netuid)).filter(netuid => netuid !== SUBTENSOR_ROOT_NETUID$1)));
4046
3818
  await fetchDynamicInfoForNetuids(uniqueNetuids);
4047
3819
  const stakes = result?.map(({
4048
3820
  coldkey,
@@ -4059,7 +3831,7 @@ async function subscribeSubtensorStaking(chaindataProvider, chainConnector, addr
4059
3831
  };
4060
3832
  }).filter(({
4061
3833
  stake
4062
- }) => stake >= SUBTENSOR_MIN_STAKE_AMOUNT_PLANK);
3834
+ }) => stake >= SUBTENSOR_MIN_STAKE_AMOUNT_PLANK$1);
4063
3835
  return stakes;
4064
3836
  }];
4065
3837
  const errors = [];
@@ -4105,15 +3877,15 @@ async function subscribeSubtensorStaking(chaindataProvider, chainConnector, addr
4105
3877
  const subnetIdentity = subnet_identity ? binaryToText(subnet_identity) : undefined;
4106
3878
 
4107
3879
  // Add 1n balance if failed to fetch dynamic info, so the position is not ignored by Balance lib and is displayed in the UI.
4108
- const alphaStakedInTao = dynamicInfo ? calculateTaoFromDynamicInfo({
3880
+ const alphaStakedInTao = dynamicInfo ? calculateTaoFromDynamicInfo$1({
4109
3881
  dynamicInfo,
4110
3882
  alphaStaked: stake
4111
3883
  }) : 1n;
4112
- const alphaToTaoRate = calculateTaoFromDynamicInfo({
3884
+ const alphaToTaoRate = calculateTaoFromDynamicInfo$1({
4113
3885
  dynamicInfo: dynamicInfo ?? null,
4114
- alphaStaked: ONE_ALPHA_TOKEN
3886
+ alphaStaked: ONE_ALPHA_TOKEN$1
4115
3887
  }).toString();
4116
- const stakeByNetuid = Number(netuid) === SUBTENSOR_ROOT_NETUID ? stake : alphaStakedInTao;
3888
+ const stakeByNetuid = Number(netuid) === SUBTENSOR_ROOT_NETUID$1 ? stake : alphaStakedInTao;
4117
3889
  return {
4118
3890
  source: "substrate-native",
4119
3891
  status: "live",
@@ -4173,14 +3945,14 @@ async function subscribeSubtensorStaking(chaindataProvider, chainConnector, addr
4173
3945
  }
4174
3946
  }
4175
3947
 
4176
- const getOtherType = input => `other-${input}`;
3948
+ const getOtherType$1 = input => `other-${input}`;
4177
3949
 
4178
3950
  /**
4179
3951
  * For converting the value of `lock?.id?.toUtf8?.()` which is retrieved from
4180
3952
  * the Balances.Locks storage key into a useful classification for our UI
4181
3953
  */
4182
- const getLockedType = input => {
4183
- if (typeof input !== "string") return getOtherType("unknown");
3954
+ const getLockedType$1 = input => {
3955
+ if (typeof input !== "string") return getOtherType$1("unknown");
4184
3956
  if (input.includes("vesting")) return "vesting";
4185
3957
  if (input.includes("calamvst")) return "vesting"; // vesting on manta network
4186
3958
  if (input.includes("ormlvest")) return "vesting"; // vesting ORML tokens
@@ -4202,19 +3974,19 @@ const getLockedType = input => {
4202
3974
  if (input.includes("councilo")) return "democracy"; // Councilor
4203
3975
  if (input.includes("proposal")) return "democracy";
4204
3976
  if (input.includes("boundsta")) return "staking"; // Bound Staking Account
4205
- if (input.includes("invitemb")) return getOtherType(input); // Invite member
4206
- if (input.includes("bounty")) return getOtherType(input);
4207
- if (input.startsWith("wg-")) return getOtherType(input);
3977
+ if (input.includes("invitemb")) return getOtherType$1(input); // Invite member
3978
+ if (input.includes("bounty")) return getOtherType$1(input);
3979
+ if (input.startsWith("wg-")) return getOtherType$1(input);
4208
3980
 
4209
3981
  // ignore technical or undocumented lock types
4210
- if (input.includes("pdexlock")) return getOtherType(input);
4211
- if (input.includes("phala/sp")) return getOtherType(input);
4212
- if (input.includes("aca/earn")) return getOtherType(input);
4213
- if (input.includes("stk_stks")) return getOtherType(input);
3982
+ if (input.includes("pdexlock")) return getOtherType$1(input);
3983
+ if (input.includes("phala/sp")) return getOtherType$1(input);
3984
+ if (input.includes("aca/earn")) return getOtherType$1(input);
3985
+ if (input.includes("stk_stks")) return getOtherType$1(input);
4214
3986
 
4215
3987
  // eslint-disable-next-line no-console
4216
3988
  console.warn(`unknown locked type: ${input}`);
4217
- return getOtherType(input);
3989
+ return getOtherType$1(input);
4218
3990
  };
4219
3991
  const baseLockLabels = ["fees", "misc"];
4220
3992
  const isBaseLock = lock => baseLockLabels.includes(lock.label);
@@ -4311,7 +4083,7 @@ const AccountInfoOverrides = {
4311
4083
  // nftmart is not yet on metadata v14
4312
4084
  "nftmart": RegularAccountInfoFallback
4313
4085
  };
4314
- async function buildQueries$1(chains, tokens, chainStorageCoders, miniMetadatas, addressesByToken) {
4086
+ async function buildQueries$4(chains, tokens, chainStorageCoders, miniMetadatas, addressesByToken) {
4315
4087
  return Object.entries(addressesByToken).reduce((outerResult, [tokenId, addresses]) => {
4316
4088
  const token = tokens[tokenId];
4317
4089
  if (!token) {
@@ -4443,7 +4215,7 @@ async function buildQueries$1(chains, tokens, chainStorageCoders, miniMetadatas,
4443
4215
  locksQueryLocks = decoded?.map?.(lock => ({
4444
4216
  type: "locked",
4445
4217
  source: "substrate-native-locks",
4446
- label: getLockedType(lock?.id?.asText?.()),
4218
+ label: getLockedType$1(lock?.id?.asText?.()),
4447
4219
  meta: {
4448
4220
  id: lock?.id?.asText?.()
4449
4221
  },
@@ -4507,7 +4279,7 @@ async function buildQueries$1(chains, tokens, chainStorageCoders, miniMetadatas,
4507
4279
  freezesQueryLocks = decoded?.map?.(lock => ({
4508
4280
  type: "locked",
4509
4281
  source: "substrate-native-freezes",
4510
- label: getLockedType(lock?.id?.type?.toLowerCase?.()),
4282
+ label: getLockedType$1(lock?.id?.type?.toLowerCase?.()),
4511
4283
  amount: lock?.amount?.toString?.() ?? "0"
4512
4284
  })) ?? [];
4513
4285
 
@@ -4646,7 +4418,7 @@ class QueryCache {
4646
4418
  const byNetwork = getAddresssesByTokenByNetwork(addressesByToken);
4647
4419
  for (const networkId of keys(byNetwork)) {
4648
4420
  if (this.miniMetadatas.has(networkId)) continue;
4649
- const miniMetadata = await getMiniMetadata(this.#chaindataProvider, this.#chainConnector, networkId, "substrate-native");
4421
+ const miniMetadata = await getMiniMetadata$9(this.#chaindataProvider, this.#chainConnector, networkId, "substrate-native");
4650
4422
  this.miniMetadatas.set(networkId, miniMetadata);
4651
4423
  }
4652
4424
 
@@ -4665,7 +4437,7 @@ class QueryCache {
4665
4437
  freezes: ["Balances", "Freezes"]
4666
4438
  }
4667
4439
  });
4668
- const queries = await buildQueries$1(chains, tokens, chainStorageCoders, this.miniMetadatas, queryResults.newAddressesByToken);
4440
+ const queries = await buildQueries$4(chains, tokens, chainStorageCoders, this.miniMetadatas, queryResults.newAddressesByToken);
4669
4441
  // now update the cache
4670
4442
  Object.entries(queries).forEach(([key, query]) => {
4671
4443
  this.balanceQueryCache.set(key, query);
@@ -4694,21 +4466,21 @@ class SubNativeBalanceError extends Error {
4694
4466
  }
4695
4467
  }
4696
4468
 
4697
- const DotNetworkPropertiesSimple = z.object({
4469
+ const DotNetworkPropertiesSimple$1 = z.object({
4698
4470
  tokenDecimals: z.number().optional().default(0),
4699
4471
  tokenSymbol: z.string().optional().default("Unit")
4700
4472
  });
4701
- const DotNetworkPropertiesArray = z.object({
4473
+ const DotNetworkPropertiesArray$1 = z.object({
4702
4474
  tokenDecimals: z.array(z.number()).nonempty(),
4703
4475
  tokenSymbol: z.array(z.string()).nonempty()
4704
4476
  });
4705
- const DotNetworkPropertiesSchema = z.union([DotNetworkPropertiesSimple, DotNetworkPropertiesArray]).transform(val => ({
4477
+ const DotNetworkPropertiesSchema$1 = z.union([DotNetworkPropertiesSimple$1, DotNetworkPropertiesArray$1]).transform(val => ({
4706
4478
  tokenDecimals: Array.isArray(val.tokenDecimals) ? val.tokenDecimals[0] : val.tokenDecimals,
4707
4479
  tokenSymbol: Array.isArray(val.tokenSymbol) ? val.tokenSymbol[0] : val.tokenSymbol
4708
4480
  }));
4709
- const getChainProperties = async (chainConnector, networkId) => {
4481
+ const getChainProperties$1 = async (chainConnector, networkId) => {
4710
4482
  const properties = await chainConnector.send(networkId, "system_properties", [], true);
4711
- return DotNetworkPropertiesSchema.parse(properties);
4483
+ return DotNetworkPropertiesSchema$1.parse(properties);
4712
4484
  };
4713
4485
 
4714
4486
  const POLLING_WINDOW_SIZE = 20;
@@ -4994,7 +4766,7 @@ const SubNativeModule = hydrate => {
4994
4766
  const {
4995
4767
  tokenSymbol: symbol,
4996
4768
  tokenDecimals: decimals
4997
- } = await getChainProperties(chainConnector, chainId);
4769
+ } = await getChainProperties$1(chainConnector, chainId);
4998
4770
  const {
4999
4771
  existentialDeposit
5000
4772
  } = chainMeta.extra ?? {};
@@ -5033,7 +4805,7 @@ const SubNativeModule = hydrate => {
5033
4805
  try {
5034
4806
  // this is what we want to be done separately for each network
5035
4807
  // this will update the DB so minimetadata will be available when it's used, everywhere else down the tree of subscribeChainBalances
5036
- await getMiniMetadata(chaindataProvider, chainConnector, networkId, moduleType$2, controller.signal);
4808
+ await getMiniMetadata$9(chaindataProvider, chainConnector, networkId, moduleType$2, controller.signal);
5037
4809
  } catch (err) {
5038
4810
  if (!isAbortError(err)) log.warn("Failed to get native token miniMetadata for network", networkId, err);
5039
4811
  return () => {};
@@ -6350,7 +6122,7 @@ const SubPsp22Module = hydrate => {
6350
6122
  if (!subscriptionActive) return;
6351
6123
  try {
6352
6124
  assert(chainConnectors.substrate, "This module requires a substrate chain connector");
6353
- const balances = await fetchBalances(chainConnectors.substrate, tokens, addressesByToken);
6125
+ const balances = await fetchBalances$9(chainConnectors.substrate, tokens, addressesByToken);
6354
6126
 
6355
6127
  // Don't call callback with balances which have not changed since the last poll.
6356
6128
  const updatedBalances = new Balances([...balances].filter(b => {
@@ -6373,7 +6145,7 @@ const SubPsp22Module = hydrate => {
6373
6145
  async fetchBalances(addressesByToken) {
6374
6146
  assert(chainConnectors.substrate, "This module requires a substrate chain connector");
6375
6147
  const tokens = await chaindataProvider.getTokensMapById();
6376
- return fetchBalances(chainConnectors.substrate, tokens, addressesByToken);
6148
+ return fetchBalances$9(chainConnectors.substrate, tokens, addressesByToken);
6377
6149
  },
6378
6150
  async transferToken({
6379
6151
  tokenId,
@@ -6453,7 +6225,7 @@ const SubPsp22Module = hydrate => {
6453
6225
  }
6454
6226
  };
6455
6227
  };
6456
- const fetchBalances = async (chainConnector, tokens, addressesByToken) => {
6228
+ const fetchBalances$9 = async (chainConnector, tokens, addressesByToken) => {
6457
6229
  const registry = new TypeRegistry();
6458
6230
  const Psp22Abi = new Abi(psp22Abi);
6459
6231
  const balanceRequests = Object.entries(addressesByToken).flatMap(([tokenId, addresses]) => addresses.map(address => [tokenId, address])).flatMap(async ([tokenId, address]) => {
@@ -6614,7 +6386,7 @@ const SubTokensModule = hydrate => {
6614
6386
  },
6615
6387
  async fetchBalances(addressesByToken) {
6616
6388
  assert(chainConnectors.substrate, "This module requires a substrate chain connector");
6617
- const queries = await buildQueries(chainConnector, chaindataProvider, addressesByToken);
6389
+ const queries = await buildQueries$3(chainConnector, chaindataProvider, addressesByToken);
6618
6390
  const result = await new RpcStateQueryHelper(chainConnectors.substrate, queries).fetch();
6619
6391
  const balances = result?.filter(b => b !== null) ?? [];
6620
6392
  return new Balances(balances);
@@ -6631,7 +6403,7 @@ const SubTokensModule = hydrate => {
6631
6403
  const chainId = token.networkId;
6632
6404
  const chain = await chaindataProvider.getNetworkById(chainId, "polkadot");
6633
6405
  assert(chain?.genesisHash, `Chain ${chainId} not found in store`);
6634
- const miniMetadata = await getMiniMetadata(chaindataProvider, chainConnector, chainId, moduleType);
6406
+ const miniMetadata = await getMiniMetadata$9(chaindataProvider, chainConnector, chainId, moduleType);
6635
6407
  const tokensPallet = miniMetadata?.extra?.palletId ?? defaultPalletId;
6636
6408
  const onChainId = (() => {
6637
6409
  try {
@@ -6732,7 +6504,7 @@ const SubTokensModule = hydrate => {
6732
6504
  };
6733
6505
  };
6734
6506
  async function buildNetworkQueries(networkId, chainConnector, chaindataProvider, addressesByToken, signal) {
6735
- const miniMetadata = await getMiniMetadata(chaindataProvider, chainConnector, networkId, moduleType, signal);
6507
+ const miniMetadata = await getMiniMetadata$9(chaindataProvider, chainConnector, networkId, moduleType, signal);
6736
6508
  const chain = await chaindataProvider.getNetworkById(networkId, "polkadot");
6737
6509
  const tokens = await chaindataProvider.getTokensMapById();
6738
6510
  if (!chain) return [];
@@ -6803,7 +6575,7 @@ async function buildNetworkQueries(networkId, chainConnector, chaindataProvider,
6803
6575
  });
6804
6576
  });
6805
6577
  }
6806
- async function buildQueries(chainConnector, chaindataProvider, addressesByToken, signal) {
6578
+ async function buildQueries$3(chainConnector, chaindataProvider, addressesByToken, signal) {
6807
6579
  const byNetwork = keys(addressesByToken).reduce((acc, tokenId) => {
6808
6580
  const networkId = parseSubTokensTokenId(tokenId).networkId;
6809
6581
  if (!acc[networkId]) acc[networkId] = {};
@@ -6817,4 +6589,3796 @@ async function buildQueries(chainConnector, chaindataProvider, addressesByToken,
6817
6589
 
6818
6590
  const defaultBalanceModules = [EvmErc20Module, EvmNativeModule, EvmUniswapV2Module, SubAssetsModule, SubForeignAssetsModule, SubNativeModule, SubPsp22Module, SubTokensModule];
6819
6591
 
6820
- export { Balance, BalanceFormatter, BalanceValueGetter, Balances, Change24hCurrencyFormatter, DefaultBalanceModule, EvmErc20Module, EvmErc20TokenConfigSchema, EvmNativeModule, EvmNativeTokenConfigSchema, EvmUniswapV2Module, EvmUniswapV2TokenConfigSchema, FiatSumBalancesFormatter, ONE_ALPHA_TOKEN, PlanckSumBalancesFormatter, RpcStateQueryHelper, SCALE_FACTOR, SUBTENSOR_MIN_STAKE_AMOUNT_PLANK, SUBTENSOR_ROOT_NETUID, SubAssetsModule, SubAssetsTokenConfigSchema, SubForeignAssetsModule, SubForeignAssetsTokenConfigSchema, SubNativeModule, SubNativeTokenConfigSchema, SubPsp22Module, SubPsp22TokenConfigSchema, SubTokensModule, SubTokensTokenConfigSchema, SumBalancesFormatter, TalismanBalancesDatabase, abiMulticall, balances, buildNetworkStorageCoders, buildStorageCoders, calculateAlphaPrice, calculateTaoAmountFromAlpha, calculateTaoFromDynamicInfo, compress, configureStore, db, decodeOutput, decompress, defaultBalanceModules, deriveMiniMetadataId, detectTransferMethod, erc20Abi, erc20BalancesAggregatorAbi, excludeFromFeePayableLocks, excludeFromTransferableAmount, filterBaseLocks, filterMirrorTokens, getBalanceId, getLockTitle, getUniqueChainIds, getValueId, includeInTotalExtraAmount, makeContractCaller, uniswapV2PairAbi };
6592
+ const MODULE_TYPE$8 = EvmErc20TokenSchema.shape.type.value;
6593
+ const PLATFORM$8 = EvmErc20TokenSchema.shape.platform.value;
6594
+
6595
+ // to be used by chaindata too
6596
+ z.strictObject({
6597
+ contractAddress: EvmErc20TokenSchema.shape.contractAddress,
6598
+ ...TokenConfigBaseSchema.shape
6599
+ });
6600
+
6601
+ class BalanceFetchError extends Error {
6602
+ constructor(message, tokenId, address, cause) {
6603
+ super(message);
6604
+ this.name = "BalanceFetchError";
6605
+ this.tokenId = tokenId;
6606
+ this.address = address;
6607
+ if (cause) this.cause = cause;
6608
+ }
6609
+ }
6610
+ class BalanceFetchNetworkError extends Error {
6611
+ constructor(message, evmNetworkId, cause) {
6612
+ super(message);
6613
+ this.name = "BalanceFetchNetworkError";
6614
+ this.evmNetworkId = evmNetworkId;
6615
+ if (cause) this.cause = cause;
6616
+ }
6617
+ }
6618
+
6619
+ const getBalanceDefs = addressesByToken => {
6620
+ return addressesByToken.flatMap(([token, addresses]) => addresses.map(address => ({
6621
+ token,
6622
+ address
6623
+ })));
6624
+ };
6625
+
6626
+ const fetchBalances$8 = async ({
6627
+ networkId,
6628
+ addressesByToken,
6629
+ connector
6630
+ }) => {
6631
+ const client = await connector.getPublicClientForEvmNetwork(networkId);
6632
+ if (!client) throw new Error(`Could not get rpc provider for evm network ${networkId}`);
6633
+ for (const [token, addresses] of addressesByToken) {
6634
+ 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}`);
6635
+ for (const address of addresses) if (!isEthereumAddress(address)) throw new Error(`Invalid ethereum address for EVM ERC20 balance module: ${address} for token ${token.id}`);
6636
+ }
6637
+ const balanceDefs = getBalanceDefs(addressesByToken);
6638
+ if (client.chain?.contracts?.erc20Aggregator && balanceDefs.length > 1) {
6639
+ const erc20Aggregator = client.chain.contracts.erc20Aggregator;
6640
+ return fetchWithAggregator$1(client, balanceDefs, erc20Aggregator.address);
6641
+ }
6642
+ return fetchWithoutAggregator$1(client, balanceDefs);
6643
+ };
6644
+ const fetchWithoutAggregator$1 = async (client, balanceDefs) => {
6645
+ if (balanceDefs.length === 0) return {
6646
+ success: [],
6647
+ errors: []
6648
+ };
6649
+ log.debug("fetching %s balances without aggregator", MODULE_TYPE$8, balanceDefs.length);
6650
+ const results = await Promise.allSettled(balanceDefs.map(async ({
6651
+ token,
6652
+ address
6653
+ }) => {
6654
+ try {
6655
+ const result = await client.readContract({
6656
+ abi: erc20Abi,
6657
+ address: token.contractAddress,
6658
+ functionName: "balanceOf",
6659
+ args: [address]
6660
+ });
6661
+ const balance = {
6662
+ address,
6663
+ tokenId: token.id,
6664
+ value: result.toString(),
6665
+ source: MODULE_TYPE$8,
6666
+ networkId: parseEvmErc20TokenId(token.id).networkId,
6667
+ status: "cache"
6668
+ };
6669
+ return balance;
6670
+ } catch (err) {
6671
+ throw new BalanceFetchError(`Failed to get balance for token ${token.id} and address ${address} on chain ${client.chain?.id}`, token.id, address, err);
6672
+ }
6673
+ }));
6674
+ return results.reduce((acc, result) => {
6675
+ if (result.status === "fulfilled") acc.success.push(result.value);else {
6676
+ const error = result.reason;
6677
+ acc.errors.push({
6678
+ tokenId: error.tokenId,
6679
+ address: error.address,
6680
+ error
6681
+ });
6682
+ }
6683
+ return acc;
6684
+ }, {
6685
+ success: [],
6686
+ errors: []
6687
+ });
6688
+ };
6689
+ const fetchWithAggregator$1 = async (client, balanceDefs, erc20BalancesAggregatorAddress) => {
6690
+ if (balanceDefs.length === 0) return {
6691
+ success: [],
6692
+ errors: []
6693
+ };
6694
+ log.debug("fetching %s balances with aggregator", MODULE_TYPE$8, balanceDefs.length);
6695
+ try {
6696
+ const erc20Balances = await client.readContract({
6697
+ abi: erc20BalancesAggregatorAbi,
6698
+ address: erc20BalancesAggregatorAddress,
6699
+ functionName: "balances",
6700
+ args: [balanceDefs.map(b => ({
6701
+ account: b.address,
6702
+ token: b.token.contractAddress
6703
+ }))]
6704
+ });
6705
+ const success = balanceDefs.map((balanceDef, index) => ({
6706
+ address: balanceDef.address,
6707
+ tokenId: balanceDef.token.id,
6708
+ value: erc20Balances[index].toString(),
6709
+ source: MODULE_TYPE$8,
6710
+ networkId: parseTokenId(balanceDef.token.id).networkId,
6711
+ status: "cache"
6712
+ }));
6713
+ return {
6714
+ success,
6715
+ errors: []
6716
+ };
6717
+ } catch (err) {
6718
+ const errors = balanceDefs.map(balanceDef => ({
6719
+ tokenId: balanceDef.token.id,
6720
+ address: balanceDef.address,
6721
+ error: new BalanceFetchNetworkError(`Failed to get balances for evm-erc20 tokens on chain ${client.chain?.id}`, String(client.chain?.id), err)
6722
+ }));
6723
+ return {
6724
+ success: [],
6725
+ errors
6726
+ };
6727
+ }
6728
+ };
6729
+
6730
+ const getErc20ContractData$1 = async (client, contractAddress) => {
6731
+ try {
6732
+ const contract = getTypedContract$1(client, erc20Abi, contractAddress);
6733
+
6734
+ // eslint-disable-next-line no-var
6735
+ var [symbol, decimals, name] = await Promise.all([contract.read.symbol(), contract.read.decimals(), contract.read.name()]);
6736
+ } catch (e) {
6737
+ if (e instanceof ContractFunctionExecutionError) {
6738
+ // try to perform the contract read with bytes32 symbol
6739
+ const contract = getTypedContract$1(client, erc20Abi_bytes32, contractAddress);
6740
+
6741
+ // eslint-disable-next-line no-var
6742
+ var [bytesSymbol, decimals, nameSymbol] = await Promise.all([contract.read.symbol(), contract.read.decimals(), contract.read.name()]);
6743
+ symbol = hexToString(bytesSymbol).replace(/\0/g, "").trim(); // remove NULL characters
6744
+ name = hexToString(nameSymbol).replace(/\0/g, "").trim(); // remove NULL characters
6745
+ } else throw e;
6746
+ }
6747
+ return {
6748
+ symbol,
6749
+ decimals,
6750
+ name
6751
+ };
6752
+ };
6753
+ const getTypedContract$1 = (client, abi, contractAddress) => getContract({
6754
+ address: contractAddress,
6755
+ abi,
6756
+ client: {
6757
+ public: client
6758
+ }
6759
+ });
6760
+
6761
+ const TokenCacheSchema$1 = EvmErc20TokenSchema.pick({
6762
+ symbol: true,
6763
+ decimals: true,
6764
+ name: true
6765
+ });
6766
+ const fetchTokens$8 = async ({
6767
+ networkId,
6768
+ tokens,
6769
+ connector,
6770
+ cache
6771
+ }) => {
6772
+ const result = [];
6773
+ for (const tokenConfig of tokens) {
6774
+ const tokenId = evmErc20TokenId(networkId, tokenConfig.contractAddress);
6775
+ if (!cache[tokenId] || !TokenCacheSchema$1.safeParse(cache[tokenId]).success) {
6776
+ const client = await connector.getPublicClientForEvmNetwork(networkId);
6777
+ if (!client) {
6778
+ log.warn(`No client found for network ${networkId} while fetching EVM ERC20 tokens`);
6779
+ continue;
6780
+ }
6781
+ try {
6782
+ const {
6783
+ name,
6784
+ decimals,
6785
+ symbol
6786
+ } = await getErc20ContractData$1(client, tokenConfig.contractAddress);
6787
+ cache[tokenId] = {
6788
+ id: tokenId,
6789
+ symbol,
6790
+ decimals,
6791
+ name
6792
+ };
6793
+ } catch (err) {
6794
+ log.warn(`Failed to fetch ERC20 token data for ${tokenConfig.contractAddress}`, err);
6795
+ continue;
6796
+ }
6797
+ }
6798
+ const base = {
6799
+ type: MODULE_TYPE$8,
6800
+ platform: PLATFORM$8,
6801
+ networkId
6802
+ };
6803
+ const token = assign(base, cache[tokenId], tokenConfig);
6804
+ const parsed = EvmErc20TokenSchema.safeParse(token);
6805
+ if (!parsed.success) {
6806
+ log.warn("Ignoring token with invalid EvmErc20TokenSchema", token);
6807
+ continue;
6808
+ }
6809
+ result.push(parsed.data);
6810
+ }
6811
+ return result;
6812
+ };
6813
+
6814
+ const getMiniMetadata$8 = () => {
6815
+ throw new Error("MiniMetadata is not supported for ethereum tokens");
6816
+ };
6817
+
6818
+ const getTransferCallData$8 = ({
6819
+ from,
6820
+ to,
6821
+ value,
6822
+ token
6823
+ }) => {
6824
+ if (!isTokenOfType(token, MODULE_TYPE$8)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$8}.`);
6825
+ if (!isEthereumAddress(from)) throw new Error("Invalid from address");
6826
+ if (!isEthereumAddress(to)) throw new Error("Invalid to address");
6827
+ const data = encodeFunctionData({
6828
+ abi: erc20Abi,
6829
+ functionName: "transfer",
6830
+ args: [to, BigInt(value)]
6831
+ });
6832
+ return {
6833
+ from,
6834
+ to: token.contractAddress,
6835
+ data
6836
+ };
6837
+ };
6838
+
6839
+ const SUBSCRIPTION_INTERVAL$8 = 6_000;
6840
+ const subscribeBalances$8 = ({
6841
+ networkId,
6842
+ addressesByToken,
6843
+ connector
6844
+ }) => {
6845
+ return new Observable(subscriber => {
6846
+ const abortController = new AbortController();
6847
+ const poll = async () => {
6848
+ try {
6849
+ if (abortController.signal.aborted) return;
6850
+ const balances = await fetchBalances$8({
6851
+ networkId,
6852
+ addressesByToken,
6853
+ connector
6854
+ });
6855
+ if (abortController.signal.aborted) return;
6856
+ subscriber.next(balances);
6857
+ setTimeout(poll, SUBSCRIPTION_INTERVAL$8);
6858
+ } catch (error) {
6859
+ log.error("Error", {
6860
+ module: MODULE_TYPE$8,
6861
+ networkId,
6862
+ addressesByToken,
6863
+ error
6864
+ });
6865
+ subscriber.error(error);
6866
+ }
6867
+ };
6868
+ poll();
6869
+ return () => {
6870
+ abortController.abort();
6871
+ };
6872
+ }).pipe(distinctUntilChanged(isEqual$1));
6873
+ };
6874
+
6875
+ const EvmErc20BalanceModule = {
6876
+ type: MODULE_TYPE$8,
6877
+ platform: PLATFORM$8,
6878
+ getMiniMetadata: getMiniMetadata$8,
6879
+ fetchTokens: fetchTokens$8,
6880
+ fetchBalances: fetchBalances$8,
6881
+ subscribeBalances: subscribeBalances$8,
6882
+ getTransferCallData: getTransferCallData$8
6883
+ };
6884
+
6885
+ const MODULE_TYPE$7 = EvmNativeTokenSchema.shape.type.value;
6886
+ const PLATFORM$7 = EvmNativeTokenSchema.shape.platform.value;
6887
+
6888
+ // to be used by chaindata too
6889
+ z.strictObject({
6890
+ ...TokenConfigBaseSchema.shape
6891
+ });
6892
+
6893
+ const fetchBalances$7 = async ({
6894
+ networkId,
6895
+ addressesByToken,
6896
+ connector
6897
+ }) => {
6898
+ const client = await connector.getPublicClientForEvmNetwork(networkId);
6899
+ if (!client) throw new Error(`Could not get rpc provider for evm network ${networkId}`);
6900
+ for (const [token, addresses] of addressesByToken) {
6901
+ 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}`);
6902
+ for (const address of addresses) if (!isEthereumAddress(address)) throw new Error(`Invalid ethereum address for EVM ERC20 balance module: ${address} for token ${token.id}`);
6903
+ }
6904
+ const balanceDefs = getBalanceDefs(addressesByToken);
6905
+ if (client.chain?.contracts?.multicall3 && balanceDefs.length > 1) {
6906
+ const multicall3 = client.chain.contracts.multicall3;
6907
+ return fetchWithMulticall(client, balanceDefs, multicall3.address);
6908
+ }
6909
+ return fetchWithoutMulticall(client, balanceDefs);
6910
+ };
6911
+ const fetchWithoutMulticall = async (client, balanceDefs) => {
6912
+ if (balanceDefs.length === 0) return {
6913
+ success: [],
6914
+ errors: []
6915
+ };
6916
+ log.debug("fetching %s balances without multicall3", MODULE_TYPE$7, balanceDefs.length);
6917
+ const results = await Promise.allSettled(balanceDefs.map(async ({
6918
+ token,
6919
+ address
6920
+ }) => {
6921
+ try {
6922
+ const result = await client.getBalance({
6923
+ address
6924
+ });
6925
+ const balance = {
6926
+ address,
6927
+ tokenId: token.id,
6928
+ value: result.toString(),
6929
+ source: MODULE_TYPE$7,
6930
+ networkId: parseTokenId(token.id).networkId,
6931
+ status: "live"
6932
+ };
6933
+ return balance;
6934
+ } catch (err) {
6935
+ throw new BalanceFetchError(`Failed to get balance for token ${token.id} and address ${address} on chain ${client.chain?.id}`, token.id, address, err);
6936
+ }
6937
+ }));
6938
+ return results.reduce((acc, result) => {
6939
+ if (result.status === "fulfilled") acc.success.push(result.value);else {
6940
+ const error = result.reason;
6941
+ acc.errors.push({
6942
+ tokenId: error.tokenId,
6943
+ address: error.address,
6944
+ error
6945
+ });
6946
+ }
6947
+ return acc;
6948
+ }, {
6949
+ success: [],
6950
+ errors: []
6951
+ });
6952
+ };
6953
+ const fetchWithMulticall = async (client, balanceDefs, multicall3Address) => {
6954
+ if (balanceDefs.length === 0) return {
6955
+ success: [],
6956
+ errors: []
6957
+ };
6958
+ log.debug("fetching %s balances with multicall3", MODULE_TYPE$7, balanceDefs.length);
6959
+ try {
6960
+ const callResults = await client.multicall({
6961
+ contracts: balanceDefs.map(({
6962
+ address
6963
+ }) => ({
6964
+ address: multicall3Address,
6965
+ abi: abiMulticall,
6966
+ functionName: "getEthBalance",
6967
+ args: [address]
6968
+ }))
6969
+ });
6970
+ return callResults.reduce((acc, result, index) => {
6971
+ if (result.status === "success") {
6972
+ acc.success.push({
6973
+ address: balanceDefs[index].address,
6974
+ tokenId: balanceDefs[index].token.id,
6975
+ value: result.result.toString(),
6976
+ source: MODULE_TYPE$7,
6977
+ networkId: parseTokenId(balanceDefs[index].token.id).networkId,
6978
+ status: "live"
6979
+ });
6980
+ }
6981
+ if (result.status === "failure") {
6982
+ acc.errors.push({
6983
+ tokenId: balanceDefs[index].token.id,
6984
+ address: balanceDefs[index].address,
6985
+ error: new BalanceFetchError(`Failed to get balance for token ${balanceDefs[index].token.id} and address ${balanceDefs[index].address} on chain ${client.chain?.id}`, balanceDefs[index].token.id, balanceDefs[index].address, result.error)
6986
+ });
6987
+ }
6988
+ return acc;
6989
+ }, {
6990
+ success: [],
6991
+ errors: []
6992
+ });
6993
+ } catch (err) {
6994
+ const errors = balanceDefs.map(balanceDef => ({
6995
+ tokenId: balanceDef.token.id,
6996
+ address: balanceDef.address,
6997
+ error: new BalanceFetchNetworkError(`Failed to get balances for evm-erc20 tokens on chain ${client.chain?.id}`, String(client.chain?.id), err)
6998
+ }));
6999
+ return {
7000
+ success: [],
7001
+ errors
7002
+ };
7003
+ }
7004
+ };
7005
+
7006
+ const fetchTokens$7 = async ({
7007
+ networkId,
7008
+ tokens
7009
+ }) => {
7010
+ // assume there is one and only one token in the array
7011
+ if (tokens.length !== 1) throw new Error("EVM Native module expects the nativeCurrency to be passed as a single token in the array");
7012
+ const token = assign({
7013
+ id: evmNativeTokenId(networkId),
7014
+ type: MODULE_TYPE$7,
7015
+ platform: PLATFORM$7,
7016
+ networkId,
7017
+ isDefault: true
7018
+ }, tokens[0]);
7019
+ const parsed = EvmNativeTokenSchema.safeParse(token);
7020
+ if (!parsed.success) {
7021
+ log.warn("Ignoring token with invalid EvmErc20TokenSchema", token);
7022
+ return [];
7023
+ }
7024
+ return [parsed.data];
7025
+ };
7026
+
7027
+ const getMiniMetadata$7 = () => {
7028
+ throw new Error("MiniMetadata is not supported for ethereum tokens");
7029
+ };
7030
+
7031
+ const getTransferCallData$7 = ({
7032
+ from,
7033
+ to,
7034
+ value,
7035
+ token
7036
+ }) => {
7037
+ if (!isTokenOfType(token, MODULE_TYPE$7)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$7}.`);
7038
+ if (!isEthereumAddress(from)) throw new Error("Invalid from address");
7039
+ if (!isEthereumAddress(to)) throw new Error("Invalid to address");
7040
+ return {
7041
+ from,
7042
+ to,
7043
+ value,
7044
+ data: "0x"
7045
+ };
7046
+ };
7047
+
7048
+ const SUBSCRIPTION_INTERVAL$7 = 6_000;
7049
+ const subscribeBalances$7 = ({
7050
+ networkId,
7051
+ addressesByToken,
7052
+ connector
7053
+ }) => {
7054
+ return new Observable(subscriber => {
7055
+ const abortController = new AbortController();
7056
+ const poll = async () => {
7057
+ try {
7058
+ if (abortController.signal.aborted) return;
7059
+ const balances = await fetchBalances$7({
7060
+ networkId,
7061
+ addressesByToken,
7062
+ connector
7063
+ });
7064
+ if (abortController.signal.aborted) return;
7065
+ subscriber.next(balances);
7066
+ setTimeout(poll, SUBSCRIPTION_INTERVAL$7);
7067
+ } catch (error) {
7068
+ log.error("Error", {
7069
+ module: MODULE_TYPE$7,
7070
+ networkId,
7071
+ addressesByToken,
7072
+ error
7073
+ });
7074
+ subscriber.error(error);
7075
+ }
7076
+ };
7077
+ poll();
7078
+ return () => {
7079
+ abortController.abort();
7080
+ };
7081
+ }).pipe(distinctUntilChanged(isEqual$1));
7082
+ };
7083
+
7084
+ const EvmNativeBalanceModule = {
7085
+ type: MODULE_TYPE$7,
7086
+ platform: PLATFORM$7,
7087
+ getMiniMetadata: getMiniMetadata$7,
7088
+ fetchTokens: fetchTokens$7,
7089
+ fetchBalances: fetchBalances$7,
7090
+ subscribeBalances: subscribeBalances$7,
7091
+ getTransferCallData: getTransferCallData$7
7092
+ };
7093
+
7094
+ const MODULE_TYPE$6 = EvmUniswapV2TokenSchema.shape.type.value;
7095
+ const PLATFORM$6 = EvmUniswapV2TokenSchema.shape.platform.value;
7096
+
7097
+ // to be used by chaindata too
7098
+ z.strictObject({
7099
+ contractAddress: EvmUniswapV2TokenSchema.shape.contractAddress,
7100
+ ...TokenConfigBaseSchema.shape
7101
+ });
7102
+
7103
+ const fetchBalances$6 = async ({
7104
+ networkId,
7105
+ addressesByToken,
7106
+ connector
7107
+ }) => {
7108
+ const client = await connector.getPublicClientForEvmNetwork(networkId);
7109
+ if (!client) throw new Error(`Could not get rpc provider for evm network ${networkId}`);
7110
+ for (const [token, addresses] of addressesByToken) {
7111
+ 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}`);
7112
+ for (const address of addresses) if (!isEthereumAddress(address)) throw new Error(`Invalid ethereum address for EVM ERC20 balance module: ${address} for token ${token.id}`);
7113
+ }
7114
+ const balanceDefs = getBalanceDefs(addressesByToken);
7115
+ if (client.chain?.contracts?.erc20Aggregator && balanceDefs.length > 1) {
7116
+ const erc20Aggregator = client.chain.contracts.erc20Aggregator;
7117
+ return fetchWithAggregator(client, balanceDefs, erc20Aggregator.address);
7118
+ }
7119
+ return fetchWithoutAggregator(client, balanceDefs);
7120
+ };
7121
+ const fetchWithoutAggregator = async (client, balanceDefs) => {
7122
+ if (balanceDefs.length === 0) return {
7123
+ success: [],
7124
+ errors: []
7125
+ };
7126
+ log.debug("fetching %s balances without aggregator", MODULE_TYPE$6, balanceDefs.length);
7127
+ const results = await Promise.allSettled(balanceDefs.map(async ({
7128
+ token,
7129
+ address
7130
+ }) => {
7131
+ try {
7132
+ const result = await client.readContract({
7133
+ abi: erc20Abi,
7134
+ address: token.contractAddress,
7135
+ functionName: "balanceOf",
7136
+ args: [address]
7137
+ });
7138
+ const balance = {
7139
+ address,
7140
+ tokenId: token.id,
7141
+ value: result.toString(),
7142
+ source: MODULE_TYPE$6,
7143
+ networkId: parseTokenId(token.id).networkId,
7144
+ status: "cache"
7145
+ };
7146
+ return balance;
7147
+ } catch (err) {
7148
+ throw new BalanceFetchError(`Failed to get balance for token ${token.id} and address ${address} on chain ${client.chain?.id}`, token.id, address, err);
7149
+ }
7150
+ }));
7151
+ return results.reduce((acc, result) => {
7152
+ if (result.status === "fulfilled") acc.success.push(result.value);else {
7153
+ const error = result.reason;
7154
+ acc.errors.push({
7155
+ tokenId: error.tokenId,
7156
+ address: error.address,
7157
+ error
7158
+ });
7159
+ }
7160
+ return acc;
7161
+ }, {
7162
+ success: [],
7163
+ errors: []
7164
+ });
7165
+ };
7166
+ const fetchWithAggregator = async (client, balanceDefs, erc20BalancesAggregatorAddress) => {
7167
+ if (balanceDefs.length === 0) return {
7168
+ success: [],
7169
+ errors: []
7170
+ };
7171
+ log.debug("fetching %s balances with aggregator", MODULE_TYPE$6, balanceDefs.length);
7172
+ try {
7173
+ const erc20Balances = await client.readContract({
7174
+ abi: erc20BalancesAggregatorAbi,
7175
+ address: erc20BalancesAggregatorAddress,
7176
+ functionName: "balances",
7177
+ args: [balanceDefs.map(b => ({
7178
+ account: b.address,
7179
+ token: b.token.contractAddress
7180
+ }))]
7181
+ });
7182
+ const success = balanceDefs.map((balanceDef, index) => ({
7183
+ address: balanceDef.address,
7184
+ tokenId: balanceDef.token.id,
7185
+ value: erc20Balances[index].toString(),
7186
+ source: MODULE_TYPE$6,
7187
+ networkId: parseTokenId(balanceDef.token.id).networkId,
7188
+ status: "cache"
7189
+ }));
7190
+ return {
7191
+ success,
7192
+ errors: []
7193
+ };
7194
+ } catch (err) {
7195
+ const errors = balanceDefs.map(balanceDef => ({
7196
+ tokenId: balanceDef.token.id,
7197
+ address: balanceDef.address,
7198
+ error: new BalanceFetchNetworkError(`Failed to get balances for evm-erc20 tokens on chain ${client.chain?.id}`, String(client.chain?.id), err)
7199
+ }));
7200
+ return {
7201
+ success: [],
7202
+ errors
7203
+ };
7204
+ }
7205
+ };
7206
+
7207
+ const getErc20ContractData = async (client, contractAddress) => {
7208
+ try {
7209
+ const contract = getTypedContract(client, erc20Abi, contractAddress);
7210
+
7211
+ // eslint-disable-next-line no-var
7212
+ var [symbol, decimals, name] = await Promise.all([contract.read.symbol(), contract.read.decimals(), contract.read.name()]);
7213
+ } catch (e) {
7214
+ if (e instanceof ContractFunctionExecutionError) {
7215
+ // try to perform the contract read with bytes32 symbol
7216
+ const contract = getTypedContract(client, erc20Abi_bytes32, contractAddress);
7217
+
7218
+ // eslint-disable-next-line no-var
7219
+ var [bytesSymbol, decimals, nameSymbol] = await Promise.all([contract.read.symbol(), contract.read.decimals(), contract.read.name()]);
7220
+ symbol = hexToString(bytesSymbol).replace(/\0/g, "").trim(); // remove NULL characters
7221
+ name = hexToString(nameSymbol).replace(/\0/g, "").trim(); // remove NULL characters
7222
+ } else throw e;
7223
+ }
7224
+ return {
7225
+ symbol,
7226
+ decimals,
7227
+ name
7228
+ };
7229
+ };
7230
+ const getTypedContract = (client, abi, contractAddress) => getContract({
7231
+ address: contractAddress,
7232
+ abi,
7233
+ client: {
7234
+ public: client
7235
+ }
7236
+ });
7237
+ const getUniswapV2PairContractData = async (client, contractAddress) => {
7238
+ const contract = getTypedContract(client, uniswapV2PairAbi, contractAddress);
7239
+
7240
+ // eslint-disable-next-line no-var
7241
+ var [token0, token1, decimals, name] = await Promise.all([contract.read.token0(), contract.read.token1(), contract.read.decimals(), contract.read.name()]);
7242
+ return {
7243
+ token0,
7244
+ token1,
7245
+ decimals,
7246
+ name
7247
+ };
7248
+ };
7249
+
7250
+ const TokenCacheSchema = EvmUniswapV2TokenSchema.pick({
7251
+ symbol: true,
7252
+ decimals: true,
7253
+ name: true,
7254
+ tokenAddress0: true,
7255
+ tokenAddress1: true,
7256
+ decimals0: true,
7257
+ decimals1: true,
7258
+ symbol0: true,
7259
+ symbol1: true
7260
+ });
7261
+ const fetchTokens$6 = async ({
7262
+ networkId,
7263
+ tokens,
7264
+ connector,
7265
+ cache
7266
+ }) => {
7267
+ const result = [];
7268
+ for (const tokenConfig of tokens) {
7269
+ const tokenId = evmUniswapV2TokenId(networkId, tokenConfig.contractAddress);
7270
+ if (!cache[tokenId] || !TokenCacheSchema.safeParse(cache[tokenId]).success) {
7271
+ const client = await connector.getPublicClientForEvmNetwork(networkId);
7272
+ if (!client) {
7273
+ log.warn(`No client found for network ${networkId} while fetching EVM ERC20 tokens`);
7274
+ continue;
7275
+ }
7276
+ try {
7277
+ const {
7278
+ token0,
7279
+ token1,
7280
+ name,
7281
+ decimals
7282
+ } = await getUniswapV2PairContractData(client, tokenConfig.contractAddress);
7283
+ const {
7284
+ symbol: symbol0,
7285
+ decimals: decimals0
7286
+ } = await getErc20ContractData(client, token0);
7287
+ const {
7288
+ symbol: symbol1,
7289
+ decimals: decimals1
7290
+ } = await getErc20ContractData(client, token1);
7291
+ cache[tokenId] = {
7292
+ id: tokenId,
7293
+ symbol: `${symbol0}/${symbol1}`,
7294
+ decimals,
7295
+ name,
7296
+ tokenAddress0: token0,
7297
+ tokenAddress1: token1,
7298
+ decimals0,
7299
+ decimals1,
7300
+ symbol0,
7301
+ symbol1
7302
+ };
7303
+ } catch (err) {
7304
+ log.warn(`Failed to fetch UniswapV2 token data for ${tokenConfig.contractAddress}`, err.shortMessage);
7305
+ continue;
7306
+ }
7307
+ }
7308
+ const base = {
7309
+ type: MODULE_TYPE$6,
7310
+ platform: PLATFORM$6,
7311
+ networkId
7312
+ };
7313
+ const token = assign(base, cache[tokenId], tokenConfig);
7314
+ const parsed = EvmUniswapV2TokenSchema.safeParse(token);
7315
+ if (!parsed.success) {
7316
+ log.warn("Ignoring token with invalid EvmErc20TokenSchema", token);
7317
+ continue;
7318
+ }
7319
+ result.push(parsed.data);
7320
+ }
7321
+ return result;
7322
+ };
7323
+
7324
+ const getMiniMetadata$6 = () => {
7325
+ throw new Error("MiniMetadata is not supported for ethereum tokens");
7326
+ };
7327
+
7328
+ const getTransferCallData$6 = ({
7329
+ from,
7330
+ to,
7331
+ value,
7332
+ token
7333
+ }) => {
7334
+ if (!isTokenOfType(token, MODULE_TYPE$6)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$6}.`);
7335
+ if (!isEthereumAddress(from)) throw new Error("Invalid from address");
7336
+ if (!isEthereumAddress(to)) throw new Error("Invalid to address");
7337
+ const data = encodeFunctionData({
7338
+ abi: erc20Abi,
7339
+ functionName: "transfer",
7340
+ args: [to, BigInt(value)]
7341
+ });
7342
+ return {
7343
+ from,
7344
+ to: token.contractAddress,
7345
+ data
7346
+ };
7347
+ };
7348
+
7349
+ const SUBSCRIPTION_INTERVAL$6 = 6_000;
7350
+ const subscribeBalances$6 = ({
7351
+ networkId,
7352
+ addressesByToken,
7353
+ connector
7354
+ }) => {
7355
+ return new Observable(subscriber => {
7356
+ const abortController = new AbortController();
7357
+ const poll = async () => {
7358
+ try {
7359
+ if (abortController.signal.aborted) return;
7360
+ const balances = await fetchBalances$6({
7361
+ networkId,
7362
+ addressesByToken,
7363
+ connector
7364
+ });
7365
+ if (abortController.signal.aborted) return;
7366
+ subscriber.next(balances);
7367
+ setTimeout(poll, SUBSCRIPTION_INTERVAL$6);
7368
+ } catch (error) {
7369
+ log.error("Error", {
7370
+ module: MODULE_TYPE$6,
7371
+ networkId,
7372
+ addressesByToken,
7373
+ error
7374
+ });
7375
+ subscriber.error(error);
7376
+ }
7377
+ };
7378
+ poll();
7379
+ return () => {
7380
+ abortController.abort();
7381
+ };
7382
+ }).pipe(distinctUntilChanged(isEqual$1));
7383
+ };
7384
+
7385
+ const EvmUniswapV2BalanceModule = {
7386
+ type: MODULE_TYPE$6,
7387
+ platform: PLATFORM$6,
7388
+ getMiniMetadata: getMiniMetadata$6,
7389
+ fetchTokens: fetchTokens$6,
7390
+ fetchBalances: fetchBalances$6,
7391
+ subscribeBalances: subscribeBalances$6,
7392
+ getTransferCallData: getTransferCallData$6
7393
+ };
7394
+
7395
+ const MODULE_TYPE$5 = SubAssetsTokenSchema.shape.type.value;
7396
+ const PLATFORM$5 = SubAssetsTokenSchema.shape.platform.value;
7397
+
7398
+ // to be used by chaindata too
7399
+ z.strictObject({
7400
+ assetId: SubAssetsTokenSchema.shape.assetId,
7401
+ ...TokenConfigBaseSchema.shape
7402
+ });
7403
+
7404
+ const fetchBalances$5 = async ({
7405
+ networkId,
7406
+ addressesByToken,
7407
+ connector,
7408
+ miniMetadata
7409
+ }) => {
7410
+ const balanceDefs = getBalanceDefs(addressesByToken);
7411
+ if (!miniMetadata?.data) {
7412
+ log.warn("MiniMetadata is required for fetching balances");
7413
+ return {
7414
+ success: [],
7415
+ errors: balanceDefs.map(def => ({
7416
+ tokenId: def.token.id,
7417
+ address: def.address,
7418
+ error: new Error("Minimetadata is required for fetching balances")
7419
+ }))
7420
+ };
7421
+ }
7422
+ if (miniMetadata.source !== MODULE_TYPE$5) {
7423
+ log.warn(`Ignoring miniMetadata with source ${miniMetadata.source} in ${MODULE_TYPE$5}.`);
7424
+ return {
7425
+ success: [],
7426
+ errors: balanceDefs.map(def => ({
7427
+ tokenId: def.token.id,
7428
+ address: def.address,
7429
+ error: new Error(`Invalid request: miniMetadata source is not ${MODULE_TYPE$5}`)
7430
+ }))
7431
+ };
7432
+ }
7433
+ if (miniMetadata.chainId !== networkId) {
7434
+ log.warn(`Ignoring miniMetadata with chainId ${miniMetadata.chainId} in ${MODULE_TYPE$5}. Expected chainId is ${networkId}`);
7435
+ return {
7436
+ success: [],
7437
+ errors: balanceDefs.map(def => ({
7438
+ tokenId: def.token.id,
7439
+ address: def.address,
7440
+ error: new Error(`Invalid request: Expected chainId is ${networkId}`)
7441
+ }))
7442
+ };
7443
+ }
7444
+ const queries = buildQueries$2(networkId, balanceDefs, miniMetadata);
7445
+ const balances = await new RpcStateQueryHelper(connector, queries).fetch();
7446
+ return balanceDefs.reduce((acc, def) => {
7447
+ const balance = balances.find(b => b?.address === def.address && b?.tokenId === def.token.id);
7448
+ if (balance) acc.success.push(balance);
7449
+ //if no entry consider empty balance
7450
+ else acc.success.push({
7451
+ address: def.address,
7452
+ networkId,
7453
+ tokenId: def.token.id,
7454
+ source: MODULE_TYPE$5,
7455
+ status: "live",
7456
+ values: [{
7457
+ type: "free",
7458
+ label: "free",
7459
+ amount: "0"
7460
+ }, {
7461
+ type: "locked",
7462
+ label: "frozen",
7463
+ amount: "0"
7464
+ }]
7465
+ });
7466
+ return acc;
7467
+ }, {
7468
+ success: [],
7469
+ errors: []
7470
+ });
7471
+ };
7472
+ const buildQueries$2 = (networkId, balanceDefs, miniMetadata) => {
7473
+ const networkStorageCoders = buildNetworkStorageCoders(networkId, miniMetadata, {
7474
+ storage: ["Assets", "Account"]
7475
+ });
7476
+ return balanceDefs.map(({
7477
+ token,
7478
+ address
7479
+ }) => {
7480
+ const scaleCoder = networkStorageCoders?.storage;
7481
+ const stateKey = tryEncode(scaleCoder, Number(token.assetId), address) ??
7482
+ // Asset Hub
7483
+ tryEncode(scaleCoder, BigInt(token.assetId), address); // Astar
7484
+
7485
+ if (!stateKey) {
7486
+ log.warn(`Invalid assetId / address in ${networkId} storage query ${token.assetId} / ${address}`);
7487
+ return null;
7488
+ }
7489
+ const decodeResult = change => {
7490
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
7491
+
7492
+ const decoded = decodeScale(scaleCoder, change, `Failed to decode substrate-assets balance on chain ${networkId}`) ?? {
7493
+ balance: 0n,
7494
+ status: {
7495
+ type: "Liquid"
7496
+ }};
7497
+ const isFrozen = decoded?.status?.type === "Frozen";
7498
+ const amount = (decoded?.balance ?? 0n).toString();
7499
+
7500
+ // due to the following balance calculations, which are made in the `Balance` type:
7501
+ //
7502
+ // total balance = (free balance) + (reserved balance)
7503
+ // transferable balance = (free balance) - (frozen balance)
7504
+ //
7505
+ // when `isFrozen` is true we need to set **both** the `free` and `frozen` amounts
7506
+ // of this balance to the value we received from the RPC.
7507
+ //
7508
+ // if we only set the `frozen` amount, then the `total` calculation will be incorrect!
7509
+ const free = amount;
7510
+ const frozen = token.isFrozen || isFrozen ? amount : "0";
7511
+
7512
+ // include balance values even if zero, so that newly-zero values overwrite old values
7513
+ const balanceValues = [{
7514
+ type: "free",
7515
+ label: "free",
7516
+ amount: free.toString()
7517
+ }, {
7518
+ type: "locked",
7519
+ label: "frozen",
7520
+ amount: frozen.toString()
7521
+ }];
7522
+ const balance = {
7523
+ source: "substrate-assets",
7524
+ status: "live",
7525
+ address,
7526
+ networkId,
7527
+ tokenId: token.id,
7528
+ values: balanceValues
7529
+ };
7530
+ return balance;
7531
+ };
7532
+ return {
7533
+ chainId: networkId,
7534
+ stateKey,
7535
+ decodeResult
7536
+ };
7537
+ }).filter(isNotNil);
7538
+ };
7539
+ const tryEncode = (scaleCoder, ...args) => {
7540
+ try {
7541
+ return scaleCoder?.keys?.enc?.(...args);
7542
+ } catch {
7543
+ return null;
7544
+ }
7545
+ };
7546
+
7547
+ const fetchTokens$5 = async ({
7548
+ networkId,
7549
+ tokens,
7550
+ connector,
7551
+ miniMetadata
7552
+ }) => {
7553
+ const anyMiniMetadata = miniMetadata;
7554
+ if (!anyMiniMetadata?.data) return [];
7555
+ const {
7556
+ builder
7557
+ } = parseMetadataRpc(anyMiniMetadata.data);
7558
+ const assetCodec = builder.buildStorage("Assets", "Asset");
7559
+ const metadataCodec = builder.buildStorage("Assets", "Metadata");
7560
+ const [allAssetStorageKeys, allMetadataStorageKeys] = await Promise.all([connector.send(networkId, "state_getKeys", [getStorageKeyPrefix("Assets", "Asset")]), connector.send(networkId, "state_getKeys", [getStorageKeyPrefix("Assets", "Metadata")])]);
7561
+ const [assetStorageResults, metadataStorageResults] = await Promise.all([connector.send(networkId, "state_queryStorageAt", [allAssetStorageKeys]), connector.send(networkId, "state_queryStorageAt", [allMetadataStorageKeys])]);
7562
+ const assetStorageEntries = assetStorageResults[0].changes;
7563
+ const metadataStorageEntries = metadataStorageResults[0].changes;
7564
+ const assetByAssetId = keyBy(assetStorageEntries.map(([key, value]) => {
7565
+ const [assetId] = assetCodec.keys.dec(key);
7566
+ const asset = assetCodec.value.dec(value);
7567
+ return {
7568
+ assetId,
7569
+ existentialDeposit: asset.min_balance,
7570
+ isSufficient: asset.is_sufficient
7571
+ };
7572
+ }), a => a.assetId);
7573
+ const metadataByAssetId = keyBy(metadataStorageEntries.map(([key, value]) => {
7574
+ const [assetId] = metadataCodec.keys.dec(key);
7575
+ const metadata = metadataCodec.value.dec(value);
7576
+ return {
7577
+ assetId,
7578
+ decimals: metadata.decimals,
7579
+ isFrozen: metadata.is_frozen,
7580
+ name: metadata.name?.asText(),
7581
+ symbol: metadata.symbol?.asText()
7582
+ };
7583
+ }), a => a.assetId);
7584
+ const allTokens = keys(assetByAssetId).map(assetId => assign({}, assetByAssetId[assetId], metadataByAssetId[assetId] ?? undefined));
7585
+ const configTokenByAssetId = keyBy(tokens, t => t.assetId);
7586
+ return allTokens.map(asset => ({
7587
+ id: subAssetTokenId(networkId, String(asset.assetId)),
7588
+ type: MODULE_TYPE$5,
7589
+ platform: "polkadot",
7590
+ networkId,
7591
+ assetId: String(asset.assetId),
7592
+ isSufficient: asset.isSufficient,
7593
+ isFrozen: asset.isFrozen,
7594
+ name: asset.name,
7595
+ symbol: asset.symbol,
7596
+ decimals: asset.decimals ?? 0,
7597
+ existentialDeposit: String(asset.existentialDeposit),
7598
+ isDefault: true
7599
+ }))
7600
+ // keep all tokens listed in the config + all tokens marked as sufficient
7601
+ .filter(token => {
7602
+ const configToken = configTokenByAssetId[token.assetId];
7603
+ return configToken || token.isSufficient;
7604
+ })
7605
+ // apply config overrides
7606
+ .map(token => {
7607
+ const configToken = configTokenByAssetId[token.assetId];
7608
+ return configToken ? assign({}, token, configToken) : token;
7609
+ })
7610
+ // validate results
7611
+ .filter(t => {
7612
+ const parsed = SubAssetsTokenSchema.safeParse(t);
7613
+ if (!parsed.success) log.warn(`Ignoring invalid token ${MODULE_TYPE$5}`, t);
7614
+ return parsed.success;
7615
+ });
7616
+ };
7617
+
7618
+ const getConstantValue = (metadataRpc, pallet, constant) => {
7619
+ const {
7620
+ unifiedMetadata,
7621
+ builder
7622
+ } = parseMetadataRpc(metadataRpc);
7623
+ const codec = builder.buildConstant(pallet, constant);
7624
+ const encodedValue = unifiedMetadata.pallets.find(({
7625
+ name
7626
+ }) => name === pallet)?.constants.find(({
7627
+ name
7628
+ }) => name === constant)?.value;
7629
+ if (!encodedValue) throw new Error(`Constant ${pallet}.${constant} not found`);
7630
+ return codec.dec(encodedValue);
7631
+ };
7632
+
7633
+ const hasStorageItem = (metadata, palletName, itemName) => {
7634
+ const pallet = metadata.pallets.find(p => p.name === palletName);
7635
+ if (!pallet || !pallet.storage) return false;
7636
+ return pallet.storage.items.some(item => item.name === itemName);
7637
+ };
7638
+ const hasStorageItems = (metadata, palletName, itemNames) => {
7639
+ const pallet = metadata.pallets.find(p => p.name === palletName);
7640
+ if (!pallet || !pallet.storage) return false;
7641
+ return itemNames.every(itemName => pallet.storage?.items.some(item => item.name === itemName));
7642
+ };
7643
+ const hasRuntimeApi = (metadata, apiName, method) => {
7644
+ const api = metadata.apis.find(api => api.name === apiName);
7645
+ if (!api || !api.methods) return false;
7646
+ return api.methods.some(m => m.name === method);
7647
+ };
7648
+
7649
+ const getMiniMetadata$5 = ({
7650
+ networkId,
7651
+ specVersion,
7652
+ metadataRpc
7653
+ }) => {
7654
+ const source = MODULE_TYPE$5;
7655
+ const chainId = networkId;
7656
+ const systemVersion = getConstantValue(metadataRpc, "System", "Version");
7657
+ if (specVersion !== systemVersion.spec_version) log.warn("specVersion mismatch", {
7658
+ networkId,
7659
+ specVersion,
7660
+ systemVersion
7661
+ });
7662
+ const id = deriveMiniMetadataId({
7663
+ source,
7664
+ chainId,
7665
+ specVersion
7666
+ });
7667
+ const {
7668
+ unifiedMetadata
7669
+ } = parseMetadataRpc(metadataRpc);
7670
+ if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
7671
+ return {
7672
+ id,
7673
+ source,
7674
+ chainId,
7675
+ specVersion,
7676
+ version: MINIMETADATA_VERSION,
7677
+ data: getData$3(metadataRpc),
7678
+ extra: null
7679
+ };
7680
+ };
7681
+ const getData$3 = metadataRpc => {
7682
+ const {
7683
+ metadata,
7684
+ unifiedMetadata
7685
+ } = parseMetadataRpc(metadataRpc);
7686
+
7687
+ // ensure the network has all the required bits
7688
+ if (!hasStorageItems(unifiedMetadata, "Assets", ["Account", "Asset", "Metadata"])) return null;
7689
+ compactMetadata(metadata, [{
7690
+ pallet: "Assets",
7691
+ items: ["Account", "Asset", "Metadata"]
7692
+ }]);
7693
+ return encodeMetadata(metadata);
7694
+ };
7695
+
7696
+ const getTransferCallData$5 = ({
7697
+ from,
7698
+ to,
7699
+ value,
7700
+ token,
7701
+ type,
7702
+ metadataRpc
7703
+ }) => {
7704
+ if (!isTokenOfType(token, MODULE_TYPE$5)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$5}.`);
7705
+ const {
7706
+ builder
7707
+ } = parseMetadataRpc(metadataRpc);
7708
+ const method = getTransferMethod$3(type);
7709
+ const {
7710
+ codec,
7711
+ location
7712
+ } = builder.buildCall("Assets", method);
7713
+ const args = getEncodedArgs$2(method, token.assetId, to, value, codec);
7714
+ const callData = Binary.fromBytes(mergeUint8([new Uint8Array(location), args]));
7715
+ return {
7716
+ address: from,
7717
+ method: callData.asHex()
7718
+ };
7719
+ };
7720
+ const getTransferMethod$3 = type => {
7721
+ switch (type) {
7722
+ case "keep-alive":
7723
+ return "transfer_keep_alive";
7724
+ case "all":
7725
+ return "transfer_all";
7726
+ case "allow-death":
7727
+ return "transfer";
7728
+ }
7729
+ };
7730
+ const getEncodedArgs$2 = (method, assetId, to, value, argsCodec) => {
7731
+ try {
7732
+ switch (method) {
7733
+ case "transfer_keep_alive":
7734
+ case "transfer":
7735
+ return getTransferEncodedArgs$2(assetId, to, value, argsCodec);
7736
+ case "transfer_all":
7737
+ return getTransferAllEncodedArgs$2(assetId, to, argsCodec);
7738
+ }
7739
+ } catch {
7740
+ throw new Error(`Failed to encode arguments for method ${method}: ${assetId}, ${to}, ${value}`);
7741
+ }
7742
+ };
7743
+ const getEncodedValue$2 = (codec, possibleValue) => {
7744
+ for (const getArgs of possibleValue) {
7745
+ try {
7746
+ return codec.enc(getArgs());
7747
+ } catch (error) {
7748
+ // wrong inputs, ignore and try the next one
7749
+ }
7750
+ }
7751
+ throw new Error("Failed to encode");
7752
+ };
7753
+
7754
+ // same inputs for both KeepAlive and allowDeath
7755
+ const getTransferEncodedArgs$2 = (assetId, to, value, codec) => {
7756
+ return getEncodedValue$2(codec, [() => ({
7757
+ id: Number(assetId),
7758
+ // for most networks
7759
+ target: Enum("Id", to),
7760
+ amount: BigInt(value)
7761
+ }), () => ({
7762
+ id: BigInt(assetId),
7763
+ // for Astar
7764
+ target: Enum("Id", to),
7765
+ amount: BigInt(value)
7766
+ })]);
7767
+ };
7768
+ const getTransferAllEncodedArgs$2 = (assetId, to, codec) => {
7769
+ return getEncodedValue$2(codec, [() => ({
7770
+ id: Number(assetId),
7771
+ // for most networks
7772
+ target: Enum("Id", to),
7773
+ keep_alive: false
7774
+ }), () => ({
7775
+ id: BigInt(assetId),
7776
+ // for Astar
7777
+ target: Enum("Id", to),
7778
+ keep_alive: false
7779
+ })]);
7780
+ };
7781
+
7782
+ const SUBSCRIPTION_INTERVAL$5 = 6_000;
7783
+ const subscribeBalances$5 = ({
7784
+ networkId,
7785
+ addressesByToken,
7786
+ connector,
7787
+ miniMetadata
7788
+ }) => {
7789
+ return new Observable(subscriber => {
7790
+ const abortController = new AbortController();
7791
+
7792
+ // on hydration balances are fetched using a runtimeApi, which can't be subscribed to.
7793
+ // => poll values for each block
7794
+ const poll = async () => {
7795
+ try {
7796
+ if (abortController.signal.aborted) return;
7797
+ const balances = await fetchBalances$5({
7798
+ networkId,
7799
+ addressesByToken,
7800
+ connector,
7801
+ miniMetadata
7802
+ });
7803
+ if (abortController.signal.aborted) return;
7804
+ subscriber.next(balances);
7805
+ setTimeout(poll, SUBSCRIPTION_INTERVAL$5);
7806
+ } catch (error) {
7807
+ log.error("Error", {
7808
+ module: MODULE_TYPE$5,
7809
+ networkId,
7810
+ miniMetadata,
7811
+ addressesByToken,
7812
+ error
7813
+ });
7814
+ subscriber.error(error);
7815
+ }
7816
+ };
7817
+ poll();
7818
+ return () => {
7819
+ abortController.abort();
7820
+ };
7821
+ }).pipe(distinctUntilChanged(isEqual$1));
7822
+ };
7823
+
7824
+ const SubAssetsBalanceModule = {
7825
+ type: MODULE_TYPE$5,
7826
+ platform: PLATFORM$5,
7827
+ getMiniMetadata: getMiniMetadata$5,
7828
+ fetchTokens: fetchTokens$5,
7829
+ fetchBalances: fetchBalances$5,
7830
+ subscribeBalances: subscribeBalances$5,
7831
+ getTransferCallData: getTransferCallData$5
7832
+ };
7833
+
7834
+ const MODULE_TYPE$4 = SubForeignAssetsTokenSchema.shape.type.value;
7835
+ const PLATFORM$4 = SubForeignAssetsTokenSchema.shape.platform.value;
7836
+
7837
+ // to be used by chaindata too
7838
+ z.strictObject({
7839
+ onChainId: SubForeignAssetsTokenSchema.shape.onChainId,
7840
+ ...TokenConfigBaseSchema.shape
7841
+ });
7842
+
7843
+ const fetchBalances$4 = async ({
7844
+ networkId,
7845
+ addressesByToken,
7846
+ connector,
7847
+ miniMetadata
7848
+ }) => {
7849
+ const balanceDefs = getBalanceDefs(addressesByToken);
7850
+ if (!miniMetadata?.data) {
7851
+ log.warn("MiniMetadata is required for fetching balances");
7852
+ return {
7853
+ success: [],
7854
+ errors: balanceDefs.map(def => ({
7855
+ tokenId: def.token.id,
7856
+ address: def.address,
7857
+ error: new Error("Minimetadata is required for fetching balances")
7858
+ }))
7859
+ };
7860
+ }
7861
+ if (miniMetadata.source !== MODULE_TYPE$4) {
7862
+ log.warn(`Ignoring miniMetadata with source ${miniMetadata.source} in ${MODULE_TYPE$4}.`);
7863
+ return {
7864
+ success: [],
7865
+ errors: balanceDefs.map(def => ({
7866
+ tokenId: def.token.id,
7867
+ address: def.address,
7868
+ error: new Error(`Invalid request: miniMetadata source is not ${MODULE_TYPE$4}`)
7869
+ }))
7870
+ };
7871
+ }
7872
+ if (miniMetadata.chainId !== networkId) {
7873
+ log.warn(`Ignoring miniMetadata with chainId ${miniMetadata.chainId} in ${MODULE_TYPE$4}. Expected chainId is ${networkId}`);
7874
+ return {
7875
+ success: [],
7876
+ errors: balanceDefs.map(def => ({
7877
+ tokenId: def.token.id,
7878
+ address: def.address,
7879
+ error: new Error(`Invalid request: Expected chainId is ${networkId}`)
7880
+ }))
7881
+ };
7882
+ }
7883
+ const queries = buildQueries$1(networkId, balanceDefs, miniMetadata);
7884
+ const balances = await new RpcStateQueryHelper(connector, queries).fetch();
7885
+ return balanceDefs.reduce((acc, def) => {
7886
+ const balance = balances.find(b => b?.address === def.address && b?.tokenId === def.token.id);
7887
+ if (balance) acc.success.push(balance);
7888
+ //if no entry consider empty balance
7889
+ else acc.success.push({
7890
+ address: def.address,
7891
+ networkId,
7892
+ tokenId: def.token.id,
7893
+ source: MODULE_TYPE$4,
7894
+ status: "live",
7895
+ values: [{
7896
+ type: "free",
7897
+ label: "free",
7898
+ amount: "0"
7899
+ }, {
7900
+ type: "locked",
7901
+ label: "frozen",
7902
+ amount: "0"
7903
+ }]
7904
+ });
7905
+ return acc;
7906
+ }, {
7907
+ success: [],
7908
+ errors: []
7909
+ });
7910
+ };
7911
+ const buildQueries$1 = (networkId, balanceDefs, miniMetadata) => {
7912
+ const networkStorageCoders = buildNetworkStorageCoders(networkId, miniMetadata, {
7913
+ storage: ["ForeignAssets", "Account"]
7914
+ });
7915
+ return balanceDefs.map(({
7916
+ token,
7917
+ address
7918
+ }) => {
7919
+ const scaleCoder = networkStorageCoders?.storage;
7920
+ const getStateKey = onChainId => {
7921
+ try {
7922
+ return scaleCoder?.keys?.enc?.(papiParse(onChainId), address);
7923
+ } catch {
7924
+ return null;
7925
+ }
7926
+ };
7927
+ const stateKey = getStateKey(token.onChainId);
7928
+ if (!stateKey) {
7929
+ log.warn(`Invalid assetId / address in ${networkId} storage query ${token.onChainId} / ${address}`);
7930
+ return null;
7931
+ }
7932
+ const decodeResult = change => {
7933
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
7934
+
7935
+ const decoded = decodeScale(scaleCoder, change, `Failed to decode substrate-assets balance on chain ${networkId}`) ?? {
7936
+ balance: 0n,
7937
+ is_frozen: false,
7938
+ status: {
7939
+ type: "Liquid"
7940
+ }};
7941
+ const isFrozen = decoded.is_frozen ?? decoded?.status?.type === "Frozen";
7942
+ const amount = (decoded?.balance ?? 0n).toString();
7943
+
7944
+ // due to the following balance calculations, which are made in the `Balance` type:
7945
+ //
7946
+ // total balance = (free balance) + (reserved balance)
7947
+ // transferable balance = (free balance) - (frozen balance)
7948
+ //
7949
+ // when `isFrozen` is true we need to set **both** the `free` and `frozen` amounts
7950
+ // of this balance to the value we received from the RPC.
7951
+ //
7952
+ // if we only set the `frozen` amount, then the `total` calculation will be incorrect!
7953
+ const free = amount;
7954
+ const frozen = token.isFrozen || isFrozen ? amount : "0";
7955
+
7956
+ // include balance values even if zero, so that newly-zero values overwrite old values
7957
+ const balanceValues = [{
7958
+ type: "free",
7959
+ label: "free",
7960
+ amount: free.toString()
7961
+ }, {
7962
+ type: "locked",
7963
+ label: "frozen",
7964
+ amount: frozen.toString()
7965
+ }];
7966
+ const balance = {
7967
+ source: "substrate-assets",
7968
+ status: "live",
7969
+ address,
7970
+ networkId,
7971
+ tokenId: token.id,
7972
+ values: balanceValues
7973
+ };
7974
+ return balance;
7975
+ };
7976
+ return {
7977
+ chainId: networkId,
7978
+ stateKey,
7979
+ decodeResult
7980
+ };
7981
+ }).filter(isNotNil);
7982
+ };
7983
+
7984
+ const fetchTokens$4 = async ({
7985
+ networkId,
7986
+ tokens,
7987
+ connector,
7988
+ miniMetadata
7989
+ }) => {
7990
+ const anyMiniMetadata = miniMetadata;
7991
+ if (!anyMiniMetadata?.data) return [];
7992
+ const {
7993
+ builder
7994
+ } = parseMetadataRpc(anyMiniMetadata.data);
7995
+ const assetCodec = builder.buildStorage("ForeignAssets", "Asset");
7996
+ const metadataCodec = builder.buildStorage("ForeignAssets", "Metadata");
7997
+ const [allAssetStorageKeys, allMetadataStorageKeys] = await Promise.all([connector.send(networkId, "state_getKeys", [getStorageKeyPrefix("ForeignAssets", "Asset")]), connector.send(networkId, "state_getKeys", [getStorageKeyPrefix("ForeignAssets", "Metadata")])]);
7998
+ const [assetStorageResults, metadataStorageResults] = await Promise.all([connector.send(networkId, "state_queryStorageAt", [allAssetStorageKeys]), connector.send(networkId, "state_queryStorageAt", [allMetadataStorageKeys])]);
7999
+ const assetStorageEntries = assetStorageResults[0].changes;
8000
+ const metadataStorageEntries = metadataStorageResults[0].changes;
8001
+ const assetByOnChainId = keyBy(assetStorageEntries.map(([key, value]) => {
8002
+ const [decodedKey] = assetCodec.keys.dec(key);
8003
+ const onChainId = papiStringify(decodedKey);
8004
+ const asset = assetCodec.value.dec(value);
8005
+ return {
8006
+ onChainId,
8007
+ existentialDeposit: asset.min_balance,
8008
+ isSufficient: asset.is_sufficient
8009
+ };
8010
+ }), a => a.onChainId);
8011
+ const metadataByOnChainId = keyBy(metadataStorageEntries.map(([key, value]) => {
8012
+ const [decodedKey] = metadataCodec.keys.dec(key);
8013
+ const onChainId = papiStringify(decodedKey);
8014
+ const metadata = metadataCodec.value.dec(value);
8015
+ return {
8016
+ onChainId,
8017
+ decimals: metadata.decimals,
8018
+ isFrozen: metadata.is_frozen,
8019
+ name: metadata.name?.asText(),
8020
+ symbol: metadata.symbol?.asText()
8021
+ };
8022
+ }), a => a.onChainId);
8023
+ const allTokens = keys(assetByOnChainId).map(onChainId => assign({}, assetByOnChainId[onChainId], metadataByOnChainId[onChainId] ?? undefined));
8024
+ const configTokenByOnChainId = keyBy(tokens, t => t.onChainId);
8025
+ return allTokens.map(asset => ({
8026
+ id: subForeignAssetTokenId(networkId, asset.onChainId),
8027
+ type: MODULE_TYPE$4,
8028
+ platform: "polkadot",
8029
+ networkId,
8030
+ onChainId: String(asset.onChainId),
8031
+ isSufficient: asset.isSufficient,
8032
+ isFrozen: asset.isFrozen,
8033
+ name: asset.name,
8034
+ symbol: asset.symbol,
8035
+ decimals: asset.decimals ?? 0,
8036
+ existentialDeposit: String(asset.existentialDeposit),
8037
+ isDefault: true
8038
+ }))
8039
+ // keep all tokens listed in the config + all tokens marked as sufficient
8040
+ .filter(token => {
8041
+ const configToken = configTokenByOnChainId[token.onChainId];
8042
+ return configToken || token.isSufficient;
8043
+ })
8044
+ // apply config overrides
8045
+ .map(token => {
8046
+ const configToken = configTokenByOnChainId[token.onChainId];
8047
+ return configToken ? assign({}, token, configToken) : token;
8048
+ })
8049
+ // validate results
8050
+ .filter(t => {
8051
+ const parsed = SubForeignAssetsTokenSchema.safeParse(t);
8052
+ if (!parsed.success) log.warn(`Ignoring invalid token ${MODULE_TYPE$4}`, t);
8053
+ return parsed.success;
8054
+ });
8055
+ };
8056
+
8057
+ const getMiniMetadata$4 = ({
8058
+ networkId,
8059
+ specVersion,
8060
+ metadataRpc
8061
+ }) => {
8062
+ const source = MODULE_TYPE$4;
8063
+ const chainId = networkId;
8064
+ const systemVersion = getConstantValue(metadataRpc, "System", "Version");
8065
+ if (specVersion !== systemVersion.spec_version) log.warn("specVersion mismatch", {
8066
+ networkId,
8067
+ specVersion,
8068
+ systemVersion
8069
+ });
8070
+ const id = deriveMiniMetadataId({
8071
+ source,
8072
+ chainId,
8073
+ specVersion
8074
+ });
8075
+ const {
8076
+ unifiedMetadata
8077
+ } = parseMetadataRpc(metadataRpc);
8078
+ if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
8079
+ return {
8080
+ id,
8081
+ source,
8082
+ chainId,
8083
+ specVersion,
8084
+ version: MINIMETADATA_VERSION,
8085
+ data: getData$2(metadataRpc),
8086
+ extra: null
8087
+ };
8088
+ };
8089
+ const getData$2 = metadataRpc => {
8090
+ const {
8091
+ metadata,
8092
+ unifiedMetadata
8093
+ } = parseMetadataRpc(metadataRpc);
8094
+
8095
+ // ensure the network has all the required bits
8096
+ if (!hasStorageItems(unifiedMetadata, "ForeignAssets", ["Account", "Asset", "Metadata"])) return null;
8097
+ compactMetadata(metadata, [{
8098
+ pallet: "ForeignAssets",
8099
+ items: ["Account", "Asset", "Metadata"]
8100
+ }]);
8101
+ return encodeMetadata(metadata);
8102
+ };
8103
+
8104
+ const getTransferCallData$4 = ({
8105
+ from,
8106
+ to,
8107
+ value,
8108
+ token,
8109
+ type,
8110
+ metadataRpc
8111
+ }) => {
8112
+ if (!isTokenOfType(token, MODULE_TYPE$4)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$4}.`);
8113
+ const {
8114
+ builder
8115
+ } = parseMetadataRpc(metadataRpc);
8116
+ const method = getTransferMethod$2(type);
8117
+ const {
8118
+ codec,
8119
+ location
8120
+ } = builder.buildCall("ForeignAssets", method);
8121
+ const args = getEncodedArgs$1(method, token.onChainId, to, value, codec);
8122
+ const callData = Binary.fromBytes(mergeUint8([new Uint8Array(location), args]));
8123
+ return {
8124
+ address: from,
8125
+ method: callData.asHex()
8126
+ };
8127
+ };
8128
+ const getTransferMethod$2 = type => {
8129
+ switch (type) {
8130
+ case "keep-alive":
8131
+ return "transfer_keep_alive";
8132
+ case "all":
8133
+ return "transfer_all";
8134
+ case "allow-death":
8135
+ return "transfer";
8136
+ }
8137
+ };
8138
+ const getEncodedArgs$1 = (method, onChainId, to, value, argsCodec) => {
8139
+ try {
8140
+ switch (method) {
8141
+ case "transfer_keep_alive":
8142
+ case "transfer":
8143
+ return getTransferEncodedArgs$1(onChainId, to, value, argsCodec);
8144
+ case "transfer_all":
8145
+ return getTransferAllEncodedArgs$1(onChainId, to, argsCodec);
8146
+ }
8147
+ } catch {
8148
+ throw new Error(`Failed to encode arguments for method ${method}: ${onChainId}, ${to}, ${value}`);
8149
+ }
8150
+ };
8151
+ const getEncodedValue$1 = (codec, possibleValue) => {
8152
+ for (const getArgs of possibleValue) {
8153
+ try {
8154
+ return codec.enc(getArgs());
8155
+ } catch (error) {
8156
+ // wrong inputs, ignore and try the next one
8157
+ }
8158
+ }
8159
+ throw new Error("Failed to encode");
8160
+ };
8161
+
8162
+ // same inputs for both KeepAlive and allowDeath
8163
+ const getTransferEncodedArgs$1 = (onChainId, to, value, codec) => {
8164
+ return getEncodedValue$1(codec, [() => ({
8165
+ id: papiParse(onChainId),
8166
+ // for most networks
8167
+ target: Enum("Id", to),
8168
+ amount: BigInt(value)
8169
+ })]);
8170
+ };
8171
+ const getTransferAllEncodedArgs$1 = (onChainId, to, codec) => {
8172
+ return getEncodedValue$1(codec, [() => ({
8173
+ id: papiParse(onChainId),
8174
+ // for most networks
8175
+ target: Enum("Id", to),
8176
+ keep_alive: false
8177
+ })]);
8178
+ };
8179
+
8180
+ const SUBSCRIPTION_INTERVAL$4 = 6_000;
8181
+ const subscribeBalances$4 = ({
8182
+ networkId,
8183
+ addressesByToken,
8184
+ connector,
8185
+ miniMetadata
8186
+ }) => {
8187
+ return new Observable(subscriber => {
8188
+ const abortController = new AbortController();
8189
+
8190
+ // on hydration balances are fetched using a runtimeApi, which can't be subscribed to.
8191
+ // => poll values for each block
8192
+ const poll = async () => {
8193
+ try {
8194
+ if (abortController.signal.aborted) return;
8195
+ const balances = await fetchBalances$4({
8196
+ networkId,
8197
+ addressesByToken,
8198
+ connector,
8199
+ miniMetadata
8200
+ });
8201
+ if (abortController.signal.aborted) return;
8202
+ subscriber.next(balances);
8203
+ setTimeout(poll, SUBSCRIPTION_INTERVAL$4);
8204
+ } catch (error) {
8205
+ log.error("Error", {
8206
+ module: MODULE_TYPE$4,
8207
+ networkId,
8208
+ miniMetadata,
8209
+ addressesByToken,
8210
+ error
8211
+ });
8212
+ subscriber.error(error);
8213
+ }
8214
+ };
8215
+ poll();
8216
+ return () => {
8217
+ abortController.abort();
8218
+ };
8219
+ }).pipe(distinctUntilChanged(isEqual$1));
8220
+ };
8221
+
8222
+ const SubForeignAssetsBalanceModule = {
8223
+ type: MODULE_TYPE$4,
8224
+ platform: PLATFORM$4,
8225
+ getMiniMetadata: getMiniMetadata$4,
8226
+ fetchTokens: fetchTokens$4,
8227
+ fetchBalances: fetchBalances$4,
8228
+ subscribeBalances: subscribeBalances$4,
8229
+ getTransferCallData: getTransferCallData$4
8230
+ };
8231
+
8232
+ // to be used by chaindata too
8233
+ z.strictObject({
8234
+ onChainId: SubHydrationTokenSchema.shape.onChainId,
8235
+ ...TokenConfigBaseSchema.shape
8236
+ });
8237
+
8238
+ const MODULE_TYPE$3 = SubHydrationTokenSchema.shape.type.value;
8239
+ const PLATFORM$3 = SubHydrationTokenSchema.shape.platform.value;
8240
+
8241
+ const fetchRuntimeCallResult = async (connector, networkId, metadataRpc, apiName, method, args) => {
8242
+ const {
8243
+ builder
8244
+ } = parseMetadataRpc(metadataRpc);
8245
+ const call = builder.buildRuntimeCall(apiName, method);
8246
+ const hex = await connector.send(networkId, "state_call", [`${apiName}_${method}`, toHex$1(call.args.enc(args))]);
8247
+ return call.value.dec(hex);
8248
+ };
8249
+
8250
+ const tryGetConstantValue = (metadataRpc, pallet, constant) => {
8251
+ const {
8252
+ unifiedMetadata,
8253
+ builder
8254
+ } = parseMetadataRpc(metadataRpc);
8255
+ const encodedValue = unifiedMetadata.pallets.find(({
8256
+ name
8257
+ }) => name === pallet)?.constants.find(({
8258
+ name
8259
+ }) => name === constant)?.value;
8260
+ if (!encodedValue) return null;
8261
+ const codec = builder.buildConstant(pallet, constant);
8262
+ return codec.dec(encodedValue);
8263
+ };
8264
+
8265
+ const fetchBalances$3 = async ({
8266
+ networkId,
8267
+ addressesByToken,
8268
+ connector,
8269
+ miniMetadata
8270
+ }) => {
8271
+ const balanceDefs = getBalanceDefs(addressesByToken);
8272
+ if (!miniMetadata?.data) {
8273
+ log.warn("MiniMetadata is required for fetching balances");
8274
+ return {
8275
+ success: [],
8276
+ errors: balanceDefs.map(def => ({
8277
+ tokenId: def.token.id,
8278
+ address: def.address,
8279
+ error: new Error("Minimetadata is required for fetching balances")
8280
+ }))
8281
+ };
8282
+ }
8283
+ if (miniMetadata.source !== MODULE_TYPE$3) {
8284
+ log.warn(`Ignoring miniMetadata with source ${miniMetadata.source} in ${MODULE_TYPE$3}.`);
8285
+ return {
8286
+ success: [],
8287
+ errors: balanceDefs.map(def => ({
8288
+ tokenId: def.token.id,
8289
+ address: def.address,
8290
+ error: new Error(`Invalid request: miniMetadata source is not ${MODULE_TYPE$3}`)
8291
+ }))
8292
+ };
8293
+ }
8294
+ if (miniMetadata.chainId !== networkId) {
8295
+ log.warn(`Ignoring miniMetadata with chainId ${miniMetadata.chainId} in ${MODULE_TYPE$3}. Expected chainId is ${networkId}`);
8296
+ return {
8297
+ success: [],
8298
+ errors: balanceDefs.map(def => ({
8299
+ tokenId: def.token.id,
8300
+ address: def.address,
8301
+ error: new Error(`Invalid request: Expected chainId is ${networkId}`)
8302
+ }))
8303
+ };
8304
+ }
8305
+ const addresses = uniq(balanceDefs.map(def => def.address));
8306
+ try {
8307
+ const res = await Promise.all(addresses.map(address => fetchRuntimeCallResult(connector, networkId, miniMetadata.data, "CurrenciesApi", "accounts", [address])));
8308
+ const fetchedBalances = addresses.flatMap((address, index) => {
8309
+ return res[index].map(([onChainId, balance]) => ({
8310
+ address,
8311
+ onChainId,
8312
+ free: balance.free.toString(),
8313
+ reserved: balance.reserved.toString(),
8314
+ frozen: balance.frozen.toString()
8315
+ })).filter(b => b.onChainId !== undefined);
8316
+ });
8317
+ const balancesByKey = keyBy(fetchedBalances, b => `${b.address}:${b.onChainId}`);
8318
+ const success = addressesByToken.reduce((acc, [token, addresses]) => {
8319
+ if (token.type === MODULE_TYPE$3) for (const address of addresses) {
8320
+ const rawBalance = balancesByKey[`${address}:${token.onChainId}`];
8321
+
8322
+ // the endpoint only returns entries for which the address has a non-zero balance
8323
+ // => generate an zero balance object if not found
8324
+ const balance = {
8325
+ address,
8326
+ networkId,
8327
+ tokenId: token.id,
8328
+ source: MODULE_TYPE$3,
8329
+ status: "cache",
8330
+ values: [{
8331
+ type: "free",
8332
+ label: "free",
8333
+ amount: rawBalance?.free.toString() ?? "0"
8334
+ }, {
8335
+ type: "reserved",
8336
+ label: "reserved",
8337
+ amount: rawBalance?.reserved.toString() ?? "0"
8338
+ }, {
8339
+ type: "locked",
8340
+ label: "frozen",
8341
+ amount: rawBalance?.frozen.toString() ?? "0"
8342
+ }]
8343
+ };
8344
+ acc.push(balance);
8345
+ }
8346
+ return acc;
8347
+ }, []);
8348
+ return {
8349
+ success,
8350
+ errors: []
8351
+ };
8352
+ } catch (err) {
8353
+ log.warn("Failed to fetch balances for substrate-hydration", err);
8354
+ const errors = balanceDefs.map(def => ({
8355
+ tokenId: def.token.id,
8356
+ address: def.address,
8357
+ error: new Error(`Failed to fetch balance for ${def.address} on ${networkId}`)
8358
+ }));
8359
+ return {
8360
+ success: [],
8361
+ errors
8362
+ };
8363
+ }
8364
+ };
8365
+
8366
+ const fetchTokens$3 = async ({
8367
+ networkId,
8368
+ tokens,
8369
+ connector,
8370
+ miniMetadata
8371
+ }) => {
8372
+ const anyMiniMetadata = miniMetadata;
8373
+ if (!anyMiniMetadata?.data) return [];
8374
+ const {
8375
+ builder
8376
+ } = parseMetadataRpc(anyMiniMetadata.data);
8377
+ const assetsCodec = builder.buildStorage("AssetRegistry", "Assets");
8378
+ const allAssetStorageKeys = await connector.send(networkId, "state_getKeys", [getStorageKeyPrefix("AssetRegistry", "Assets")]);
8379
+ const assetStorageResults = await connector.send(networkId, "state_queryStorageAt", [allAssetStorageKeys]);
8380
+ const assetStorageEntries = assetStorageResults[0].changes;
8381
+ const configTokenByAssetId = keyBy(tokens, t => t.onChainId);
8382
+ return assetStorageEntries.map(([key, value]) => {
8383
+ // parse results
8384
+ const [onChainId] = assetsCodec.keys.dec(key);
8385
+ const asset = assetsCodec.value.dec(value);
8386
+ return {
8387
+ onChainId,
8388
+ assetType: asset.asset_type.type,
8389
+ isSufficient: asset.is_sufficient,
8390
+ name: asset.name?.asText(),
8391
+ symbol: asset.symbol?.asText(),
8392
+ decimals: asset.decimals,
8393
+ existentialDeposit: asset.existential_deposit.toString()
8394
+ };
8395
+ })
8396
+ // exclude unsupported asset types
8397
+ .filter(({
8398
+ assetType
8399
+ }) => ["Erc20", "Token"].includes(assetType))
8400
+ // convert asset to a SubHydrationToken
8401
+ .map(asset => ({
8402
+ id: subHydrationTokenId(networkId, asset.onChainId),
8403
+ type: MODULE_TYPE$3,
8404
+ platform: "polkadot",
8405
+ networkId,
8406
+ onChainId: asset.onChainId,
8407
+ assetType: asset.assetType,
8408
+ // Erc20 or Token,
8409
+ isSufficient: asset.isSufficient,
8410
+ name: asset.name,
8411
+ symbol: asset.symbol,
8412
+ decimals: asset.decimals ?? 0,
8413
+ existentialDeposit: asset.existentialDeposit,
8414
+ isDefault: true
8415
+ }))
8416
+ // keep all tokens listed in the config + all tokens marked as sufficient
8417
+ .filter(token => {
8418
+ const configToken = configTokenByAssetId[token.onChainId];
8419
+ return configToken || token.isSufficient;
8420
+ })
8421
+ // apply config overrides
8422
+ .map(token => {
8423
+ const configToken = configTokenByAssetId[token.onChainId];
8424
+ return configToken ? assign({}, token, configToken) : token;
8425
+ })
8426
+ // validate results
8427
+ .filter(t => {
8428
+ const parsed = SubHydrationTokenSchema.safeParse(t);
8429
+ if (!parsed.success) log.warn(`Ignoring invalid token ${MODULE_TYPE$3}`, t);
8430
+ return parsed.success;
8431
+ });
8432
+ };
8433
+
8434
+ const getMiniMetadata$3 = ({
8435
+ networkId,
8436
+ specVersion,
8437
+ metadataRpc
8438
+ }) => {
8439
+ const source = MODULE_TYPE$3;
8440
+ const chainId = networkId;
8441
+ const systemVersion = getConstantValue(metadataRpc, "System", "Version");
8442
+ if (specVersion !== systemVersion.spec_version) log.warn("specVersion mismatch", {
8443
+ networkId,
8444
+ specVersion,
8445
+ systemVersion
8446
+ });
8447
+ const id = deriveMiniMetadataId({
8448
+ source,
8449
+ chainId,
8450
+ specVersion
8451
+ });
8452
+ const {
8453
+ unifiedMetadata
8454
+ } = parseMetadataRpc(metadataRpc);
8455
+ if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
8456
+ return {
8457
+ id,
8458
+ source,
8459
+ chainId,
8460
+ specVersion,
8461
+ version: MINIMETADATA_VERSION,
8462
+ data: getData$1(metadataRpc),
8463
+ extra: null
8464
+ };
8465
+ };
8466
+ const getData$1 = metadataRpc => {
8467
+ const {
8468
+ metadata,
8469
+ unifiedMetadata
8470
+ } = parseMetadataRpc(metadataRpc);
8471
+
8472
+ // ensure the network has all the required bits
8473
+ if (!hasStorageItem(unifiedMetadata, "AssetRegistry", "Assets") || !hasStorageItem(unifiedMetadata, "Tokens", "Accounts") || !hasRuntimeApi(unifiedMetadata, "CurrenciesApi", "accounts")) return null;
8474
+ compactMetadata(metadata, [{
8475
+ pallet: "AssetRegistry",
8476
+ items: ["Assets"]
8477
+ },
8478
+ // token specs
8479
+ {
8480
+ pallet: "Tokens",
8481
+ items: ["Accounts"]
8482
+ } // balances for tokens
8483
+ ], [{
8484
+ runtimeApi: "CurrenciesApi",
8485
+ methods: ["accounts"]
8486
+ }]);
8487
+ return encodeMetadata(metadata);
8488
+ };
8489
+
8490
+ const getTransferCallData$3 = ({
8491
+ from,
8492
+ to,
8493
+ value,
8494
+ token,
8495
+ metadataRpc
8496
+ }) => {
8497
+ if (!isTokenOfType(token, MODULE_TYPE$3)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$3}.`);
8498
+
8499
+ // there is only one transfer method, no existential deposit handling.
8500
+ // => leave this to the frontend and dry runs
8501
+ const {
8502
+ builder
8503
+ } = parseMetadataRpc(metadataRpc);
8504
+ const {
8505
+ codec,
8506
+ location
8507
+ } = builder.buildCall("Currencies", "transfer");
8508
+ const args = {
8509
+ dest: to,
8510
+ currency_id: token.onChainId,
8511
+ amount: BigInt(value)
8512
+ };
8513
+ const callData = Binary.fromBytes(mergeUint8([new Uint8Array(location), codec.enc(args)]));
8514
+ return {
8515
+ address: from,
8516
+ method: callData.asHex()
8517
+ };
8518
+ };
8519
+
8520
+ const SUBSCRIPTION_INTERVAL$3 = 6_000;
8521
+ const subscribeBalances$3 = ({
8522
+ networkId,
8523
+ addressesByToken,
8524
+ connector,
8525
+ miniMetadata
8526
+ }) => {
8527
+ return new Observable(subscriber => {
8528
+ const abortController = new AbortController();
8529
+
8530
+ // on hydration balances are fetched using a runtimeApi, which can't be subscribed to.
8531
+ // => poll values for each block
8532
+ const poll = async () => {
8533
+ try {
8534
+ if (abortController.signal.aborted) return;
8535
+ const balances = await fetchBalances$3({
8536
+ networkId,
8537
+ addressesByToken,
8538
+ connector,
8539
+ miniMetadata
8540
+ });
8541
+ if (abortController.signal.aborted) return;
8542
+ subscriber.next(balances);
8543
+ setTimeout(poll, SUBSCRIPTION_INTERVAL$3);
8544
+ } catch (error) {
8545
+ log.error("Error", {
8546
+ module: MODULE_TYPE$3,
8547
+ networkId,
8548
+ miniMetadata,
8549
+ addressesByToken,
8550
+ error
8551
+ });
8552
+ subscriber.error(error);
8553
+ }
8554
+ };
8555
+ poll();
8556
+ return () => {
8557
+ abortController.abort();
8558
+ };
8559
+ }).pipe(distinctUntilChanged(isEqual$1));
8560
+ };
8561
+
8562
+ const SubHydrationBalanceModule = {
8563
+ type: MODULE_TYPE$3,
8564
+ platform: PLATFORM$3,
8565
+ getMiniMetadata: getMiniMetadata$3,
8566
+ fetchTokens: fetchTokens$3,
8567
+ fetchBalances: fetchBalances$3,
8568
+ subscribeBalances: subscribeBalances$3,
8569
+ getTransferCallData: getTransferCallData$3
8570
+ };
8571
+
8572
+ const MODULE_TYPE$2 = SubNativeTokenSchema.shape.type.value;
8573
+ const PLATFORM$2 = SubNativeTokenSchema.shape.platform.value;
8574
+
8575
+ // to be used by chaindata too
8576
+ z.strictObject({
8577
+ ...TokenConfigBaseSchema.shape
8578
+ });
8579
+
8580
+ // Do not use this type outside of this module
8581
+
8582
+ // Do not use this type outside of this module
8583
+
8584
+ // Do not use this type outside of this module
8585
+
8586
+ /**
8587
+ * Pass some these into an `RpcStateQueryHelper` in order to easily batch multiple state queries into the one rpc call.
8588
+ */
8589
+
8590
+ const fetchQueriesPack = async (connector, networkId, queries) => {
8591
+ const allStateKeys = queries.flatMap(({
8592
+ stateKeys
8593
+ }) => stateKeys).filter(isNotNil);
8594
+
8595
+ // doing a query with only null keys would throw an error => return early
8596
+ if (!allStateKeys.length) return queries.map(({
8597
+ stateKeys,
8598
+ decodeResult
8599
+ }) => decodeResult(stateKeys.map(() => null)));
8600
+ const response = await connector.send(networkId, "state_queryStorageAt", [allStateKeys]);
8601
+ const results = queries.reduce((acc, {
8602
+ stateKeys,
8603
+ decodeResult
8604
+ }) => {
8605
+ const changes = stateKeys.map(stateKey => {
8606
+ if (!stateKey) return null;
8607
+ const change = response[0].changes.find(([key]) => key === stateKey);
8608
+ if (!change) return null;
8609
+ return change[1];
8610
+ });
8611
+ acc.push(decodeResult(changes));
8612
+ return acc;
8613
+ }, []);
8614
+ return results;
8615
+ };
8616
+
8617
+ /**
8618
+ * Used by a variety of balance modules to help batch multiple state queries into the one rpc call.
8619
+ */
8620
+ // export class RpcStateQueriesHelper<T> {
8621
+ // #connector: ChainConnector
8622
+ // #queries: Array<RpcStateQueries<T>>
8623
+
8624
+ // constructor(connector: ChainConnector, queries: Array<RpcStateQueries<T>>) {
8625
+ // this.#connector = connector
8626
+ // this.#queries = queries
8627
+ // }
8628
+
8629
+ // async subscribe(
8630
+ // networkId: DotNetworkId,
8631
+ // callback: SubscriptionCallback<T[]>,
8632
+ // timeout: number | false = false,
8633
+ // subscribeMethod = "state_subscribeStorage",
8634
+ // responseMethod = "state_storage",
8635
+ // unsubscribeMethod = "state_unsubscribeStorage",
8636
+ // ): Promise<UnsubscribeFn> {
8637
+ // const params = [this.#queries.flatMap(({ stateKeys }) => stateKeys)]
8638
+
8639
+ // const unsub = this.#connector.subscribe(
8640
+ // networkId,
8641
+ // subscribeMethod,
8642
+ // responseMethod,
8643
+ // params,
8644
+ // (error, result) => {
8645
+ // error
8646
+ // ? callback(error)
8647
+ // : callback(null, this.#distributeChangesToQueryDecoders.call(this, chainId, result))
8648
+ // },
8649
+ // timeout,
8650
+ // )
8651
+
8652
+ // const subscriptions = queries.map(([chainId, queries]) => {
8653
+ // const params = [queries.map(({ stateKey }) => stateKey)]
8654
+
8655
+ // const unsub = this.#connector.subscribe(
8656
+ // networkId,
8657
+ // subscribeMethod,
8658
+ // responseMethod,
8659
+ // params,
8660
+ // (error, result) => {
8661
+ // error
8662
+ // ? callback(error)
8663
+ // : callback(null, this.#distributeChangesToQueryDecoders.call(this, chainId, result))
8664
+ // },
8665
+ // timeout,
8666
+ // )
8667
+
8668
+ // return () => unsub.then((unsubscribe) => unsubscribe(unsubscribeMethod))
8669
+ // })
8670
+
8671
+ // return () => subscriptions.forEach((unsubscribe) => unsubscribe())
8672
+ // }
8673
+
8674
+ // async fetch(method = "state_queryStorageAt"): Promise<T[]> {
8675
+ // const queriesByChain = groupBy(this.#queries, "chainId")
8676
+
8677
+ // const resultsByChain = await Promise.all(
8678
+ // Object.entries(queriesByChain).map(async ([chainId, queries]) => {
8679
+ // const params = [queries.map(({ stateKey }) => stateKey)]
8680
+
8681
+ // const result = (await this.#connector.send(chainId, method, params))[0]
8682
+ // return this.#distributeChangesToQueryDecoders.call(this, chainId, result)
8683
+ // }),
8684
+ // )
8685
+
8686
+ // return resultsByChain.flatMap((result) => result)
8687
+ // }
8688
+
8689
+ // #distributeChangesToQueryDecoders(chainId: DotNetworkId, result: unknown): T[] {
8690
+ // if (typeof result !== "object" || result === null) return []
8691
+ // if (!hasOwnProperty(result, "changes") || typeof result.changes !== "object") return []
8692
+ // if (!Array.isArray(result.changes)) return []
8693
+
8694
+ // return result.changes.flatMap(([reference, change]: [unknown, unknown]): [T] | [] => {
8695
+ // if (typeof reference !== "string") {
8696
+ // log.warn(`Received non-string reference in RPC result: ${reference}`)
8697
+ // return []
8698
+ // }
8699
+
8700
+ // if (typeof change !== "string" && change !== null) {
8701
+ // log.warn(`Received non-string and non-null change in RPC result: ${reference} | ${change}`)
8702
+ // return []
8703
+ // }
8704
+
8705
+ // const query = this.#queries.find(
8706
+ // ({ chainId: cId, stateKey }) => cId === chainId && stateKey === reference,
8707
+ // )
8708
+ // if (!query) {
8709
+ // log.warn(
8710
+ // `Failed to find query:\n${reference} in\n${this.#queries.map(({ stateKey }) => stateKey)}`,
8711
+ // )
8712
+ // return []
8713
+ // }
8714
+
8715
+ // return [query.decodeResult(change)]
8716
+ // })
8717
+ // }
8718
+ // }
8719
+
8720
+ const SUBTENSOR_ROOT_NETUID = 0;
8721
+ const SUBTENSOR_MIN_STAKE_AMOUNT_PLANK = 1000000n;
8722
+ const TAO_DECIMALS = 9n;
8723
+ const SCALE_FACTOR = 10n ** TAO_DECIMALS; // Equivalent to 10e9 for precision
8724
+ const ONE_ALPHA_TOKEN = SCALE_FACTOR;
8725
+ const calculateAlphaPrice = ({
8726
+ dynamicInfo
8727
+ }) => {
8728
+ if (!dynamicInfo) return 0n;
8729
+ const {
8730
+ alpha_in,
8731
+ tao_in
8732
+ } = dynamicInfo;
8733
+
8734
+ // Scale taoIn before division to preserve precision
8735
+ const result = tao_in * SCALE_FACTOR / alpha_in;
8736
+ return result; // Scaled price as bigint
8737
+ };
8738
+ const calculateTaoAmountFromAlpha = ({
8739
+ alphaPrice,
8740
+ alphaStaked
8741
+ }) => {
8742
+ if (!alphaStaked || !alphaPrice) return 0n;
8743
+ const expectedAlpha = alphaStaked * alphaPrice;
8744
+ return expectedAlpha / SCALE_FACTOR;
8745
+ };
8746
+ const calculateTaoFromDynamicInfo = ({
8747
+ dynamicInfo,
8748
+ alphaStaked
8749
+ }) => {
8750
+ const alphaPrice = calculateAlphaPrice({
8751
+ dynamicInfo
8752
+ });
8753
+ return calculateTaoAmountFromAlpha({
8754
+ alphaPrice,
8755
+ alphaStaked
8756
+ });
8757
+ };
8758
+
8759
+ // per address, lists of values to add to the native balance
8760
+
8761
+ const getSubtensorStakingBalances$ = (connector, networkId, balanceDefs, miniMetadata) => {
8762
+ const addresses = balanceDefs.map(def => def.address);
8763
+ const token = balanceDefs[0].token;
8764
+ if (!addresses.length || !token || !miniMetadata.extra.hasSubtensorPallet || !miniMetadata.data) return of({});
8765
+
8766
+ // we are only doing runtime calls, there is no way to subscribe to changes, except polling
8767
+ // => start immediately, then repeat every 30 seconds
8768
+ return timer(0, 30000).pipe(switchMap(() => from(fetchStakeInfoByAddress(connector, networkId, miniMetadata, addresses)).pipe(switchMap(stakeInfoByAddress => fetchStakingBalanceValuesByAddress(connector, networkId, miniMetadata, stakeInfoByAddress)))));
8769
+ };
8770
+ const fetchStakingBalanceValuesByAddress = async (connector, networkId, miniMetadata, stakeInfoByAddress) => {
8771
+ const uniqueNetuids = uniq(values(stakeInfoByAddress).flatMap(infos => infos.map(info => info.netuid))).filter(netuid => netuid !== SUBTENSOR_ROOT_NETUID);
8772
+ const dynamicInfoByNetuid = await fetchDynamicInfoByNetuid(connector, networkId, miniMetadata, uniqueNetuids);
8773
+ return fromPairs(toPairs(stakeInfoByAddress).map(([address, stakeInfos]) => {
8774
+ const stakesBalances = stakeInfos.filter(({
8775
+ stake
8776
+ }) => stake >= SUBTENSOR_MIN_STAKE_AMOUNT_PLANK).map(({
8777
+ hotkey,
8778
+ netuid,
8779
+ stake
8780
+ }) => ({
8781
+ hotkey,
8782
+ netuid: Number(netuid),
8783
+ stake: BigInt(stake),
8784
+ dynamicInfo: dynamicInfoByNetuid[Number(netuid)]
8785
+ })).map(({
8786
+ hotkey,
8787
+ stake,
8788
+ netuid,
8789
+ dynamicInfo
8790
+ }) => {
8791
+ const {
8792
+ token_symbol,
8793
+ subnet_name,
8794
+ subnet_identity
8795
+ } = dynamicInfo ?? {};
8796
+ const tokenSymbol = new TextDecoder().decode(Uint8Array.from(token_symbol ?? []));
8797
+ const subnetName = new TextDecoder().decode(Uint8Array.from(subnet_name ?? []));
8798
+ const subnetIdentity = subnet_identity ? fromPairs(toPairs(subnet_identity).map(([key, binary]) => [key, binary.asText()])) : undefined;
8799
+
8800
+ // Add 1n balance if failed to fetch dynamic info, so the position is not ignored by Balance lib and is displayed in the UI.
8801
+ const alphaStakedInTao = dynamicInfo ? calculateTaoFromDynamicInfo({
8802
+ dynamicInfo,
8803
+ alphaStaked: stake
8804
+ }) : 1n;
8805
+ const alphaToTaoRate = calculateTaoFromDynamicInfo({
8806
+ dynamicInfo: dynamicInfo ?? null,
8807
+ alphaStaked: ONE_ALPHA_TOKEN
8808
+ }).toString();
8809
+ const stakeByNetuid = Number(netuid) === SUBTENSOR_ROOT_NETUID ? stake : alphaStakedInTao;
8810
+ const balanceValue = {
8811
+ source: "subtensor-staking",
8812
+ type: "subtensor",
8813
+ label: "subtensor-staking",
8814
+ amount: stakeByNetuid.toString(),
8815
+ meta: {
8816
+ type: "subtensor-staking",
8817
+ hotkey,
8818
+ netuid,
8819
+ amountStaked: stake.toString(),
8820
+ alphaToTaoRate,
8821
+ dynamicInfo: {
8822
+ tokenSymbol,
8823
+ subnetName,
8824
+ subnetIdentity: {
8825
+ ...subnetIdentity,
8826
+ subnetName: subnetIdentity?.subnet_name || subnetName
8827
+ }
8828
+ }
8829
+ }
8830
+ };
8831
+ return balanceValue;
8832
+ });
8833
+ return [address, stakesBalances];
8834
+ }));
8835
+ };
8836
+ const fetchStakeInfoByAddress = async (connector, networkId, miniMetadata, addresses) => {
8837
+ const pairs = await Promise.all(addresses.map(async address => [address, await withRetry(() => fetchRuntimeCallResult(connector, networkId, miniMetadata.data, "StakeInfoRuntimeApi", "get_stake_info_for_coldkey", [address]), {
8838
+ delay: 500,
8839
+ retryCount: 3
8840
+ })]));
8841
+ return fromPairs(pairs);
8842
+ };
8843
+
8844
+ // assume dynamic info doesnt change over the course of a browser session
8845
+ const dynamicInfoCache = new Map();
8846
+ const getCacheKey = (networkId, netuid) => `${networkId}:${netuid}`;
8847
+ const fetchDynamicInfoByNetuid = async (connector, networkId, miniMetadata, uniqueNetuids) => {
8848
+ const fetchInfo = async netuid => {
8849
+ if (netuid === SUBTENSOR_ROOT_NETUID) return null;
8850
+ const cacheKey = getCacheKey(networkId, netuid);
8851
+ if (!dynamicInfoCache.has(cacheKey)) {
8852
+ await withRetry(async () => {
8853
+ const result = await fetchRuntimeCallResult(connector, networkId, miniMetadata.data, "SubnetInfoRuntimeApi", "get_dynamic_info", [netuid]);
8854
+ dynamicInfoCache.set(cacheKey, result); // Cache successful response
8855
+
8856
+ return result;
8857
+ }, {
8858
+ delay: 500,
8859
+ retryCount: 3
8860
+ });
8861
+ }
8862
+ return dynamicInfoCache.get(cacheKey) ?? null;
8863
+ };
8864
+ const results = await Promise.all(uniqueNetuids.map(async netuid => [netuid, await fetchInfo(netuid)]));
8865
+ return fromPairs(results);
8866
+ };
8867
+
8868
+ const getOtherType = input => `other-${input}`;
8869
+
8870
+ /**
8871
+ * For converting the value of `lock?.id?.toUtf8?.()` which is retrieved from
8872
+ * the Balances.Locks storage key into a useful classification for our UI
8873
+ */
8874
+ const getLockedType = input => {
8875
+ if (typeof input !== "string") return getOtherType("unknown");
8876
+ if (input.includes("vesting")) return "vesting";
8877
+ if (input.includes("calamvst")) return "vesting"; // vesting on manta network
8878
+ if (input.includes("ormlvest")) return "vesting"; // vesting ORML tokens
8879
+ if (input.includes("pyconvot")) return "democracy";
8880
+ if (input.includes("democrac")) return "democracy";
8881
+ if (input.includes("democracy")) return "democracy";
8882
+ if (input.includes("phrelect")) return "democracy"; // specific to council
8883
+ if (input.includes("staking")) return "staking";
8884
+ if (input.includes("stkngdel")) return "staking"; // staking delegator
8885
+ if (input.includes("stkngcol")) return "staking"; // staking collator
8886
+ if (input.includes("kiltpstk")) return "staking"; // Kilt specific staking
8887
+ if (input.includes("dapstake")) return "dapp-staking"; // Astar specific
8888
+ if (input.includes("appstake")) return "dapp-staking"; // Quartz (unique) specific
8889
+ if (input.includes("dappstaking")) return "dapp-staking";
8890
+
8891
+ // Joystream specifics https://github.com/Joystream/pioneer/blob/dev/packages/ui/src/accounts/model/lockTypes.ts
8892
+ if (input.includes("voting")) return "democracy";
8893
+ if (input.includes("candidac")) return "democracy"; // Council Candidate
8894
+ if (input.includes("councilo")) return "democracy"; // Councilor
8895
+ if (input.includes("proposal")) return "democracy";
8896
+ if (input.includes("boundsta")) return "staking"; // Bound Staking Account
8897
+ if (input.includes("invitemb")) return getOtherType(input); // Invite member
8898
+ if (input.includes("bounty")) return getOtherType(input);
8899
+ if (input.startsWith("wg-")) return getOtherType(input);
8900
+
8901
+ // ignore technical or undocumented lock types
8902
+ if (input.includes("pdexlock")) return getOtherType(input);
8903
+ if (input.includes("phala/sp")) return getOtherType(input);
8904
+ if (input.includes("aca/earn")) return getOtherType(input);
8905
+ if (input.includes("stk_stks")) return getOtherType(input);
8906
+
8907
+ // eslint-disable-next-line no-console
8908
+ console.warn(`unknown locked type: ${input}`);
8909
+ return getOtherType(input);
8910
+ };
8911
+
8912
+ const buildBaseQueries = (networkId, balanceDefs, miniMetadata) => {
8913
+ const networkStorageCoders = buildNetworkStorageCoders(networkId, miniMetadata, {
8914
+ account: ["System", "Account"],
8915
+ stakingLedger: ["Staking", "Ledger"],
8916
+ reserves: ["Balances", "Reserves"],
8917
+ // unused ??
8918
+ holds: ["Balances", "Holds"],
8919
+ locks: ["Balances", "Locks"],
8920
+ freezes: ["Balances", "Freezes"],
8921
+ poolMembers: ["NominationPools", "PoolMembers"]
8922
+ });
8923
+ if (!networkStorageCoders) throw new Error(`No network storage coders found for networkId: ${networkId}`);
8924
+ return balanceDefs.map(({
8925
+ token,
8926
+ address
8927
+ }) => {
8928
+ const accountStateKey = networkStorageCoders.account ? networkStorageCoders.account.keys.enc(address) : null;
8929
+ const locksStateKey = networkStorageCoders.locks ? networkStorageCoders.locks.keys.enc(address) : null;
8930
+ const freezesStateKey = networkStorageCoders.freezes ? networkStorageCoders.freezes.keys.enc(address) : null;
8931
+ const holdsStateKey = networkStorageCoders.holds ? networkStorageCoders.holds.keys.enc(address) : null;
8932
+ const stakingLedgerStateKey = networkStorageCoders.stakingLedger ? networkStorageCoders.stakingLedger.keys.enc(address) : null;
8933
+ const poolMemberStateKey = networkStorageCoders.poolMembers ? networkStorageCoders.poolMembers.keys.enc(address) : null;
8934
+ const stateKeys = [accountStateKey, locksStateKey, freezesStateKey, holdsStateKey, stakingLedgerStateKey, poolMemberStateKey];
8935
+ return {
8936
+ stateKeys,
8937
+ decodeResult: changes => {
8938
+ const balance = {
8939
+ source: "substrate-native",
8940
+ status: "live",
8941
+ address,
8942
+ networkId,
8943
+ tokenId: token.id,
8944
+ values: [],
8945
+ useLegacyTransferableCalculation: miniMetadata.extra.useLegacyTransferableCalculation
8946
+ };
8947
+ let nomPoolMemberInfo = null;
8948
+ const [accountChange, lockChange, freezesChange, holdsChange, stakingLedgerChange, nomPoolMemberChange] = changes;
8949
+ if (networkStorageCoders.account) {
8950
+ // for account balance we decode even empty values
8951
+ const baseValues = decodeBaseResult(networkStorageCoders.account, accountChange, networkId);
8952
+ balance.values.push(...baseValues);
8953
+ }
8954
+ if (networkStorageCoders.locks && lockChange) {
8955
+ const lockValues = decodeLocksResult(networkStorageCoders.locks, lockChange, networkId);
8956
+ balance.values.push(...lockValues);
8957
+ }
8958
+ if (networkStorageCoders.freezes && freezesChange) {
8959
+ const freezesValues = decodeFreezesResult(networkStorageCoders.freezes, freezesChange, networkId);
8960
+ balance.values.push(...freezesValues);
8961
+ }
8962
+ if (networkStorageCoders.holds && holdsChange) {
8963
+ const holdsValues = decodeHoldsResult(networkStorageCoders.holds, holdsChange, networkId);
8964
+ balance.values.push(...holdsValues);
8965
+ }
8966
+ if (networkStorageCoders.stakingLedger && stakingLedgerChange) {
8967
+ const stakingLedgerValues = decodeStakingLedgerResult(networkStorageCoders.stakingLedger, stakingLedgerChange, networkId);
8968
+ balance.values.push(...stakingLedgerValues);
8969
+ }
8970
+ if (networkStorageCoders.poolMembers && nomPoolMemberChange) {
8971
+ const nomPoolMemberValue = decodePoolMemberResult(networkStorageCoders.poolMembers, nomPoolMemberChange, networkId);
8972
+ if (nomPoolMemberValue) nomPoolMemberInfo = nomPoolMemberValue;
8973
+ }
8974
+ return {
8975
+ balance,
8976
+ nomPoolMemberInfo
8977
+ };
8978
+ }
8979
+ };
8980
+ }).filter(isNotNil);
8981
+ };
8982
+
8983
+ // AccountInfo is the state_storage data format for nativeToken balances
8984
+ // Theory: new chains will be at least on metadata v14, and so we won't need to hardcode their AccountInfo type.
8985
+ // But for chains we want to support which aren't on metadata v14, hardcode them here:
8986
+ // If the chain upgrades to metadata v14, this override will be ignored :)
8987
+ // const RegularAccountInfoFallback = Struct({
8988
+ // nonce: u32,
8989
+ // consumers: u32,
8990
+ // providers: u32,
8991
+ // sufficients: u32,
8992
+ // data: Struct({ free: u128, reserved: u128, miscFrozen: u128, feeFrozen: u128 }),
8993
+ // })
8994
+ // const NoSufficientsAccountInfoFallback = Struct({
8995
+ // nonce: u32,
8996
+ // consumers: u32,
8997
+ // providers: u32,
8998
+ // data: Struct({ free: u128, reserved: u128, miscFrozen: u128, feeFrozen: u128 }),
8999
+ // })
9000
+ // const AccountInfoOverrides: Record<
9001
+ // string,
9002
+ // typeof RegularAccountInfoFallback | typeof NoSufficientsAccountInfoFallback | undefined
9003
+ // > = {
9004
+ // // crown-sterlin is not yet on metadata v14
9005
+ // "crown-sterling": NoSufficientsAccountInfoFallback,
9006
+
9007
+ // // crust is not yet on metadata v14
9008
+ // "crust": NoSufficientsAccountInfoFallback,
9009
+
9010
+ // // kulupu is not yet on metadata v14
9011
+ // "kulupu": RegularAccountInfoFallback,
9012
+
9013
+ // // nftmart is not yet on metadata v14
9014
+ // "nftmart": RegularAccountInfoFallback,
9015
+ // }
9016
+
9017
+ const decodeBaseResult = (coder, value, networkId) => {
9018
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9019
+
9020
+ const decoded = decodeScale(coder, value, `Failed to decode base native balance on chain ${networkId}`);
9021
+ const free = (decoded?.data?.free ?? 0n).toString();
9022
+ const reserved = (decoded?.data?.reserved ?? 0n).toString();
9023
+ const miscLock = ((decoded?.data?.miscFrozen ?? 0n) + (
9024
+ // new chains don't split their `frozen` amount into `feeFrozen` and `miscFrozen`.
9025
+ // for these chains, we'll use the `frozen` amount as `miscFrozen`.
9026
+ decoded?.data?.frozen ?? 0n)).toString();
9027
+ const feesLock = (decoded?.data?.feeFrozen ?? 0n).toString();
9028
+
9029
+ // even if these values are 0, we still need to add them to the balanceJson.values array
9030
+ // so that the balance pool can handle newly zeroed balances
9031
+ // const existingValues = Object.fromEntries(
9032
+ // balanceJson.values.map((v) => [getValueId(v), v]),
9033
+ // )
9034
+ const newValues = [{
9035
+ type: "free",
9036
+ label: "free",
9037
+ amount: free.toString()
9038
+ }, {
9039
+ type: "reserved",
9040
+ label: "reserved",
9041
+ amount: reserved.toString()
9042
+ }, {
9043
+ type: "locked",
9044
+ label: "misc",
9045
+ amount: miscLock.toString()
9046
+ }, {
9047
+ type: "locked",
9048
+ label: "fees",
9049
+ amount: feesLock.toString()
9050
+ }];
9051
+ return newValues;
9052
+ };
9053
+ const decodeLocksResult = (coder, value, networkId) => {
9054
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9055
+
9056
+ const decoded = decodeScale(coder, value, `Failed to decode lock on chain ${networkId}`);
9057
+ const locksQueryLocks = decoded?.map?.(lock => ({
9058
+ type: "locked",
9059
+ source: "substrate-native-locks",
9060
+ label: getLockedType(lock?.id?.asText?.()),
9061
+ meta: {
9062
+ id: lock?.id?.asText?.()
9063
+ },
9064
+ amount: (lock?.amount ?? 0n).toString()
9065
+ })) ?? [];
9066
+ return locksQueryLocks;
9067
+
9068
+ // // locked values should be replaced entirely, not merged or appended
9069
+ // const nonLockValues = balanceJson.values.filter(
9070
+ // (v) => v.source !== "substrate-native-locks",
9071
+ // )
9072
+ // balanceJson.values = nonLockValues.concat(locksQueryLocks)
9073
+
9074
+ // // fix any double-counting between Balances.Locks (for staking locks) and Staking.Ledger (for unbonding locks)
9075
+ // balanceJson.values = updateStakingLocksUsingUnbondingLocks(balanceJson.values)
9076
+ };
9077
+ const decodeFreezesResult = (coder, value, networkId) => {
9078
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9079
+
9080
+ const decoded = decodeScale(coder, value, `Failed to decode freeze on chain ${networkId}`);
9081
+ const freezesValues = decoded?.map?.(lock => ({
9082
+ type: "locked",
9083
+ source: "substrate-native-freezes",
9084
+ label: getLockedType(lock?.id?.type?.toLowerCase?.()),
9085
+ amount: lock?.amount?.toString?.() ?? "0"
9086
+ })) ?? [];
9087
+ return freezesValues;
9088
+
9089
+ // // freezes values should be replaced entirely, not merged or appended
9090
+ // const nonFreezesValues = balanceJson.values.filter(
9091
+ // (v) => v.source !== "substrate-native-freezes",
9092
+ // )
9093
+ // balanceJson.values = nonFreezesValues.concat(freezesQueryLocks)
9094
+
9095
+ // return balanceJson
9096
+ };
9097
+ const decodeHoldsResult = (coder, value, networkId) => {
9098
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9099
+
9100
+ const decoded = decodeScale(coder, value, `Failed to decode holds on chain ${networkId}`);
9101
+
9102
+ // at this time we re only interested in DelegatedStaking holds, to determine if nom pool staked amount is included in reserved or not
9103
+ const holdsValues = decoded?.filter(hold => hold.id?.type).map(hold => ({
9104
+ type: "locked",
9105
+ source: "substrate-native-holds",
9106
+ label: hold.id.type,
9107
+ // anount needs to be 0 or a row could appear in the UI, this entry is just for information
9108
+ amount: "0",
9109
+ meta: {
9110
+ amount: (hold?.amount ?? 0n).toString()
9111
+ }
9112
+ })) ?? [];
9113
+ return holdsValues;
9114
+
9115
+ // // values should be replaced entirely, not merged or appended
9116
+ // const nonHoldsValues = balanceJson.values.filter(
9117
+ // (v) => v.source !== "substrate-native-holds",
9118
+ // )
9119
+ // balanceJson.values = nonHoldsValues.concat(holdsQueryLocks)
9120
+
9121
+ // return balanceJson
9122
+ };
9123
+ const decodeStakingLedgerResult = (coder, value, networkId) => {
9124
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9125
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9126
+
9127
+ const decoded = decodeScale(coder, value, `Failed to decode unbonding query on chain ${networkId}`);
9128
+ const totalUnlocking = decoded?.unlocking?.reduce?.((acc, unlocking) => acc + unlocking.value, 0n) ?? 0n;
9129
+ const stakingLedgerResults = totalUnlocking <= 0n ? [] : [{
9130
+ type: "locked",
9131
+ source: "substrate-native-unbonding",
9132
+ label: "Unbonding",
9133
+ amount: totalUnlocking.toString()
9134
+ }];
9135
+ return stakingLedgerResults;
9136
+
9137
+ // if (totalUnlocking <= 0n) unbondingQueryLocks = []
9138
+ // else {
9139
+ // unbondingQueryLocks = [
9140
+ // {
9141
+ // type: "locked",
9142
+ // source: "substrate-native-unbonding",
9143
+ // label: "Unbonding",
9144
+ // amount: totalUnlocking.toString(),
9145
+ // },
9146
+ // ]
9147
+ // }
9148
+
9149
+ // // unbonding values should be replaced entirely, not merged or appended
9150
+ // const nonUnbondingValues = balanceJson.values.filter(
9151
+ // (v) => v.source !== "substrate-native-unbonding",
9152
+ // )
9153
+ // balanceJson.values = nonUnbondingValues.concat(unbondingQueryLocks)
9154
+
9155
+ // // fix any double-counting between Balances.Locks (for staking locks) and Staking.Ledger (for unbonding locks)
9156
+ // balanceJson.values = updateStakingLocksUsingUnbondingLocks(balanceJson.values)
9157
+
9158
+ // return balanceJson
9159
+ };
9160
+ const decodePoolMemberResult = (coder, value, networkId) => {
9161
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9162
+
9163
+ const decoded = decodeScale(coder, value, `Failed to decode poolMembers on chain ${networkId}`);
9164
+ if (!decoded) return null;
9165
+ const poolId = decoded.pool_id.toString();
9166
+ const points = decoded.points.toString();
9167
+ const unbondingEras = Array.from(decoded.unbonding_eras ?? []).flatMap(entry => {
9168
+ if (entry === undefined) return [];
9169
+ const [key, value] = Array.from(entry);
9170
+ const era = key.toString();
9171
+ const amount = value.toString();
9172
+ if (typeof era !== "string" || typeof amount !== "string") return [];
9173
+ return {
9174
+ era,
9175
+ amount
9176
+ };
9177
+ });
9178
+ return {
9179
+ poolId,
9180
+ points,
9181
+ unbondingEras
9182
+ };
9183
+ };
9184
+
9185
+ // const getBaseQuery = (
9186
+ // networkId: string,
9187
+ // address: string,
9188
+ // coder: ScaleStorageCoder,
9189
+ // ): RpcStateQuery<Array<AmountWithLabel<string>>> | null => {
9190
+ // // For chains which are using metadata < v14
9191
+ // const getFallbackStateKey = () => {
9192
+ // const addressBytes = decodeAnyAddress(address) // TODO replace with modern api, this is slow
9193
+ // const addressHash = blake2Concat(addressBytes).replace(/^0x/, "")
9194
+ // const moduleHash = "26aa394eea5630e07c48ae0c9558cef7" // util_crypto.xxhashAsHex("System", 128);
9195
+ // const storageHash = "b99d880ec681799c0cf30e8886371da9" // util_crypto.xxhashAsHex("Account", 128);
9196
+ // const moduleStorageHash = `${moduleHash}${storageHash}` // System.Account is the state_storage key prefix for nativeToken balances
9197
+ // return `0x${moduleStorageHash}${addressHash}`
9198
+ // }
9199
+
9200
+ // // const scaleCoder = chainStorageCoders.get(chainId)?.base
9201
+ // // NOTE: Only use fallback key when `scaleCoder` is not defined
9202
+ // // i.e. when chain doesn't have metadata v14/v15
9203
+ // const stateKey = coder
9204
+ // ? encodeStateKey(coder, `Invalid address in ${networkId} base query ${address}`, address)
9205
+ // : getFallbackStateKey()
9206
+ // if (!stateKey) return null
9207
+
9208
+ // const decodeResult = (change: string | null) => {
9209
+ // // BEGIN: Handle chains which use metadata < v14
9210
+ // let oldChainBalance = null
9211
+ // if (!coder) {
9212
+ // const scaleAccountInfo = AccountInfoOverrides[networkId]
9213
+ // if (scaleAccountInfo === undefined) {
9214
+ // // chain metadata version is < 15 and we also don't have an override hardcoded in
9215
+ // // the best way to handle this case: log a warning and return an empty balance
9216
+ // log.debug(
9217
+ // `Native token on chain ${networkId} has no balance type for decoding. Defaulting to a balance of 0 (zero).`,
9218
+ // )
9219
+ // return []
9220
+ // }
9221
+
9222
+ // try {
9223
+ // // eslint-disable-next-line no-var
9224
+ // oldChainBalance = change === null ? null : scaleAccountInfo.dec(change)
9225
+ // } catch (error) {
9226
+ // log.warn(
9227
+ // `Failed to create pre-metadataV14 balance type for native on chain ${networkId}: ${error?.toString()}`,
9228
+ // )
9229
+ // return []
9230
+ // }
9231
+ // }
9232
+ // // END: Handle chains which use metadata < v14
9233
+
9234
+ // /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9235
+ // type DecodedType = {
9236
+ // data?: {
9237
+ // flags?: bigint
9238
+ // free?: bigint
9239
+ // frozen?: bigint
9240
+ // reserved?: bigint
9241
+
9242
+ // // deprecated fields (they only show up on old chains)
9243
+ // feeFrozen?: bigint
9244
+ // miscFrozen?: bigint
9245
+ // }
9246
+ // }
9247
+ // const decoded =
9248
+ // decodeScale<DecodedType>(
9249
+ // coder,
9250
+ // change,
9251
+ // `Failed to decode base native balance on chain ${networkId}`,
9252
+ // ) ?? oldChainBalance
9253
+
9254
+ // const free = (decoded?.data?.free ?? 0n).toString()
9255
+ // const reserved = (decoded?.data?.reserved ?? 0n).toString()
9256
+ // const miscLock = (
9257
+ // (decoded?.data?.miscFrozen ?? 0n) +
9258
+ // // new chains don't split their `frozen` amount into `feeFrozen` and `miscFrozen`.
9259
+ // // for these chains, we'll use the `frozen` amount as `miscFrozen`.
9260
+ // ((decoded?.data as DecodedType["data"])?.frozen ?? 0n)
9261
+ // ).toString()
9262
+ // const feesLock = (decoded?.data?.feeFrozen ?? 0n).toString()
9263
+
9264
+ // // even if these values are 0, we still need to add them to the balanceJson.values array
9265
+ // // so that the balance pool can handle newly zeroed balances
9266
+ // // const existingValues = Object.fromEntries(
9267
+ // // balanceJson.values.map((v) => [getValueId(v), v]),
9268
+ // // )
9269
+ // const newValues: AmountWithLabel<string>[] = [
9270
+ // { type: "free", label: "free", amount: free.toString() },
9271
+ // { type: "reserved", label: "reserved", amount: reserved.toString() },
9272
+ // { type: "locked", label: "misc", amount: miscLock.toString() },
9273
+ // { type: "locked", label: "fees", amount: feesLock.toString() },
9274
+ // ]
9275
+
9276
+ // return newValues
9277
+
9278
+ // // const newValuesObj = Object.fromEntries(newValues.map((v) => [getValueId(v), v]))
9279
+
9280
+ // // balanceJson.values = Object.values({ ...existingValues, ...newValuesObj })
9281
+
9282
+ // // return balanceJson
9283
+ // }
9284
+
9285
+ // return { chainId: networkId, stateKey, decodeResult }
9286
+ // }
9287
+
9288
+ /**
9289
+ * Each nominationPool in the nominationPools pallet has access to some accountIds which have no
9290
+ * associated private key. Instead, they are derived from this function.
9291
+ */
9292
+ const nompoolAccountId = (palletId, poolId, index) => {
9293
+ const utf8Encoder = new TextEncoder();
9294
+ const encModPrefix = utf8Encoder.encode("modl");
9295
+ const encPalletId = utf8Encoder.encode(palletId);
9296
+ const encIndex = new Uint8Array([index]);
9297
+ const encPoolId = u32.enc(typeof poolId === "string" ? parseInt(poolId, 10) : poolId);
9298
+ const length = encModPrefix.length + encPalletId.length + encIndex.length + encPoolId.length;
9299
+ const remainingBytes = 32 - length;
9300
+ const encEmptyH256 = new Uint8Array(remainingBytes);
9301
+ const bytes = mergeUint8([encModPrefix, encPalletId, encIndex, encPoolId, encEmptyH256]);
9302
+ return AccountId().dec(bytes);
9303
+ };
9304
+ /** The stash account for the nomination pool */
9305
+ const nompoolStashAccountId = (palletId, poolId) => nompoolAccountId(palletId, poolId, 0);
9306
+
9307
+ const buildNomPoolQueries = (networkId, partialBalances, miniMetadata) => {
9308
+ const networkStorageCoders = getNomPoolCoders(networkId, miniMetadata);
9309
+ if (!networkStorageCoders) throw new Error(`No network storage coders found for networkId: ${networkId}`);
9310
+ return partialBalances.map(({
9311
+ balance,
9312
+ nomPoolMemberInfo
9313
+ }) => {
9314
+ const stateKeys = getNomPoolStateKeys(networkStorageCoders, nomPoolMemberInfo, miniMetadata.extra);
9315
+ return {
9316
+ stateKeys,
9317
+ decodeResult: changes => {
9318
+ if (!nomPoolMemberInfo || !stateKeys.length || changes.includes(null)) return balance;
9319
+ const accountPoints = nomPoolMemberInfo?.points ?? "0";
9320
+ const {
9321
+ poolPoints = "0"
9322
+ } = decodePoolPoints(networkStorageCoders.bondedPools, changes[0], networkId);
9323
+ const {
9324
+ poolTotalActiveStake = "0"
9325
+ } = decodePoolStake(networkStorageCoders.ledger, changes[1], networkId);
9326
+ const {
9327
+ metadata = "0"
9328
+ } = decodePoolMeta(networkStorageCoders.metadata, changes[2], networkId);
9329
+ const amount = accountPoints === "0" || poolPoints === "0" || poolTotalActiveStake === "0" ? 0n : BigInt(poolTotalActiveStake) * BigInt(accountPoints) / BigInt(poolPoints);
9330
+ const unbondingAmount = nomPoolMemberInfo.unbondingEras.reduce((total, {
9331
+ amount
9332
+ }) => total + BigInt(amount ?? "0"), 0n);
9333
+ return {
9334
+ ...balance,
9335
+ values: [...(balance.values ?? []), {
9336
+ source: "nompools-staking",
9337
+ type: "nompool",
9338
+ label: "nompools-staking",
9339
+ amount: amount.toString(),
9340
+ meta: {
9341
+ type: "nompool",
9342
+ poolId: nomPoolMemberInfo.poolId,
9343
+ description: metadata
9344
+ }
9345
+ }, {
9346
+ source: "nompools-staking",
9347
+ type: "nompool",
9348
+ label: "nompools-unbonding",
9349
+ amount: unbondingAmount.toString(),
9350
+ meta: {
9351
+ poolId: nomPoolMemberInfo.poolId,
9352
+ description: metadata ?? `Pool ${nomPoolMemberInfo.poolId}`,
9353
+ unbonding: true
9354
+ }
9355
+ }]
9356
+ };
9357
+ }
9358
+ };
9359
+ });
9360
+ };
9361
+ const getNomPoolCoders = (networkId, miniMetadata) => {
9362
+ return buildNetworkStorageCoders(networkId, miniMetadata, {
9363
+ poolMembers: ["NominationPools", "PoolMembers"],
9364
+ bondedPools: ["NominationPools", "BondedPools"],
9365
+ ledger: ["Staking", "Ledger"],
9366
+ metadata: ["NominationPools", "Metadata"]
9367
+ });
9368
+ };
9369
+ const decodePoolPoints = (coder, value, networkId) => {
9370
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9371
+
9372
+ const decoded = decodeScale(coder, value, `Failed to decode bondedPools on chain ${networkId}`);
9373
+ return {
9374
+ poolPoints: decoded?.points.toString()
9375
+ };
9376
+ };
9377
+ const decodePoolStake = (coder, value, networkId) => {
9378
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9379
+
9380
+ const decoded = decodeScale(coder, value, `Failed to decode ledger on chain ${networkId}`);
9381
+ return {
9382
+ poolTotalActiveStake: decoded?.active.toString()
9383
+ };
9384
+ };
9385
+ const decodePoolMeta = (coder, value, networkId) => {
9386
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9387
+
9388
+ const decoded = decodeScale(coder, value, `Failed to decode metadata on chain ${networkId}`);
9389
+ const metadata = decoded?.asText();
9390
+ return {
9391
+ metadata
9392
+ };
9393
+ };
9394
+ const getNomPoolStateKeys = (coders, nomPoolMemberInfo, extra) => {
9395
+ if (!nomPoolMemberInfo || !extra.nominationPoolsPalletId || !coders?.bondedPools || !coders.ledger || !coders.metadata) return [];
9396
+ const poolId = nomPoolMemberInfo.poolId;
9397
+ const stashAddress = nompoolStashAccountId(extra.nominationPoolsPalletId, poolId);
9398
+ const poolPointsStateKey = coders.bondedPools.keys.enc(poolId);
9399
+ const poolStakeStateKey = coders.ledger.keys.enc(stashAddress);
9400
+ const poolMetaStateKey = coders.metadata.keys.enc(poolId);
9401
+ return [poolPointsStateKey, poolStakeStateKey, poolMetaStateKey];
9402
+ };
9403
+
9404
+ const fetchBalances$2 = async ({
9405
+ networkId,
9406
+ addressesByToken,
9407
+ connector,
9408
+ miniMetadata
9409
+ }) => {
9410
+ const balanceDefs = getBalanceDefs(addressesByToken);
9411
+ if (!miniMetadata?.data) {
9412
+ log.warn("MiniMetadata is required for fetching balances");
9413
+ return {
9414
+ success: [],
9415
+ errors: balanceDefs.map(def => ({
9416
+ tokenId: def.token.id,
9417
+ address: def.address,
9418
+ error: new Error("Minimetadata is required for fetching balances")
9419
+ }))
9420
+ };
9421
+ }
9422
+ if (miniMetadata.source !== MODULE_TYPE$2) {
9423
+ log.warn(`Ignoring miniMetadata with source ${miniMetadata.source} in ${MODULE_TYPE$2}.`);
9424
+ return {
9425
+ success: [],
9426
+ errors: balanceDefs.map(def => ({
9427
+ tokenId: def.token.id,
9428
+ address: def.address,
9429
+ error: new Error(`Invalid request: miniMetadata source is not ${MODULE_TYPE$2}`)
9430
+ }))
9431
+ };
9432
+ }
9433
+ if (miniMetadata.chainId !== networkId) {
9434
+ log.warn(`Ignoring miniMetadata with chainId ${miniMetadata.chainId} in ${MODULE_TYPE$2}. Expected chainId is ${networkId}`);
9435
+ return {
9436
+ success: [],
9437
+ errors: balanceDefs.map(def => ({
9438
+ tokenId: def.token.id,
9439
+ address: def.address,
9440
+ error: new Error(`Invalid request: Expected chainId is ${networkId}`)
9441
+ }))
9442
+ };
9443
+ }
9444
+ const queries = buildBaseQueries(networkId, balanceDefs, miniMetadata);
9445
+ const partialBalances = await fetchQueriesPack(connector, networkId, queries);
9446
+
9447
+ // now for each balance that includes nomPoolStaking, we need to fetch the metadata for the pool
9448
+ const nomPoolQueries = buildNomPoolQueries(networkId, partialBalances, miniMetadata);
9449
+ const balances = await fetchQueriesPack(connector, networkId, nomPoolQueries);
9450
+
9451
+ // TODO ⚠️ dedupe locks
9452
+
9453
+ const subtensorBalances$ = getSubtensorStakingBalances$(connector, networkId, balanceDefs, miniMetadata);
9454
+ const subtensorBalancesByAddress = await firstValueFrom(subtensorBalances$);
9455
+ for (const [address, subtensorBalances] of Object.entries(subtensorBalancesByAddress)) {
9456
+ const balance = balances.find(b => b.address === address);
9457
+ if (balance?.values) balance.values.push(...subtensorBalances);
9458
+ }
9459
+ return {
9460
+ success: balances,
9461
+ errors: []
9462
+ };
9463
+ };
9464
+
9465
+ const fetchTokens$2 = async ({
9466
+ networkId,
9467
+ tokens,
9468
+ connector,
9469
+ miniMetadata
9470
+ }) => {
9471
+ if (miniMetadata.extra.disable) return [];
9472
+ const {
9473
+ tokenSymbol: symbol,
9474
+ tokenDecimals: decimals
9475
+ } = await getChainProperties(connector, networkId);
9476
+ if (!miniMetadata.extra.existentialDeposit) log.warn(`Substrate native module: existentialDeposit is undefined for ${networkId}, using 0`);
9477
+ const tokenConfig = tokens[0];
9478
+ const nativeToken = {
9479
+ id: subNativeTokenId(networkId),
9480
+ type: "substrate-native",
9481
+ platform: "polkadot",
9482
+ networkId,
9483
+ isDefault: true,
9484
+ symbol: symbol,
9485
+ name: symbol,
9486
+ decimals: decimals,
9487
+ existentialDeposit: miniMetadata.extra.existentialDeposit ?? "0"
9488
+ };
9489
+ return [assign(nativeToken, tokenConfig)];
9490
+ };
9491
+ const DotNetworkPropertiesSimple = z.object({
9492
+ tokenDecimals: z.number().optional().default(0),
9493
+ tokenSymbol: z.string().optional().default("Unit")
9494
+ });
9495
+ const DotNetworkPropertiesArray = z.object({
9496
+ tokenDecimals: z.array(z.number()).nonempty(),
9497
+ tokenSymbol: z.array(z.string()).nonempty()
9498
+ });
9499
+ const DotNetworkPropertiesSchema = z.union([DotNetworkPropertiesSimple, DotNetworkPropertiesArray]).transform(val => ({
9500
+ tokenDecimals: Array.isArray(val.tokenDecimals) ? val.tokenDecimals[0] : val.tokenDecimals,
9501
+ tokenSymbol: Array.isArray(val.tokenSymbol) ? val.tokenSymbol[0] : val.tokenSymbol
9502
+ }));
9503
+ const getChainProperties = async (connector, networkId) => {
9504
+ const properties = await connector.send(networkId, "system_properties", [], true);
9505
+ return DotNetworkPropertiesSchema.parse(properties);
9506
+ };
9507
+
9508
+ const getMiniMetadata$2 = ({
9509
+ networkId,
9510
+ specVersion,
9511
+ metadataRpc,
9512
+ config
9513
+ }) => {
9514
+ const source = MODULE_TYPE$2;
9515
+ const chainId = networkId;
9516
+ const systemVersion = getConstantValue(metadataRpc, "System", "Version");
9517
+ if (specVersion !== systemVersion.spec_version) log.warn("specVersion mismatch", {
9518
+ networkId,
9519
+ specVersion,
9520
+ systemVersion
9521
+ });
9522
+ const id = deriveMiniMetadataId({
9523
+ source,
9524
+ chainId,
9525
+ specVersion
9526
+ });
9527
+ const {
9528
+ metadata,
9529
+ unifiedMetadata
9530
+ } = parseMetadataRpc(metadataRpc);
9531
+ if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
9532
+ if (config?.disable) return {
9533
+ id,
9534
+ source,
9535
+ chainId,
9536
+ specVersion,
9537
+ version: MINIMETADATA_VERSION,
9538
+ data: null,
9539
+ extra: {
9540
+ disable: true
9541
+ }
9542
+ };
9543
+ const existentialDeposit = tryGetConstantValue(metadataRpc, "Balances", "ExistentialDeposit")?.toString();
9544
+ const nominationPoolsPalletId = tryGetConstantValue(metadataRpc, "NominationPools", "PalletId")?.asText();
9545
+ const hasSubtensorPallet = !!tryGetConstantValue(metadataRpc, "SubtensorModule", "KeySwapCost");
9546
+ const hasFreezesItem = Boolean(unifiedMetadata.pallets.find(({
9547
+ name
9548
+ }) => name === "Balances")?.storage?.items.find(({
9549
+ name
9550
+ }) => name === "Freezes"));
9551
+ const useLegacyTransferableCalculation = !hasFreezesItem;
9552
+ compactMetadata(metadata, [{
9553
+ pallet: "System",
9554
+ constants: ["Version", "SS58Prefix"],
9555
+ items: ["Account"]
9556
+ }, {
9557
+ pallet: "Balances",
9558
+ items: ["Reserves", "Holds", "Locks", "Freezes"]
9559
+ }, {
9560
+ pallet: "NominationPools",
9561
+ items: ["PoolMembers", "BondedPools", "Metadata"]
9562
+ }, {
9563
+ pallet: "Staking",
9564
+ items: ["Ledger"]
9565
+ },
9566
+ // TotalColdkeyStake is used until v.2.2.1, then it is replaced by StakingHotkeys+Stake
9567
+ // Need to keep TotalColdkeyStake for a while so chaindata keeps including it in miniMetadatas, so it doesnt break old versions of the wallet
9568
+ // TODO: Since chaindata v4 this is safe to now delete
9569
+ {
9570
+ pallet: "SubtensorModule",
9571
+ items: ["TotalColdkeyStake", "StakingHotkeys", "Stake"]
9572
+ }], [{
9573
+ runtimeApi: "StakeInfoRuntimeApi",
9574
+ methods: ["get_stake_info_for_coldkey"]
9575
+ }, {
9576
+ runtimeApi: "SubnetInfoRuntimeApi",
9577
+ methods: ["get_dynamic_info"]
9578
+ }]);
9579
+ return {
9580
+ id,
9581
+ source,
9582
+ chainId,
9583
+ specVersion,
9584
+ version: MINIMETADATA_VERSION,
9585
+ data: encodeMetadata(metadata),
9586
+ extra: {
9587
+ useLegacyTransferableCalculation,
9588
+ existentialDeposit,
9589
+ nominationPoolsPalletId,
9590
+ hasSubtensorPallet
9591
+ }
9592
+ };
9593
+ };
9594
+
9595
+ const getTransferCallData$2 = ({
9596
+ from,
9597
+ to,
9598
+ value,
9599
+ token,
9600
+ type,
9601
+ metadataRpc
9602
+ }) => {
9603
+ if (!isTokenOfType(token, MODULE_TYPE$2)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$2}.`);
9604
+ const {
9605
+ unifiedMetadata,
9606
+ lookupFn,
9607
+ builder
9608
+ } = parseMetadataRpc(metadataRpc);
9609
+ const method = getTransferMethod$1(type, unifiedMetadata, lookupFn);
9610
+ const {
9611
+ codec,
9612
+ location
9613
+ } = builder.buildCall("Balances", method);
9614
+ const args = getEncodedArgs(method, to, value, codec);
9615
+ const callData = Binary.fromBytes(mergeUint8([new Uint8Array(location), args]));
9616
+ return {
9617
+ address: from,
9618
+ method: callData.asHex()
9619
+ };
9620
+ };
9621
+ const getTransferMethod$1 = (type, unifiedMetadata, lookupFn) => {
9622
+ switch (type) {
9623
+ case "keep-alive":
9624
+ return "transfer_keep_alive";
9625
+ case "all":
9626
+ return "transfer_all";
9627
+ case "allow-death":
9628
+ {
9629
+ const callType = unifiedMetadata.pallets.find(pallet => pallet.name === "Balances")?.calls?.type;
9630
+ if (callType) {
9631
+ const palletCalls = lookupFn(callType);
9632
+ if (palletCalls.type === "enum" && palletCalls.value["transfer_allow_death"]) return "transfer_allow_death";
9633
+ }
9634
+
9635
+ // legacy fallback
9636
+ return "transfer";
9637
+ }
9638
+ }
9639
+ };
9640
+ const getEncodedArgs = (method, to, value, argsCodec) => {
9641
+ try {
9642
+ switch (method) {
9643
+ case "transfer_allow_death":
9644
+ case "transfer_keep_alive":
9645
+ case "transfer":
9646
+ return getTransferEncodedArgs(to, value, argsCodec);
9647
+ case "transfer_all":
9648
+ return getTransferAllEncodedArgs(to, argsCodec);
9649
+ }
9650
+ } catch {
9651
+ throw new Error(`Failed to encode arguments for method ${method}, ${to}, ${value}`);
9652
+ }
9653
+ };
9654
+ const getEncodedValue = (codec, possibleValue) => {
9655
+ for (const getArgs of possibleValue) {
9656
+ try {
9657
+ return codec.enc(getArgs());
9658
+ } catch {
9659
+ // wrong inputs, ignore and try the next one
9660
+ }
9661
+ }
9662
+ throw new Error("Failed to encode");
9663
+ };
9664
+
9665
+ // same inputs for both KeepAlive and allowDeath
9666
+ const getTransferEncodedArgs = (to, value, codec) => {
9667
+ return getEncodedValue(codec, [() => ({
9668
+ dest: Enum("Id", to),
9669
+ value: BigInt(value)
9670
+ })]);
9671
+ };
9672
+ const getTransferAllEncodedArgs = (to, codec) => {
9673
+ return getEncodedValue(codec, [() => ({
9674
+ dest: Enum("Id", to),
9675
+ keep_alive: false
9676
+ })]);
9677
+ };
9678
+
9679
+ const SUBSCRIPTION_INTERVAL$2 = 6_000;
9680
+ const subscribeBalances$2 = ({
9681
+ networkId,
9682
+ addressesByToken,
9683
+ connector,
9684
+ miniMetadata
9685
+ }) => {
9686
+ return new Observable(subscriber => {
9687
+ const abortController = new AbortController();
9688
+
9689
+ // on hydration balances are fetched using a runtimeApi, which can't be subscribed to.
9690
+ // => poll values for each block
9691
+ const poll = async () => {
9692
+ try {
9693
+ if (abortController.signal.aborted) return;
9694
+ const balances = await fetchBalances$2({
9695
+ networkId,
9696
+ addressesByToken,
9697
+ connector,
9698
+ miniMetadata
9699
+ });
9700
+ if (abortController.signal.aborted) return;
9701
+ subscriber.next(balances);
9702
+ setTimeout(poll, SUBSCRIPTION_INTERVAL$2);
9703
+ } catch (error) {
9704
+ log.error("Error", {
9705
+ module: MODULE_TYPE$2,
9706
+ networkId,
9707
+ miniMetadata,
9708
+ addressesByToken,
9709
+ error
9710
+ });
9711
+ subscriber.error(error);
9712
+ }
9713
+ };
9714
+ poll();
9715
+ return () => {
9716
+ abortController.abort();
9717
+ };
9718
+ }).pipe(distinctUntilChanged(isEqual$1));
9719
+ };
9720
+
9721
+ const SubNativeBalanceModule = {
9722
+ type: MODULE_TYPE$2,
9723
+ platform: PLATFORM$2,
9724
+ getMiniMetadata: getMiniMetadata$2,
9725
+ fetchTokens: fetchTokens$2,
9726
+ fetchBalances: fetchBalances$2,
9727
+ subscribeBalances: subscribeBalances$2,
9728
+ getTransferCallData: getTransferCallData$2
9729
+ };
9730
+
9731
+ const MODULE_TYPE$1 = SubPsp22TokenSchema.shape.type.value;
9732
+ const PLATFORM$1 = SubPsp22TokenSchema.shape.platform.value;
9733
+
9734
+ // to be used by chaindata too
9735
+ z.strictObject({
9736
+ contractAddress: SubPsp22TokenSchema.shape.contractAddress,
9737
+ ...TokenConfigBaseSchema.shape
9738
+ });
9739
+
9740
+ const fetchBalances$1 = async ({
9741
+ networkId,
9742
+ addressesByToken,
9743
+ connector
9744
+ }) => {
9745
+ const balanceDefs = getBalanceDefs(addressesByToken);
9746
+ if (!balanceDefs.length) return {
9747
+ success: [],
9748
+ errors: []
9749
+ };
9750
+ const registry = new TypeRegistry();
9751
+ const Psp22Abi = new Abi(psp22Abi);
9752
+ const contractCall = makeContractCaller({
9753
+ chainConnector: connector,
9754
+ chainId: networkId,
9755
+ registry
9756
+ });
9757
+ const results = await Promise.allSettled(balanceDefs.map(async ({
9758
+ token,
9759
+ address
9760
+ }) => {
9761
+ const result = await contractCall(address, token.contractAddress, Psp22Abi.findMessage("PSP22::balance_of").toU8a([address]));
9762
+ if (!result.result.isOk) throw new Error("Failed to fetch balance");
9763
+ const value = registry.createType("Balance", result.result.asOk.data).toString();
9764
+ const balance = {
9765
+ source: "substrate-psp22",
9766
+ status: "live",
9767
+ address,
9768
+ networkId: token.networkId,
9769
+ tokenId: token.id,
9770
+ value
9771
+ };
9772
+ return balance;
9773
+ }));
9774
+ return results.reduce((acc, result) => {
9775
+ if (result.status === "fulfilled") acc.success.push(result.value);else {
9776
+ const error = result.reason;
9777
+ acc.errors.push({
9778
+ tokenId: error.tokenId,
9779
+ address: error.address,
9780
+ error
9781
+ });
9782
+ }
9783
+ return acc;
9784
+ }, {
9785
+ success: [],
9786
+ errors: []
9787
+ });
9788
+ };
9789
+
9790
+ const fetchTokens$1 = async ({
9791
+ networkId,
9792
+ tokens,
9793
+ connector
9794
+ }) => {
9795
+ if (!tokens.length) return [];
9796
+ const registry = new TypeRegistry();
9797
+ const Psp22Abi = new Abi(psp22Abi);
9798
+
9799
+ // TODO: Use `decodeOutput` from `./util/decodeOutput`
9800
+ const contractCall = makeContractCaller({
9801
+ chainConnector: connector,
9802
+ chainId: networkId,
9803
+ registry
9804
+ });
9805
+ const tokenList = {};
9806
+ for (const tokenConfig of tokens ?? []) {
9807
+ try {
9808
+ let symbol = tokenConfig?.symbol ?? "Unit";
9809
+ let decimals = tokenConfig?.decimals ?? 0;
9810
+ const contractAddress = tokenConfig?.contractAddress ?? undefined;
9811
+ if (contractAddress === undefined) continue;
9812
+ await (async () => {
9813
+ const [symbolResult, decimalsResult] = await Promise.all([contractCall(contractAddress, contractAddress, Psp22Abi.findMessage("PSP22Metadata::token_symbol").toU8a([])), contractCall(contractAddress, contractAddress, Psp22Abi.findMessage("PSP22Metadata::token_decimals").toU8a([]))]);
9814
+
9815
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9816
+ const symbolData = symbolResult.toJSON()?.result?.ok?.data;
9817
+ symbol = typeof symbolData === "string" && symbolData.startsWith("0x") ? u8aToString(registry.createType("Option<Vec<u8>>",
9818
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9819
+ symbolResult.toJSON()?.result?.ok?.data)?.value)?.replace(/\p{C}/gu, "") : symbol;
9820
+
9821
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9822
+ const decimalsData = decimalsResult.toJSON()?.result?.ok?.data;
9823
+ decimals = typeof decimalsData === "string" && decimalsData.startsWith("0x") ? hexToNumber(decimalsData) : decimals;
9824
+ })();
9825
+ const id = subPsp22TokenId(networkId, contractAddress);
9826
+ const token = {
9827
+ id,
9828
+ type: "substrate-psp22",
9829
+ platform: "polkadot",
9830
+ isDefault: tokenConfig.isDefault ?? true,
9831
+ symbol,
9832
+ decimals,
9833
+ name: tokenConfig?.name || symbol,
9834
+ logo: tokenConfig?.logo,
9835
+ contractAddress,
9836
+ networkId
9837
+ };
9838
+ if (tokenConfig?.coingeckoId) token.coingeckoId = tokenConfig?.coingeckoId;
9839
+ if (tokenConfig?.mirrorOf) token.mirrorOf = tokenConfig?.mirrorOf;
9840
+ tokenList[token.id] = token;
9841
+ } catch (error) {
9842
+ log.error(`Failed to build substrate-psp22 token ${tokenConfig.contractAddress} (${tokenConfig.symbol}) on ${networkId}`, error?.message ?? error);
9843
+ continue;
9844
+ }
9845
+ }
9846
+ return values(tokenList).filter(t => {
9847
+ const parsed = SubPsp22TokenSchema.safeParse(t);
9848
+ if (!parsed.success) log.warn(`Ignoring invalid token ${MODULE_TYPE$1}`, t);
9849
+ return parsed.success;
9850
+ });
9851
+ };
9852
+
9853
+ const getMiniMetadata$1 = ({
9854
+ networkId,
9855
+ specVersion,
9856
+ metadataRpc
9857
+ }) => {
9858
+ const source = MODULE_TYPE$1;
9859
+ const chainId = networkId;
9860
+ const systemVersion = getConstantValue(metadataRpc, "System", "Version");
9861
+ if (specVersion !== systemVersion.spec_version) log.warn("specVersion mismatch", {
9862
+ networkId,
9863
+ specVersion,
9864
+ systemVersion
9865
+ });
9866
+ const id = deriveMiniMetadataId({
9867
+ source,
9868
+ chainId,
9869
+ specVersion
9870
+ });
9871
+ const {
9872
+ unifiedMetadata
9873
+ } = parseMetadataRpc(metadataRpc);
9874
+ if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
9875
+ return {
9876
+ id,
9877
+ source,
9878
+ chainId,
9879
+ specVersion,
9880
+ version: MINIMETADATA_VERSION,
9881
+ data: null,
9882
+ extra: null
9883
+ };
9884
+ };
9885
+
9886
+ const getTransferCallData$1 = async ({
9887
+ from,
9888
+ to,
9889
+ value,
9890
+ token,
9891
+ metadataRpc,
9892
+ connector
9893
+ }) => {
9894
+ if (!isTokenOfType(token, MODULE_TYPE$1)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$1}.`);
9895
+ const networkId = parseTokenId(token.id).networkId;
9896
+ const {
9897
+ builder
9898
+ } = parseMetadataRpc(metadataRpc);
9899
+ const {
9900
+ codec,
9901
+ location
9902
+ } = builder.buildCall("Contracts", "call");
9903
+ const Psp22Abi = new Abi(psp22Abi);
9904
+ const registry = new TypeRegistry();
9905
+ const contractCall = makeContractCaller({
9906
+ chainConnector: connector,
9907
+ chainId: networkId,
9908
+ registry
9909
+ });
9910
+
9911
+ // TODO use papi contract api
9912
+ const data = Psp22Abi.findMessage("PSP22::transfer").toU8a([to, value, undefined]);
9913
+ const hexData = registry.createType("Vec<u8>", data).toHex();
9914
+ const dryRunResult = await contractCall(from, token.contractAddress, data);
9915
+ const args = codec.enc({
9916
+ dest: Enum("Id", token.contractAddress),
9917
+ value: 0,
9918
+ gas_limit: {
9919
+ ref_time: dryRunResult.gasRequired.refTime.toBigInt(),
9920
+ proof_size: dryRunResult.gasRequired.proofSize.toBigInt()
9921
+ },
9922
+ storage_deposit_limit: dryRunResult.storageDeposit.isCharge ? dryRunResult.storageDeposit.asCharge.toBigInt() : null,
9923
+ data: Binary.fromHex(hexData)
9924
+ });
9925
+ const callData = Binary.fromBytes(mergeUint8([new Uint8Array(location), args]));
9926
+ return {
9927
+ address: from,
9928
+ method: callData.asHex()
9929
+ };
9930
+ };
9931
+
9932
+ const SUBSCRIPTION_INTERVAL$1 = 6_000;
9933
+ const subscribeBalances$1 = ({
9934
+ networkId,
9935
+ addressesByToken,
9936
+ connector,
9937
+ miniMetadata
9938
+ }) => {
9939
+ return new Observable(subscriber => {
9940
+ const abortController = new AbortController();
9941
+
9942
+ // on hydration balances are fetched using a runtimeApi, which can't be subscribed to.
9943
+ // => poll values for each block
9944
+ const poll = async () => {
9945
+ try {
9946
+ if (abortController.signal.aborted) return;
9947
+ const balances = await fetchBalances$1({
9948
+ networkId,
9949
+ addressesByToken,
9950
+ connector,
9951
+ miniMetadata
9952
+ });
9953
+ if (abortController.signal.aborted) return;
9954
+ subscriber.next(balances);
9955
+ setTimeout(poll, SUBSCRIPTION_INTERVAL$1);
9956
+ } catch (error) {
9957
+ log.error("Error", {
9958
+ module: MODULE_TYPE$1,
9959
+ networkId,
9960
+ miniMetadata,
9961
+ addressesByToken,
9962
+ error
9963
+ });
9964
+ subscriber.error(error);
9965
+ }
9966
+ };
9967
+ poll();
9968
+ return () => {
9969
+ abortController.abort();
9970
+ };
9971
+ }).pipe(distinctUntilChanged(isEqual$1));
9972
+ };
9973
+
9974
+ const SubPsp22BalanceModule = {
9975
+ type: MODULE_TYPE$1,
9976
+ platform: PLATFORM$1,
9977
+ getMiniMetadata: getMiniMetadata$1,
9978
+ fetchTokens: fetchTokens$1,
9979
+ fetchBalances: fetchBalances$1,
9980
+ subscribeBalances: subscribeBalances$1,
9981
+ getTransferCallData: getTransferCallData$1
9982
+ };
9983
+
9984
+ const MODULE_TYPE = SubTokensTokenSchema.shape.type.value;
9985
+ const PLATFORM = SubTokensTokenSchema.shape.platform.value;
9986
+
9987
+ // to be used by chaindata too
9988
+ z.strictObject({
9989
+ onChainId: SubTokensTokenSchema.shape.onChainId,
9990
+ ...TokenConfigBaseSchema.shape,
9991
+ // force these 3 fields because in this module we wont pull anything from chain
9992
+ symbol: z.string().nonempty(),
9993
+ decimals: z.number(),
9994
+ existentialDeposit: z.string().nonempty()
9995
+ });
9996
+
9997
+ // Do not use this type outside of this module
9998
+
9999
+ // Do not use this type outside of this module
10000
+
10001
+ const fetchBalances = async ({
10002
+ networkId,
10003
+ addressesByToken,
10004
+ connector,
10005
+ miniMetadata
10006
+ }) => {
10007
+ const balanceDefs = getBalanceDefs(addressesByToken);
10008
+ if (!miniMetadata?.data) {
10009
+ log.warn("MiniMetadata is required for fetching balances");
10010
+ return {
10011
+ success: [],
10012
+ errors: balanceDefs.map(def => ({
10013
+ tokenId: def.token.id,
10014
+ address: def.address,
10015
+ error: new Error("Minimetadata is required for fetching balances")
10016
+ }))
10017
+ };
10018
+ }
10019
+ if (miniMetadata.source !== MODULE_TYPE) {
10020
+ log.warn(`Ignoring miniMetadata with source ${miniMetadata.source} in ${MODULE_TYPE}.`);
10021
+ return {
10022
+ success: [],
10023
+ errors: balanceDefs.map(def => ({
10024
+ tokenId: def.token.id,
10025
+ address: def.address,
10026
+ error: new Error(`Invalid request: miniMetadata source is not ${MODULE_TYPE}`)
10027
+ }))
10028
+ };
10029
+ }
10030
+ if (miniMetadata.chainId !== networkId) {
10031
+ log.warn(`Ignoring miniMetadata with chainId ${miniMetadata.chainId} in ${MODULE_TYPE}. Expected chainId is ${networkId}`);
10032
+ return {
10033
+ success: [],
10034
+ errors: balanceDefs.map(def => ({
10035
+ tokenId: def.token.id,
10036
+ address: def.address,
10037
+ error: new Error(`Invalid request: Expected chainId is ${networkId}`)
10038
+ }))
10039
+ };
10040
+ }
10041
+ const queries = buildQueries(networkId, balanceDefs, miniMetadata);
10042
+ const balances = await new RpcStateQueryHelper(connector, queries).fetch();
10043
+ return balanceDefs.reduce((acc, def) => {
10044
+ const balance = balances.find(b => b?.address === def.address && b?.tokenId === def.token.id);
10045
+ if (balance) acc.success.push(balance);
10046
+ //if no entry consider empty balance
10047
+ else acc.success.push({
10048
+ address: def.address,
10049
+ networkId,
10050
+ tokenId: def.token.id,
10051
+ source: MODULE_TYPE,
10052
+ status: "live",
10053
+ values: [{
10054
+ type: "free",
10055
+ label: "free",
10056
+ amount: "0"
10057
+ }, {
10058
+ type: "locked",
10059
+ label: "frozen",
10060
+ amount: "0"
10061
+ }]
10062
+ });
10063
+ return acc;
10064
+ }, {
10065
+ success: [],
10066
+ errors: []
10067
+ });
10068
+ };
10069
+ const buildQueries = (networkId, balanceDefs, miniMetadata) => {
10070
+ const networkStorageCoders = buildNetworkStorageCoders(networkId, miniMetadata, {
10071
+ storage: [miniMetadata.extra.palletId, "Accounts"]
10072
+ });
10073
+ return balanceDefs.map(({
10074
+ token,
10075
+ address
10076
+ }) => {
10077
+ const scaleCoder = networkStorageCoders?.storage;
10078
+ const getStateKey = onChainId => {
10079
+ try {
10080
+ return scaleCoder.keys.enc(address, papiParse(onChainId));
10081
+ } catch {
10082
+ return null;
10083
+ }
10084
+ };
10085
+ const stateKey = getStateKey(token.onChainId);
10086
+ if (!stateKey) {
10087
+ log.warn(`Invalid assetId / address in ${networkId} storage query ${token.onChainId} / ${address}`);
10088
+ return null;
10089
+ }
10090
+ const decodeResult = change => {
10091
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
10092
+
10093
+ const decoded = decodeScale(scaleCoder, change, `Failed to decode substrate-tokens balance on chain ${networkId}`) ?? {
10094
+ free: 0n,
10095
+ reserved: 0n,
10096
+ frozen: 0n
10097
+ };
10098
+ const free = (decoded?.free ?? 0n).toString();
10099
+ const reserved = (decoded?.reserved ?? 0n).toString();
10100
+ const frozen = (decoded?.frozen ?? 0n).toString();
10101
+ const balanceValues = [{
10102
+ type: "free",
10103
+ label: "free",
10104
+ amount: free.toString()
10105
+ }, {
10106
+ type: "reserved",
10107
+ label: "reserved",
10108
+ amount: reserved.toString()
10109
+ }, {
10110
+ type: "locked",
10111
+ label: "frozen",
10112
+ amount: frozen.toString()
10113
+ }];
10114
+ return {
10115
+ source: "substrate-tokens",
10116
+ status: "live",
10117
+ address,
10118
+ networkId,
10119
+ tokenId: token.id,
10120
+ values: balanceValues
10121
+ };
10122
+ };
10123
+ return {
10124
+ chainId: networkId,
10125
+ stateKey,
10126
+ decodeResult
10127
+ };
10128
+ }).filter(isNotNil);
10129
+ };
10130
+
10131
+ const fetchTokens = async ({
10132
+ networkId,
10133
+ tokens,
10134
+ miniMetadata
10135
+ }) => {
10136
+ if (!miniMetadata?.data) return [];
10137
+
10138
+ // in this module we do not fetch any token information from the chain
10139
+ // this is because there are basically as many pallet implementations as there are networks (Expect Chaos, they said)
10140
+ // we rely on the config to provide all the info we need
10141
+ return tokens.map(tokenConfig => assign({
10142
+ id: subTokensTokenId(networkId, tokenConfig.onChainId),
10143
+ type: MODULE_TYPE,
10144
+ platform: PLATFORM,
10145
+ networkId,
10146
+ onChainId: tokenConfig.onChainId,
10147
+ symbol: tokenConfig.symbol ?? "Unit",
10148
+ decimals: tokenConfig.decimals ?? 0,
10149
+ name: tokenConfig.name ?? tokenConfig.symbol ?? "Unit",
10150
+ existentialDeposit: tokenConfig.existentialDeposit ?? "0",
10151
+ isDefault: true
10152
+ }, tokenConfig));
10153
+ };
10154
+
10155
+ const getMiniMetadata = ({
10156
+ networkId,
10157
+ specVersion,
10158
+ metadataRpc,
10159
+ config
10160
+ }) => {
10161
+ const source = MODULE_TYPE;
10162
+ const chainId = networkId;
10163
+ const systemVersion = getConstantValue(metadataRpc, "System", "Version");
10164
+ if (specVersion !== systemVersion.spec_version) log.warn("specVersion mismatch", {
10165
+ networkId,
10166
+ specVersion,
10167
+ systemVersion
10168
+ });
10169
+ const id = deriveMiniMetadataId({
10170
+ source,
10171
+ chainId,
10172
+ specVersion
10173
+ });
10174
+ const {
10175
+ unifiedMetadata
10176
+ } = parseMetadataRpc(metadataRpc);
10177
+ if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
10178
+ const extra = {
10179
+ palletId: config?.palletId ?? "Tokens"
10180
+ };
10181
+ return {
10182
+ id,
10183
+ source,
10184
+ chainId,
10185
+ specVersion,
10186
+ version: MINIMETADATA_VERSION,
10187
+ data: getData(metadataRpc, extra.palletId),
10188
+ extra
10189
+ };
10190
+ };
10191
+ const getData = (metadataRpc, pallet) => {
10192
+ const {
10193
+ metadata,
10194
+ unifiedMetadata
10195
+ } = parseMetadataRpc(metadataRpc);
10196
+
10197
+ // ensure the network has all the required bits
10198
+ if (!hasStorageItems(unifiedMetadata, pallet, ["Accounts"])) return null;
10199
+ compactMetadata(metadata, [{
10200
+ pallet,
10201
+ items: ["Accounts"]
10202
+ }]);
10203
+ return encodeMetadata(metadata);
10204
+ };
10205
+
10206
+ const getTransferCallData = ({
10207
+ from,
10208
+ to,
10209
+ value,
10210
+ token,
10211
+ type,
10212
+ metadataRpc,
10213
+ config
10214
+ }) => {
10215
+ if (!isTokenOfType(token, MODULE_TYPE)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE}.`);
10216
+ const {
10217
+ builder
10218
+ } = parseMetadataRpc(metadataRpc);
10219
+
10220
+ // each chain has its own way of encoding the transfer call data
10221
+ // let's try our luck until one works!
10222
+ const options = getCallDataOptions(to, token, value, type, config);
10223
+ const callData = getCallDataFromOptions(builder, options);
10224
+ return {
10225
+ address: from,
10226
+ method: callData.asHex()
10227
+ };
10228
+ };
10229
+ const getTransferMethod = type => {
10230
+ switch (type) {
10231
+ case "keep-alive":
10232
+ return "transfer_keep_alive";
10233
+ case "all":
10234
+ return "transfer_all";
10235
+ case "allow-death":
10236
+ return "transfer";
10237
+ }
10238
+ };
10239
+ const getCallDataFromOptions = (builder, options) => {
10240
+ for (const {
10241
+ pallet,
10242
+ method,
10243
+ getArgs
10244
+ } of options) {
10245
+ try {
10246
+ return buildCallData(builder, pallet, method, getArgs());
10247
+ } catch {
10248
+ // wrong inputs, ignore and try the next one
10249
+ }
10250
+ }
10251
+ throw new Error("Failed to encode call data");
10252
+ };
10253
+ const buildCallData = (builder, pallet, method, args) => {
10254
+ const {
10255
+ location,
10256
+ codec
10257
+ } = builder.buildCall(pallet, method);
10258
+ return Binary.fromBytes(mergeUint8([new Uint8Array(location), codec.enc(args)]));
10259
+ };
10260
+ const getCallDataOptions = (to, token, value, type, config) => {
10261
+ const onChainId = papiParse(token.onChainId);
10262
+ const method = getTransferMethod(type);
10263
+ return [{
10264
+ pallet: "Currencies",
10265
+ method: "transfer",
10266
+ getArgs: () => ({
10267
+ dest: Enum("Id", to),
10268
+ currency_id: onChainId,
10269
+ amount: BigInt(value)
10270
+ })
10271
+ }, {
10272
+ pallet: "Currencies",
10273
+ method: "transfer",
10274
+ getArgs: () => ({
10275
+ dest: to,
10276
+ currency_id: onChainId,
10277
+ amount: BigInt(value)
10278
+ })
10279
+ }, {
10280
+ pallet: "Tokens",
10281
+ method,
10282
+ getArgs: () => method === "transfer_all" ? {
10283
+ dest: Enum("Id", to),
10284
+ currency_id: onChainId,
10285
+ keepAlive: false
10286
+ } : {
10287
+ dest: Enum("Id", to),
10288
+ currency_id: onChainId,
10289
+ amount: BigInt(value)
10290
+ }
10291
+ }, {
10292
+ pallet: "Tokens",
10293
+ method,
10294
+ getArgs: () => method === "transfer_all" ? {
10295
+ dest: to,
10296
+ currency_id: onChainId,
10297
+ keepAlive: false
10298
+ } : {
10299
+ dest: to,
10300
+ currency_id: onChainId,
10301
+ amount: BigInt(value)
10302
+ }
10303
+ }].concat(...(config?.palletId ? [{
10304
+ pallet: config.palletId,
10305
+ method,
10306
+ getArgs: () => method === "transfer_all" ? {
10307
+ dest: Enum("Id", to),
10308
+ currency_id: onChainId,
10309
+ keepAlive: false
10310
+ } : {
10311
+ dest: Enum("Id", to),
10312
+ currency_id: onChainId,
10313
+ amount: BigInt(value)
10314
+ }
10315
+ }, {
10316
+ pallet: config.palletId,
10317
+ method,
10318
+ getArgs: () => method === "transfer_all" ? {
10319
+ dest: to,
10320
+ currency_id: onChainId,
10321
+ keepAlive: false
10322
+ } : {
10323
+ dest: to,
10324
+ currency_id: onChainId,
10325
+ amount: BigInt(value)
10326
+ }
10327
+ }] : []));
10328
+ };
10329
+
10330
+ const SUBSCRIPTION_INTERVAL = 6_000;
10331
+ const subscribeBalances = ({
10332
+ networkId,
10333
+ addressesByToken,
10334
+ connector,
10335
+ miniMetadata
10336
+ }) => {
10337
+ return new Observable(subscriber => {
10338
+ const abortController = new AbortController();
10339
+
10340
+ // on hydration balances are fetched using a runtimeApi, which can't be subscribed to.
10341
+ // => poll values for each block
10342
+ const poll = async () => {
10343
+ try {
10344
+ if (abortController.signal.aborted) return;
10345
+ const balances = await fetchBalances({
10346
+ networkId,
10347
+ addressesByToken,
10348
+ connector,
10349
+ miniMetadata
10350
+ });
10351
+ if (abortController.signal.aborted) return;
10352
+ subscriber.next(balances);
10353
+ setTimeout(poll, SUBSCRIPTION_INTERVAL);
10354
+ } catch (error) {
10355
+ log.error("Error", {
10356
+ module: MODULE_TYPE,
10357
+ networkId,
10358
+ miniMetadata,
10359
+ addressesByToken,
10360
+ error
10361
+ });
10362
+ subscriber.error(error);
10363
+ }
10364
+ };
10365
+ poll();
10366
+ return () => {
10367
+ abortController.abort();
10368
+ };
10369
+ }).pipe(distinctUntilChanged(isEqual$1));
10370
+ };
10371
+
10372
+ const SubTokensBalanceModule = {
10373
+ type: MODULE_TYPE,
10374
+ platform: PLATFORM,
10375
+ getMiniMetadata,
10376
+ fetchTokens,
10377
+ fetchBalances,
10378
+ subscribeBalances,
10379
+ getTransferCallData
10380
+ };
10381
+
10382
+ const NEW_BALANCE_MODULES = [SubNativeBalanceModule, SubAssetsBalanceModule, SubHydrationBalanceModule, SubForeignAssetsBalanceModule, SubPsp22BalanceModule, SubTokensBalanceModule, EvmErc20BalanceModule, EvmUniswapV2BalanceModule, EvmNativeBalanceModule];
10383
+
10384
+ export { Balance, BalanceFormatter, BalanceValueGetter, Balances, Change24hCurrencyFormatter, DefaultBalanceModule, EvmErc20Module, EvmErc20TokenConfigSchema, EvmNativeModule, EvmNativeTokenConfigSchema, EvmUniswapV2Module, EvmUniswapV2TokenConfigSchema, FiatSumBalancesFormatter, NEW_BALANCE_MODULES, ONE_ALPHA_TOKEN$1 as ONE_ALPHA_TOKEN, PlanckSumBalancesFormatter, RpcStateQueryHelper, SCALE_FACTOR$1 as SCALE_FACTOR, SUBTENSOR_MIN_STAKE_AMOUNT_PLANK$1 as SUBTENSOR_MIN_STAKE_AMOUNT_PLANK, SUBTENSOR_ROOT_NETUID$1 as SUBTENSOR_ROOT_NETUID, SubAssetsModule, SubAssetsTokenConfigSchema, SubForeignAssetsModule, SubForeignAssetsTokenConfigSchema, SubNativeModule, SubNativeTokenConfigSchema, SubPsp22Module, SubPsp22TokenConfigSchema, SubTokensModule, SubTokensTokenConfigSchema, SumBalancesFormatter, TalismanBalancesDatabase, abiMulticall, balances, buildNetworkStorageCoders, buildStorageCoders, calculateAlphaPrice$1 as calculateAlphaPrice, calculateTaoAmountFromAlpha$1 as calculateTaoAmountFromAlpha, calculateTaoFromDynamicInfo$1 as calculateTaoFromDynamicInfo, compress, configureStore, db, decodeOutput, decompress, defaultBalanceModules, deriveMiniMetadataId, detectTransferMethod, erc20BalancesAggregatorAbi, excludeFromFeePayableLocks, excludeFromTransferableAmount, filterBaseLocks, filterMirrorTokens, getBalanceId, getLockTitle, getUniqueChainIds, getValueId, includeInTotalExtraAmount, makeContractCaller, uniswapV2PairAbi };