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

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
@@ -9,8 +9,8 @@ var BigNumber = require('bignumber.js');
9
9
  var util$1 = require('@polkadot/util');
10
10
  var utilCrypto = require('@polkadot/util-crypto');
11
11
  var pako = require('pako');
12
- var z = require('zod/v4');
13
12
  var viem = require('viem');
13
+ var z = require('zod/v4');
14
14
  var lodash = require('lodash');
15
15
  var isEqual = require('lodash/isEqual');
16
16
  var txwrapperCore = require('@substrate/txwrapper-core');
@@ -73,11 +73,10 @@ const DefaultBalanceModule = type => ({
73
73
  // internal
74
74
  //
75
75
 
76
- var pkg = {
77
- name: "@talismn/balances",
78
- version: "0.0.0-pr2075-20250703111149"};
76
+ var packageJson = {
77
+ name: "@talismn/balances"};
79
78
 
80
- var log = anylogger__default.default(pkg.name);
79
+ var log = anylogger__default.default(packageJson.name);
81
80
 
82
81
  function excludeFromTransferableAmount(locks) {
83
82
  if (typeof locks === "string") return BigInt(locks);
@@ -861,9 +860,8 @@ const getValueId = amount => {
861
860
  const deriveMiniMetadataId = ({
862
861
  source,
863
862
  chainId,
864
- specVersion,
865
- libVersion
866
- }) => util$1.u8aToHex(utilCrypto.xxhashAsU8a(new TextEncoder().encode(`${source}${chainId}${specVersion}${libVersion}`), 64), undefined, false);
863
+ specVersion
864
+ }) => util$1.u8aToHex(utilCrypto.xxhashAsU8a(new TextEncoder().encode(`${source}${chainId}${specVersion}${chaindataProvider.MINIMETADATA_VERSION}`), 64), undefined, false);
867
865
 
868
866
  // for DB version 3, Wallet version 1.21.0
869
867
  const upgradeRemoveSymbolFromNativeTokenId = async tx => {
@@ -962,234 +960,6 @@ const TokenConfigBaseSchema = chaindataProvider.TokenBaseSchema.partial().omit({
962
960
  id: true
963
961
  });
964
962
 
965
- const erc20Abi = [{
966
- constant: true,
967
- inputs: [],
968
- name: "name",
969
- outputs: [{
970
- name: "",
971
- type: "string"
972
- }],
973
- payable: false,
974
- stateMutability: "view",
975
- type: "function"
976
- }, {
977
- constant: false,
978
- inputs: [{
979
- name: "_spender",
980
- type: "address"
981
- }, {
982
- name: "_value",
983
- type: "uint256"
984
- }],
985
- name: "approve",
986
- outputs: [{
987
- name: "",
988
- type: "bool"
989
- }],
990
- payable: false,
991
- stateMutability: "nonpayable",
992
- type: "function"
993
- }, {
994
- constant: true,
995
- inputs: [],
996
- name: "totalSupply",
997
- outputs: [{
998
- name: "",
999
- type: "uint256"
1000
- }],
1001
- payable: false,
1002
- stateMutability: "view",
1003
- type: "function"
1004
- }, {
1005
- constant: false,
1006
- inputs: [{
1007
- name: "_from",
1008
- type: "address"
1009
- }, {
1010
- name: "_to",
1011
- type: "address"
1012
- }, {
1013
- name: "_value",
1014
- type: "uint256"
1015
- }],
1016
- name: "transferFrom",
1017
- outputs: [{
1018
- name: "",
1019
- type: "bool"
1020
- }],
1021
- payable: false,
1022
- stateMutability: "nonpayable",
1023
- type: "function"
1024
- }, {
1025
- constant: true,
1026
- inputs: [],
1027
- name: "decimals",
1028
- outputs: [{
1029
- name: "",
1030
- type: "uint8"
1031
- }],
1032
- payable: false,
1033
- stateMutability: "view",
1034
- type: "function"
1035
- }, {
1036
- constant: false,
1037
- inputs: [{
1038
- name: "_to",
1039
- type: "address"
1040
- }, {
1041
- name: "_value",
1042
- type: "uint256"
1043
- }, {
1044
- name: "_data",
1045
- type: "bytes"
1046
- }],
1047
- name: "transferAndCall",
1048
- outputs: [{
1049
- name: "success",
1050
- type: "bool"
1051
- }],
1052
- payable: false,
1053
- stateMutability: "nonpayable",
1054
- type: "function"
1055
- }, {
1056
- constant: false,
1057
- inputs: [{
1058
- name: "_spender",
1059
- type: "address"
1060
- }, {
1061
- name: "_subtractedValue",
1062
- type: "uint256"
1063
- }],
1064
- name: "decreaseApproval",
1065
- outputs: [{
1066
- name: "success",
1067
- type: "bool"
1068
- }],
1069
- payable: false,
1070
- stateMutability: "nonpayable",
1071
- type: "function"
1072
- }, {
1073
- constant: true,
1074
- inputs: [{
1075
- name: "_owner",
1076
- type: "address"
1077
- }],
1078
- name: "balanceOf",
1079
- outputs: [{
1080
- name: "balance",
1081
- type: "uint256"
1082
- }],
1083
- payable: false,
1084
- stateMutability: "view",
1085
- type: "function"
1086
- }, {
1087
- constant: true,
1088
- inputs: [],
1089
- name: "symbol",
1090
- outputs: [{
1091
- name: "",
1092
- type: "string"
1093
- }],
1094
- payable: false,
1095
- stateMutability: "view",
1096
- type: "function"
1097
- }, {
1098
- constant: false,
1099
- inputs: [{
1100
- name: "_to",
1101
- type: "address"
1102
- }, {
1103
- name: "_value",
1104
- type: "uint256"
1105
- }],
1106
- name: "transfer",
1107
- outputs: [{
1108
- name: "success",
1109
- type: "bool"
1110
- }],
1111
- payable: false,
1112
- stateMutability: "nonpayable",
1113
- type: "function"
1114
- }, {
1115
- constant: false,
1116
- inputs: [{
1117
- name: "_spender",
1118
- type: "address"
1119
- }, {
1120
- name: "_addedValue",
1121
- type: "uint256"
1122
- }],
1123
- name: "increaseApproval",
1124
- outputs: [{
1125
- name: "success",
1126
- type: "bool"
1127
- }],
1128
- payable: false,
1129
- stateMutability: "nonpayable",
1130
- type: "function"
1131
- }, {
1132
- constant: true,
1133
- inputs: [{
1134
- name: "_owner",
1135
- type: "address"
1136
- }, {
1137
- name: "_spender",
1138
- type: "address"
1139
- }],
1140
- name: "allowance",
1141
- outputs: [{
1142
- name: "remaining",
1143
- type: "uint256"
1144
- }],
1145
- payable: false,
1146
- stateMutability: "view",
1147
- type: "function"
1148
- }, {
1149
- inputs: [],
1150
- payable: false,
1151
- stateMutability: "nonpayable",
1152
- type: "constructor"
1153
- }, {
1154
- anonymous: false,
1155
- inputs: [{
1156
- indexed: true,
1157
- name: "from",
1158
- type: "address"
1159
- }, {
1160
- indexed: true,
1161
- name: "to",
1162
- type: "address"
1163
- }, {
1164
- indexed: false,
1165
- name: "value",
1166
- type: "uint256"
1167
- }, {
1168
- indexed: false,
1169
- name: "data",
1170
- type: "bytes"
1171
- }],
1172
- name: "Transfer",
1173
- type: "event"
1174
- }, {
1175
- anonymous: false,
1176
- inputs: [{
1177
- indexed: true,
1178
- name: "owner",
1179
- type: "address"
1180
- }, {
1181
- indexed: true,
1182
- name: "spender",
1183
- type: "address"
1184
- }, {
1185
- indexed: false,
1186
- name: "value",
1187
- type: "uint256"
1188
- }],
1189
- name: "Approval",
1190
- type: "event"
1191
- }];
1192
-
1193
963
  const erc20BalancesAggregatorAbi = viem.parseAbi(["struct AccountToken {address account; address token;}", "function balances(AccountToken[] memory accountTokens) public view returns (uint256[] memory)"]);
1194
964
 
1195
965
  const moduleType$7 = "evm-erc20";
@@ -1345,7 +1115,7 @@ const EvmErc20Module = hydrate => {
1345
1115
  const {
1346
1116
  errors,
1347
1117
  results
1348
- } = await fetchBalances$3(chainConnectors.evm, {
1118
+ } = await fetchBalances$c(chainConnectors.evm, {
1349
1119
  [evmNetworkId]: fetchesPerNetwork[evmNetworkId]
1350
1120
  }, aggregators);
1351
1121
 
@@ -1403,7 +1173,7 @@ const EvmErc20Module = hydrate => {
1403
1173
  if (!chainConnectors.evm) throw new Error(`This module requires an evm chain connector`);
1404
1174
  const [aggregators, tokens] = await Promise.all([getErc20Aggregators(), getModuleTokens()]);
1405
1175
  const fetchesPerNetwork = await prepareFetchParameters(addressesByToken, tokens);
1406
- const balances = await fetchBalances$3(chainConnectors.evm, fetchesPerNetwork, aggregators);
1176
+ const balances = await fetchBalances$c(chainConnectors.evm, fetchesPerNetwork, aggregators);
1407
1177
  return new Balances(balances.results);
1408
1178
  }
1409
1179
  };
@@ -1425,7 +1195,7 @@ class EvmErc20NetworkError extends Error {
1425
1195
  this.evmNetworkId = evmNetworkId;
1426
1196
  }
1427
1197
  }
1428
- const fetchBalances$3 = async (evmChainConnector, tokenAddressesByNetwork, erc20Aggregators = {}) => {
1198
+ const fetchBalances$c = async (evmChainConnector, tokenAddressesByNetwork, erc20Aggregators = {}) => {
1429
1199
  const result = {
1430
1200
  results: [],
1431
1201
  errors: []
@@ -1458,7 +1228,7 @@ const getEvmTokenBalancesWithoutAggregator = async (client, balanceDefs, errors)
1458
1228
  }) => {
1459
1229
  try {
1460
1230
  const balance = await client.readContract({
1461
- abi: erc20Abi,
1231
+ abi: viem.erc20Abi,
1462
1232
  address: token.contractAddress,
1463
1233
  functionName: "balanceOf",
1464
1234
  args: [address]
@@ -1600,7 +1370,7 @@ const EvmNativeModule = hydrate => {
1600
1370
  if (!tokenId) throw new Error(`No native token for evm network ${evmNetworkId}`);
1601
1371
  try {
1602
1372
  if (!chainConnectors.evm) throw new Error(`This module requires an evm chain connector`);
1603
- const balances = await fetchBalances$2(chainConnectors.evm, {
1373
+ const balances = await fetchBalances$b(chainConnectors.evm, {
1604
1374
  [tokenId]: addresses
1605
1375
  }, tokens);
1606
1376
  const resultBalances = [];
@@ -1642,7 +1412,7 @@ const EvmNativeModule = hydrate => {
1642
1412
  async fetchBalances(addressesByToken) {
1643
1413
  if (!chainConnectors.evm) throw new Error(`This module requires an evm chain connector`);
1644
1414
  const tokens = await getModuleTokens();
1645
- const balanceResults = await fetchBalances$2(chainConnectors.evm, addressesByToken, tokens);
1415
+ const balanceResults = await fetchBalances$b(chainConnectors.evm, addressesByToken, tokens);
1646
1416
  const pureBalances = balanceResults.flat().filter(b => !(b instanceof EvmNativeBalanceError) && BigInt(b.value) > 0n);
1647
1417
  return new Balances(pureBalances);
1648
1418
  }
@@ -1658,7 +1428,7 @@ class EvmNativeBalanceError extends Error {
1658
1428
  }
1659
1429
  }
1660
1430
  }
1661
- const fetchBalances$2 = async (evmChainConnector, addressesByToken, tokens) => {
1431
+ const fetchBalances$b = async (evmChainConnector, addressesByToken, tokens) => {
1662
1432
  if (!evmChainConnector) throw new Error(`This module requires an evm chain connector`);
1663
1433
  return Promise.all(Object.entries(addressesByToken).map(async ([tokenId, addresses]) => {
1664
1434
  const token = tokens[tokenId];
@@ -2410,7 +2180,7 @@ const EvmUniswapV2Module = hydrate => {
2410
2180
  }
2411
2181
  try {
2412
2182
  if (!chainConnectors.evm) throw new Error(`This module requires an evm chain connector`);
2413
- const balances = await fetchBalances$1(chainConnectors.evm, evmNetworks, tokens, addressesByToken);
2183
+ const balances = await fetchBalances$a(chainConnectors.evm, evmNetworks, tokens, addressesByToken);
2414
2184
 
2415
2185
  // Don't call callback with balances which have not changed since the last poll.
2416
2186
  const json = balances.toJSON();
@@ -2439,11 +2209,11 @@ const EvmUniswapV2Module = hydrate => {
2439
2209
  if (!chainConnectors.evm) throw new Error(`This module requires an evm chain connector`);
2440
2210
  const evmNetworks = await chaindataProvider$1.getNetworksMapById("ethereum");
2441
2211
  const tokens = await chaindataProvider$1.getTokensMapById();
2442
- return fetchBalances$1(chainConnectors.evm, evmNetworks, tokens, addressesByToken);
2212
+ return fetchBalances$a(chainConnectors.evm, evmNetworks, tokens, addressesByToken);
2443
2213
  }
2444
2214
  };
2445
2215
  };
2446
- const fetchBalances$1 = async (evmChainConnector, evmNetworks, tokens, addressesByToken) => {
2216
+ const fetchBalances$a = async (evmChainConnector, evmNetworks, tokens, addressesByToken) => {
2447
2217
  const addressesByTokenGroupedByEvmNetwork = groupAddressesByTokenByEvmNetwork(addressesByToken, tokens);
2448
2218
  const balances = (await Promise.allSettled(Object.entries(addressesByTokenGroupedByEvmNetwork).map(async ([networkId, addressesByToken]) => {
2449
2219
  if (!evmChainConnector) throw new Error(`This module requires an evm chain connector`);
@@ -2583,8 +2353,6 @@ async function getPoolBalance(publicClient, contractAddress, accountAddress) {
2583
2353
  }
2584
2354
  }
2585
2355
 
2586
- const libVersion = pkg.version;
2587
-
2588
2356
  // cache the promise so it can be shared across multiple calls
2589
2357
  const CACHE_GET_SPEC_VERSION = new Map();
2590
2358
  const fetchSpecVersion = async (chainConnector, networkId) => {
@@ -2660,7 +2428,7 @@ const getMiniMetadatas = async (chainConnector, chaindataProvider, networkId, sp
2660
2428
  }
2661
2429
  };
2662
2430
  const DotBalanceModuleTypeSchema = z__default.default.keyof(chaindataProvider.DotNetworkBalancesConfigSchema);
2663
- const fetchMiniMetadatas = async (chainConnector, chaindataProvider, chainId, specVersion, signal) => {
2431
+ const fetchMiniMetadatas = async (chainConnector, chaindataProvider$1, chainId, specVersion, signal) => {
2664
2432
  const start = performance.now();
2665
2433
  log.info("[miniMetadata] fetching minimetadatas for %s", chainId);
2666
2434
  try {
@@ -2672,11 +2440,11 @@ const fetchMiniMetadatas = async (chainConnector, chaindataProvider, chainId, sp
2672
2440
  };
2673
2441
  const modules = defaultBalanceModules.map(mod => mod({
2674
2442
  chainConnectors,
2675
- chaindataProvider
2443
+ chaindataProvider: chaindataProvider$1
2676
2444
  })).filter(mod => DotBalanceModuleTypeSchema.safeParse(mod.type).success);
2677
2445
  return Promise.all(modules.map(async mod => {
2678
2446
  const source = mod.type;
2679
- const chain = await chaindataProvider.getNetworkById(chainId, "polkadot");
2447
+ const chain = await chaindataProvider$1.getNetworkById(chainId, "polkadot");
2680
2448
  const balancesConfig = chain?.balancesConfig?.[mod.type];
2681
2449
  const chainMeta = await mod.fetchSubstrateChainMeta(chainId, balancesConfig,
2682
2450
  // TODO better typing
@@ -2685,13 +2453,12 @@ const fetchMiniMetadatas = async (chainConnector, chaindataProvider, chainId, sp
2685
2453
  id: deriveMiniMetadataId({
2686
2454
  source,
2687
2455
  chainId,
2688
- specVersion,
2689
- libVersion
2456
+ specVersion
2690
2457
  }),
2691
2458
  source,
2692
2459
  chainId,
2693
2460
  specVersion,
2694
- libVersion,
2461
+ version: chaindataProvider.MINIMETADATA_VERSION,
2695
2462
  data: chainMeta?.miniMetadata ?? null,
2696
2463
  extra: chainMeta?.extra ?? null
2697
2464
  };
@@ -2713,24 +2480,23 @@ const getUpdatedMiniMetadatas = async (chainConnector, chaindataProvider, chainI
2713
2480
  return miniMetadatas;
2714
2481
  };
2715
2482
 
2716
- const getMiniMetadata = async (chaindataProvider, chainConnector, chainId, source, signal) => {
2483
+ const getMiniMetadata$9 = async (chaindataProvider$1, chainConnector, chainId, source, signal) => {
2717
2484
  const specVersion = await getSpecVersion(chainConnector, chainId);
2718
2485
  signal?.throwIfAborted();
2719
2486
  const miniMetadataId = deriveMiniMetadataId({
2720
2487
  source,
2721
2488
  chainId,
2722
- specVersion,
2723
- libVersion
2489
+ specVersion
2724
2490
  });
2725
2491
 
2726
2492
  // lookup local ones
2727
- const [dbMiniMetadata, ghMiniMetadata] = await Promise.all([db.miniMetadatas.get(miniMetadataId), chaindataProvider.miniMetadataById(miniMetadataId)]);
2493
+ const [dbMiniMetadata, ghMiniMetadata] = await Promise.all([db.miniMetadatas.get(miniMetadataId), chaindataProvider$1.miniMetadataById(miniMetadataId)]);
2728
2494
  signal?.throwIfAborted();
2729
2495
  const miniMetadata = dbMiniMetadata ?? ghMiniMetadata;
2730
2496
  if (miniMetadata) return miniMetadata;
2731
2497
 
2732
2498
  // update from live chain metadata and persist locally
2733
- const miniMetadatas = await getUpdatedMiniMetadatas(chainConnector, chaindataProvider, chainId, specVersion, signal);
2499
+ const miniMetadatas = await getUpdatedMiniMetadatas(chainConnector, chaindataProvider$1, chainId, specVersion, signal);
2734
2500
  signal?.throwIfAborted();
2735
2501
  const found = miniMetadatas.find(m => m.id === miniMetadataId);
2736
2502
  if (!found) {
@@ -2738,7 +2504,7 @@ const getMiniMetadata = async (chaindataProvider, chainConnector, chainId, sourc
2738
2504
  source,
2739
2505
  chainId,
2740
2506
  specVersion,
2741
- libVersion,
2507
+ version: chaindataProvider.MINIMETADATA_VERSION,
2742
2508
  miniMetadataId,
2743
2509
  miniMetadatas
2744
2510
  });
@@ -2794,6 +2560,8 @@ const buildStorageCoders = ({
2794
2560
  return [];
2795
2561
  }
2796
2562
  }));
2563
+ // type StorageCoder<TCoders extends NetworkCoders> = ReturnType<ReturnType<typeof getDynamicBuilder>["buildStorage"]>[keyof TCoders]
2564
+
2797
2565
  const buildNetworkStorageCoders = (chainId, miniMetadata, coders) => {
2798
2566
  if (!miniMetadata.data) return null;
2799
2567
  const metadata = scale.unifyMetadata(scale.decAnyMetadata(miniMetadata.data));
@@ -3052,8 +2820,8 @@ const SubAssetsModule = hydrate => {
3052
2820
  for (const tokenConfig of tokens ?? []) {
3053
2821
  try {
3054
2822
  const assetId = String(tokenConfig.assetId);
3055
- const assetStateKey = tryEncode(assetCoder, BigInt(assetId)) ?? tryEncode(assetCoder, assetId);
3056
- const metadataStateKey = tryEncode(metadataCoder, BigInt(assetId)) ?? tryEncode(metadataCoder, assetId);
2823
+ const assetStateKey = tryEncode$1(assetCoder, BigInt(assetId)) ?? tryEncode$1(assetCoder, assetId);
2824
+ const metadataStateKey = tryEncode$1(metadataCoder, BigInt(assetId)) ?? tryEncode$1(metadataCoder, assetId);
3057
2825
  if (assetStateKey === null || metadataStateKey === null) throw new Error(`Failed to encode stateKey for asset ${assetId} on chain ${chainId}`);
3058
2826
  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)]);
3059
2827
  const existentialDeposit = assetsAsset?.min_balance?.toString?.() ?? "0";
@@ -3073,6 +2841,7 @@ const SubAssetsModule = hydrate => {
3073
2841
  logo: tokenConfig?.logo,
3074
2842
  existentialDeposit,
3075
2843
  assetId,
2844
+ isSufficient: false,
3076
2845
  isFrozen,
3077
2846
  networkId: chainId
3078
2847
  };
@@ -3125,7 +2894,7 @@ const SubAssetsModule = hydrate => {
3125
2894
  },
3126
2895
  async fetchBalances(addressesByToken) {
3127
2896
  util$1.assert(chainConnectors.substrate, "This module requires a substrate chain connector");
3128
- const queries = await buildQueries$3(chainConnector, chaindataProvider$1, addressesByToken);
2897
+ const queries = await buildQueries$6(chainConnector, chaindataProvider$1, addressesByToken);
3129
2898
  const result = await new RpcStateQueryHelper(chainConnectors.substrate, queries).fetch();
3130
2899
  const balances = result?.filter(b => b !== null) ?? [];
3131
2900
  return new Balances(balances);
@@ -3195,7 +2964,7 @@ const SubAssetsModule = hydrate => {
3195
2964
  };
3196
2965
  };
3197
2966
  async function buildNetworkQueries$2(networkId, chainConnector, chaindataProvider, addressesByToken, signal) {
3198
- const miniMetadata = await getMiniMetadata(chaindataProvider, chainConnector, networkId, moduleType$4, signal);
2967
+ const miniMetadata = await getMiniMetadata$9(chaindataProvider, chainConnector, networkId, moduleType$4, signal);
3199
2968
  const chain = await chaindataProvider.getNetworkById(networkId, "polkadot");
3200
2969
  const tokensById = await chaindataProvider.getTokensMapById();
3201
2970
  signal?.throwIfAborted();
@@ -3219,7 +2988,7 @@ async function buildNetworkQueries$2(networkId, chainConnector, chaindataProvide
3219
2988
  }
3220
2989
  return addresses.flatMap(address => {
3221
2990
  const scaleCoder = networkStorageCoders?.storage;
3222
- const stateKey = tryEncode(scaleCoder, Number(token.assetId), address) ?? tryEncode(scaleCoder, BigInt(token.assetId), address);
2991
+ const stateKey = tryEncode$1(scaleCoder, Number(token.assetId), address) ?? tryEncode$1(scaleCoder, BigInt(token.assetId), address);
3223
2992
  if (!stateKey) {
3224
2993
  log.warn(`Invalid assetId / address in ${networkId} storage query ${token.assetId} / ${address}`);
3225
2994
  return [];
@@ -3274,7 +3043,7 @@ async function buildNetworkQueries$2(networkId, chainConnector, chaindataProvide
3274
3043
  });
3275
3044
  });
3276
3045
  }
3277
- async function buildQueries$3(chainConnector, chaindataProvider$1, addressesByToken, signal) {
3046
+ async function buildQueries$6(chainConnector, chaindataProvider$1, addressesByToken, signal) {
3278
3047
  const byNetwork = lodash.keys(addressesByToken).reduce((acc, tokenId) => {
3279
3048
  const networkId = chaindataProvider.parseSubAssetTokenId(tokenId).networkId;
3280
3049
  if (!acc[networkId]) acc[networkId] = {};
@@ -3289,7 +3058,7 @@ async function buildQueries$3(chainConnector, chaindataProvider$1, addressesByTo
3289
3058
  // E.g. Polkadot Asset Hub needs it to be a string, Astar needs it to be a bigint
3290
3059
  //
3291
3060
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
3292
- const tryEncode = (scaleCoder, ...args) => {
3061
+ const tryEncode$1 = (scaleCoder, ...args) => {
3293
3062
  try {
3294
3063
  return scaleCoder?.keys?.enc?.(...args);
3295
3064
  } catch {
@@ -3372,6 +3141,7 @@ const SubForeignAssetsModule = hydrate => {
3372
3141
  logo: tokenConfig?.logo,
3373
3142
  existentialDeposit,
3374
3143
  onChainId: tokenConfig.onChainId,
3144
+ isSufficient: assetsAsset?.is_sufficient ?? false,
3375
3145
  isFrozen,
3376
3146
  networkId: chainId
3377
3147
  };
@@ -3420,7 +3190,7 @@ const SubForeignAssetsModule = hydrate => {
3420
3190
  },
3421
3191
  async fetchBalances(addressesByToken) {
3422
3192
  util$1.assert(chainConnectors.substrate, "This module requires a substrate chain connector");
3423
- const queries = await buildQueries$2(chainConnector, chaindataProvider$1, addressesByToken);
3193
+ const queries = await buildQueries$5(chainConnector, chaindataProvider$1, addressesByToken);
3424
3194
  const result = await new RpcStateQueryHelper(chainConnectors.substrate, queries).fetch();
3425
3195
  const balances = result?.filter(b => b !== null) ?? [];
3426
3196
  return new Balances(balances);
@@ -3476,7 +3246,7 @@ const SubForeignAssetsModule = hydrate => {
3476
3246
  };
3477
3247
  };
3478
3248
  async function buildNetworkQueries$1(networkId, chainConnector, chaindataProvider, addressesByToken, signal) {
3479
- const miniMetadata = await getMiniMetadata(chaindataProvider, chainConnector, networkId, moduleType$3, signal);
3249
+ const miniMetadata = await getMiniMetadata$9(chaindataProvider, chainConnector, networkId, moduleType$3, signal);
3480
3250
  const chain = await chaindataProvider.getNetworkById(networkId, "polkadot");
3481
3251
  const tokensById = await chaindataProvider.getTokensMapById();
3482
3252
  signal?.throwIfAborted();
@@ -3558,7 +3328,7 @@ async function buildNetworkQueries$1(networkId, chainConnector, chaindataProvide
3558
3328
  });
3559
3329
  });
3560
3330
  }
3561
- async function buildQueries$2(chainConnector, chaindataProvider$1, addressesByToken, signal) {
3331
+ async function buildQueries$5(chainConnector, chaindataProvider$1, addressesByToken, signal) {
3562
3332
  const byNetwork = lodash.keys(addressesByToken).reduce((acc, tokenId) => {
3563
3333
  const networkId = chaindataProvider.parseSubForeignAssetTokenId(tokenId).networkId;
3564
3334
  if (!acc[networkId]) acc[networkId] = {};
@@ -3612,7 +3382,7 @@ const asObservable = handler => (...args) => new rxjs.Observable(subscriber => {
3612
3382
  * Each nominationPool in the nominationPools pallet has access to some accountIds which have no
3613
3383
  * associated private key. Instead, they are derived from this function.
3614
3384
  */
3615
- const nompoolAccountId = (palletId, poolId, index) => {
3385
+ const nompoolAccountId$1 = (palletId, poolId, index) => {
3616
3386
  const utf8Encoder = new TextEncoder();
3617
3387
  const encModPrefix = utf8Encoder.encode("modl");
3618
3388
  const encPalletId = utf8Encoder.encode(palletId);
@@ -3625,7 +3395,7 @@ const nompoolAccountId = (palletId, poolId, index) => {
3625
3395
  return polkadotApi.AccountId().dec(bytes);
3626
3396
  };
3627
3397
  /** The stash account for the nomination pool */
3628
- const nompoolStashAccountId = (palletId, poolId) => nompoolAccountId(palletId, poolId, 0);
3398
+ const nompoolStashAccountId$1 = (palletId, poolId) => nompoolAccountId$1(palletId, poolId, 0);
3629
3399
 
3630
3400
  // TODO make this method chain-specific
3631
3401
  async function subscribeNompoolStaking(chaindataProvider$1, chainConnector, addressesByToken, callback, signal) {
@@ -3637,7 +3407,7 @@ async function subscribeNompoolStaking(chaindataProvider$1, chainConnector, addr
3637
3407
  const networkIds = lodash.keys(addressesByToken).map(tokenId => chaindataProvider.parseTokenId(tokenId).networkId);
3638
3408
  const miniMetadatas = new Map();
3639
3409
  for (const networkId of networkIds) {
3640
- const miniMetadata = await getMiniMetadata(chaindataProvider$1, chainConnector, networkId, "substrate-native");
3410
+ const miniMetadata = await getMiniMetadata$9(chaindataProvider$1, chainConnector, networkId, "substrate-native");
3641
3411
  miniMetadatas.set(networkId, miniMetadata);
3642
3412
  }
3643
3413
  signal?.throwIfAborted();
@@ -3763,7 +3533,7 @@ async function subscribeNompoolStaking(chaindataProvider$1, chainConnector, addr
3763
3533
  const scaleCoder = chainStorageCoders.get(chainId)?.ledger;
3764
3534
  const queries = poolIds.flatMap(poolId => {
3765
3535
  if (!nominationPoolsPalletId) return [];
3766
- const stashAddress = nompoolStashAccountId(nominationPoolsPalletId, poolId);
3536
+ const stashAddress = nompoolStashAccountId$1(nominationPoolsPalletId, poolId);
3767
3537
  const stateKey = scale.encodeStateKey(scaleCoder, `Invalid address in ${chainId} ledger query ${stashAddress}`, stashAddress);
3768
3538
  if (!stateKey) return [];
3769
3539
  const decodeResult = change => {
@@ -3916,12 +3686,12 @@ async function subscribeNompoolStaking(chaindataProvider$1, chainConnector, addr
3916
3686
  }
3917
3687
  }
3918
3688
 
3919
- const SUBTENSOR_ROOT_NETUID = 0;
3920
- const SUBTENSOR_MIN_STAKE_AMOUNT_PLANK = 1000000n;
3921
- const TAO_DECIMALS = 9n;
3922
- const SCALE_FACTOR = 10n ** TAO_DECIMALS; // Equivalent to 10e9 for precision
3923
- const ONE_ALPHA_TOKEN = SCALE_FACTOR;
3924
- const calculateAlphaPrice = ({
3689
+ const SUBTENSOR_ROOT_NETUID$1 = 0;
3690
+ const SUBTENSOR_MIN_STAKE_AMOUNT_PLANK$1 = 1000000n;
3691
+ const TAO_DECIMALS$1 = 9n;
3692
+ const SCALE_FACTOR$1 = 10n ** TAO_DECIMALS$1; // Equivalent to 10e9 for precision
3693
+ const ONE_ALPHA_TOKEN$1 = SCALE_FACTOR$1;
3694
+ const calculateAlphaPrice$1 = ({
3925
3695
  dynamicInfo
3926
3696
  }) => {
3927
3697
  if (!dynamicInfo) return 0n;
@@ -3931,25 +3701,25 @@ const calculateAlphaPrice = ({
3931
3701
  } = dynamicInfo;
3932
3702
 
3933
3703
  // Scale taoIn before division to preserve precision
3934
- const result = tao_in * SCALE_FACTOR / alpha_in;
3704
+ const result = tao_in * SCALE_FACTOR$1 / alpha_in;
3935
3705
  return result; // Scaled price as bigint
3936
3706
  };
3937
- const calculateTaoAmountFromAlpha = ({
3707
+ const calculateTaoAmountFromAlpha$1 = ({
3938
3708
  alphaPrice,
3939
3709
  alphaStaked
3940
3710
  }) => {
3941
3711
  if (!alphaStaked || !alphaPrice) return 0n;
3942
3712
  const expectedAlpha = alphaStaked * alphaPrice;
3943
- return expectedAlpha / SCALE_FACTOR;
3713
+ return expectedAlpha / SCALE_FACTOR$1;
3944
3714
  };
3945
- const calculateTaoFromDynamicInfo = ({
3715
+ const calculateTaoFromDynamicInfo$1 = ({
3946
3716
  dynamicInfo,
3947
3717
  alphaStaked
3948
3718
  }) => {
3949
- const alphaPrice = calculateAlphaPrice({
3719
+ const alphaPrice = calculateAlphaPrice$1({
3950
3720
  dynamicInfo
3951
3721
  });
3952
- return calculateTaoAmountFromAlpha({
3722
+ return calculateTaoAmountFromAlpha$1({
3953
3723
  alphaPrice,
3954
3724
  alphaStaked
3955
3725
  });
@@ -3965,7 +3735,7 @@ async function subscribeSubtensorStaking(chaindataProvider$1, chainConnector, ad
3965
3735
  const networkIds = lodash.keys(addressesByToken).map(tokenId => chaindataProvider.parseTokenId(tokenId).networkId);
3966
3736
  const miniMetadatas = new Map();
3967
3737
  for (const networkId of networkIds) {
3968
- const miniMetadata = await getMiniMetadata(chaindataProvider$1, chainConnector, networkId, "substrate-native", signal);
3738
+ const miniMetadata = await getMiniMetadata$9(chaindataProvider$1, chainConnector, networkId, "substrate-native", signal);
3969
3739
  miniMetadatas.set(networkId, miniMetadata);
3970
3740
  }
3971
3741
  signal?.throwIfAborted();
@@ -4056,7 +3826,7 @@ async function subscribeSubtensorStaking(chaindataProvider$1, chainConnector, ad
4056
3826
  const params = [address];
4057
3827
  const result = await scaleApi.getRuntimeCallValue("StakeInfoRuntimeApi", "get_stake_info_for_coldkey", params);
4058
3828
  if (!Array.isArray(result)) return [];
4059
- const uniqueNetuids = Array.from(new Set(result.map(item => Number(item.netuid)).filter(netuid => netuid !== SUBTENSOR_ROOT_NETUID)));
3829
+ const uniqueNetuids = Array.from(new Set(result.map(item => Number(item.netuid)).filter(netuid => netuid !== SUBTENSOR_ROOT_NETUID$1)));
4060
3830
  await fetchDynamicInfoForNetuids(uniqueNetuids);
4061
3831
  const stakes = result?.map(({
4062
3832
  coldkey,
@@ -4073,7 +3843,7 @@ async function subscribeSubtensorStaking(chaindataProvider$1, chainConnector, ad
4073
3843
  };
4074
3844
  }).filter(({
4075
3845
  stake
4076
- }) => stake >= SUBTENSOR_MIN_STAKE_AMOUNT_PLANK);
3846
+ }) => stake >= SUBTENSOR_MIN_STAKE_AMOUNT_PLANK$1);
4077
3847
  return stakes;
4078
3848
  }];
4079
3849
  const errors = [];
@@ -4119,15 +3889,15 @@ async function subscribeSubtensorStaking(chaindataProvider$1, chainConnector, ad
4119
3889
  const subnetIdentity = subnet_identity ? binaryToText(subnet_identity) : undefined;
4120
3890
 
4121
3891
  // Add 1n balance if failed to fetch dynamic info, so the position is not ignored by Balance lib and is displayed in the UI.
4122
- const alphaStakedInTao = dynamicInfo ? calculateTaoFromDynamicInfo({
3892
+ const alphaStakedInTao = dynamicInfo ? calculateTaoFromDynamicInfo$1({
4123
3893
  dynamicInfo,
4124
3894
  alphaStaked: stake
4125
3895
  }) : 1n;
4126
- const alphaToTaoRate = calculateTaoFromDynamicInfo({
3896
+ const alphaToTaoRate = calculateTaoFromDynamicInfo$1({
4127
3897
  dynamicInfo: dynamicInfo ?? null,
4128
- alphaStaked: ONE_ALPHA_TOKEN
3898
+ alphaStaked: ONE_ALPHA_TOKEN$1
4129
3899
  }).toString();
4130
- const stakeByNetuid = Number(netuid) === SUBTENSOR_ROOT_NETUID ? stake : alphaStakedInTao;
3900
+ const stakeByNetuid = Number(netuid) === SUBTENSOR_ROOT_NETUID$1 ? stake : alphaStakedInTao;
4131
3901
  return {
4132
3902
  source: "substrate-native",
4133
3903
  status: "live",
@@ -4187,14 +3957,14 @@ async function subscribeSubtensorStaking(chaindataProvider$1, chainConnector, ad
4187
3957
  }
4188
3958
  }
4189
3959
 
4190
- const getOtherType = input => `other-${input}`;
3960
+ const getOtherType$1 = input => `other-${input}`;
4191
3961
 
4192
3962
  /**
4193
3963
  * For converting the value of `lock?.id?.toUtf8?.()` which is retrieved from
4194
3964
  * the Balances.Locks storage key into a useful classification for our UI
4195
3965
  */
4196
- const getLockedType = input => {
4197
- if (typeof input !== "string") return getOtherType("unknown");
3966
+ const getLockedType$1 = input => {
3967
+ if (typeof input !== "string") return getOtherType$1("unknown");
4198
3968
  if (input.includes("vesting")) return "vesting";
4199
3969
  if (input.includes("calamvst")) return "vesting"; // vesting on manta network
4200
3970
  if (input.includes("ormlvest")) return "vesting"; // vesting ORML tokens
@@ -4216,19 +3986,19 @@ const getLockedType = input => {
4216
3986
  if (input.includes("councilo")) return "democracy"; // Councilor
4217
3987
  if (input.includes("proposal")) return "democracy";
4218
3988
  if (input.includes("boundsta")) return "staking"; // Bound Staking Account
4219
- if (input.includes("invitemb")) return getOtherType(input); // Invite member
4220
- if (input.includes("bounty")) return getOtherType(input);
4221
- if (input.startsWith("wg-")) return getOtherType(input);
3989
+ if (input.includes("invitemb")) return getOtherType$1(input); // Invite member
3990
+ if (input.includes("bounty")) return getOtherType$1(input);
3991
+ if (input.startsWith("wg-")) return getOtherType$1(input);
4222
3992
 
4223
3993
  // ignore technical or undocumented lock types
4224
- if (input.includes("pdexlock")) return getOtherType(input);
4225
- if (input.includes("phala/sp")) return getOtherType(input);
4226
- if (input.includes("aca/earn")) return getOtherType(input);
4227
- if (input.includes("stk_stks")) return getOtherType(input);
3994
+ if (input.includes("pdexlock")) return getOtherType$1(input);
3995
+ if (input.includes("phala/sp")) return getOtherType$1(input);
3996
+ if (input.includes("aca/earn")) return getOtherType$1(input);
3997
+ if (input.includes("stk_stks")) return getOtherType$1(input);
4228
3998
 
4229
3999
  // eslint-disable-next-line no-console
4230
4000
  console.warn(`unknown locked type: ${input}`);
4231
- return getOtherType(input);
4001
+ return getOtherType$1(input);
4232
4002
  };
4233
4003
  const baseLockLabels = ["fees", "misc"];
4234
4004
  const isBaseLock = lock => baseLockLabels.includes(lock.label);
@@ -4325,7 +4095,7 @@ const AccountInfoOverrides = {
4325
4095
  // nftmart is not yet on metadata v14
4326
4096
  "nftmart": RegularAccountInfoFallback
4327
4097
  };
4328
- async function buildQueries$1(chains, tokens, chainStorageCoders, miniMetadatas, addressesByToken) {
4098
+ async function buildQueries$4(chains, tokens, chainStorageCoders, miniMetadatas, addressesByToken) {
4329
4099
  return Object.entries(addressesByToken).reduce((outerResult, [tokenId, addresses]) => {
4330
4100
  const token = tokens[tokenId];
4331
4101
  if (!token) {
@@ -4457,7 +4227,7 @@ async function buildQueries$1(chains, tokens, chainStorageCoders, miniMetadatas,
4457
4227
  locksQueryLocks = decoded?.map?.(lock => ({
4458
4228
  type: "locked",
4459
4229
  source: "substrate-native-locks",
4460
- label: getLockedType(lock?.id?.asText?.()),
4230
+ label: getLockedType$1(lock?.id?.asText?.()),
4461
4231
  meta: {
4462
4232
  id: lock?.id?.asText?.()
4463
4233
  },
@@ -4521,7 +4291,7 @@ async function buildQueries$1(chains, tokens, chainStorageCoders, miniMetadatas,
4521
4291
  freezesQueryLocks = decoded?.map?.(lock => ({
4522
4292
  type: "locked",
4523
4293
  source: "substrate-native-freezes",
4524
- label: getLockedType(lock?.id?.type?.toLowerCase?.()),
4294
+ label: getLockedType$1(lock?.id?.type?.toLowerCase?.()),
4525
4295
  amount: lock?.amount?.toString?.() ?? "0"
4526
4296
  })) ?? [];
4527
4297
 
@@ -4660,7 +4430,7 @@ class QueryCache {
4660
4430
  const byNetwork = getAddresssesByTokenByNetwork(addressesByToken);
4661
4431
  for (const networkId of lodash.keys(byNetwork)) {
4662
4432
  if (this.miniMetadatas.has(networkId)) continue;
4663
- const miniMetadata = await getMiniMetadata(this.#chaindataProvider, this.#chainConnector, networkId, "substrate-native");
4433
+ const miniMetadata = await getMiniMetadata$9(this.#chaindataProvider, this.#chainConnector, networkId, "substrate-native");
4664
4434
  this.miniMetadatas.set(networkId, miniMetadata);
4665
4435
  }
4666
4436
 
@@ -4679,7 +4449,7 @@ class QueryCache {
4679
4449
  freezes: ["Balances", "Freezes"]
4680
4450
  }
4681
4451
  });
4682
- const queries = await buildQueries$1(chains, tokens, chainStorageCoders, this.miniMetadatas, queryResults.newAddressesByToken);
4452
+ const queries = await buildQueries$4(chains, tokens, chainStorageCoders, this.miniMetadatas, queryResults.newAddressesByToken);
4683
4453
  // now update the cache
4684
4454
  Object.entries(queries).forEach(([key, query]) => {
4685
4455
  this.balanceQueryCache.set(key, query);
@@ -4708,21 +4478,21 @@ class SubNativeBalanceError extends Error {
4708
4478
  }
4709
4479
  }
4710
4480
 
4711
- const DotNetworkPropertiesSimple = z__default.default.object({
4481
+ const DotNetworkPropertiesSimple$1 = z__default.default.object({
4712
4482
  tokenDecimals: z__default.default.number().optional().default(0),
4713
4483
  tokenSymbol: z__default.default.string().optional().default("Unit")
4714
4484
  });
4715
- const DotNetworkPropertiesArray = z__default.default.object({
4485
+ const DotNetworkPropertiesArray$1 = z__default.default.object({
4716
4486
  tokenDecimals: z__default.default.array(z__default.default.number()).nonempty(),
4717
4487
  tokenSymbol: z__default.default.array(z__default.default.string()).nonempty()
4718
4488
  });
4719
- const DotNetworkPropertiesSchema = z__default.default.union([DotNetworkPropertiesSimple, DotNetworkPropertiesArray]).transform(val => ({
4489
+ const DotNetworkPropertiesSchema$1 = z__default.default.union([DotNetworkPropertiesSimple$1, DotNetworkPropertiesArray$1]).transform(val => ({
4720
4490
  tokenDecimals: Array.isArray(val.tokenDecimals) ? val.tokenDecimals[0] : val.tokenDecimals,
4721
4491
  tokenSymbol: Array.isArray(val.tokenSymbol) ? val.tokenSymbol[0] : val.tokenSymbol
4722
4492
  }));
4723
- const getChainProperties = async (chainConnector, networkId) => {
4493
+ const getChainProperties$1 = async (chainConnector, networkId) => {
4724
4494
  const properties = await chainConnector.send(networkId, "system_properties", [], true);
4725
- return DotNetworkPropertiesSchema.parse(properties);
4495
+ return DotNetworkPropertiesSchema$1.parse(properties);
4726
4496
  };
4727
4497
 
4728
4498
  const POLLING_WINDOW_SIZE = 20;
@@ -5008,7 +4778,7 @@ const SubNativeModule = hydrate => {
5008
4778
  const {
5009
4779
  tokenSymbol: symbol,
5010
4780
  tokenDecimals: decimals
5011
- } = await getChainProperties(chainConnector$1, chainId);
4781
+ } = await getChainProperties$1(chainConnector$1, chainId);
5012
4782
  const {
5013
4783
  existentialDeposit
5014
4784
  } = chainMeta.extra ?? {};
@@ -5047,7 +4817,7 @@ const SubNativeModule = hydrate => {
5047
4817
  try {
5048
4818
  // this is what we want to be done separately for each network
5049
4819
  // this will update the DB so minimetadata will be available when it's used, everywhere else down the tree of subscribeChainBalances
5050
- await getMiniMetadata(chaindataProvider$1, chainConnector$1, networkId, moduleType$2, controller.signal);
4820
+ await getMiniMetadata$9(chaindataProvider$1, chainConnector$1, networkId, moduleType$2, controller.signal);
5051
4821
  } catch (err) {
5052
4822
  if (!util.isAbortError(err)) log.warn("Failed to get native token miniMetadata for network", networkId, err);
5053
4823
  return () => {};
@@ -6364,7 +6134,7 @@ const SubPsp22Module = hydrate => {
6364
6134
  if (!subscriptionActive) return;
6365
6135
  try {
6366
6136
  util$1.assert(chainConnectors.substrate, "This module requires a substrate chain connector");
6367
- const balances = await fetchBalances(chainConnectors.substrate, tokens, addressesByToken);
6137
+ const balances = await fetchBalances$9(chainConnectors.substrate, tokens, addressesByToken);
6368
6138
 
6369
6139
  // Don't call callback with balances which have not changed since the last poll.
6370
6140
  const updatedBalances = new Balances([...balances].filter(b => {
@@ -6387,7 +6157,7 @@ const SubPsp22Module = hydrate => {
6387
6157
  async fetchBalances(addressesByToken) {
6388
6158
  util$1.assert(chainConnectors.substrate, "This module requires a substrate chain connector");
6389
6159
  const tokens = await chaindataProvider$1.getTokensMapById();
6390
- return fetchBalances(chainConnectors.substrate, tokens, addressesByToken);
6160
+ return fetchBalances$9(chainConnectors.substrate, tokens, addressesByToken);
6391
6161
  },
6392
6162
  async transferToken({
6393
6163
  tokenId,
@@ -6467,7 +6237,7 @@ const SubPsp22Module = hydrate => {
6467
6237
  }
6468
6238
  };
6469
6239
  };
6470
- const fetchBalances = async (chainConnector, tokens, addressesByToken) => {
6240
+ const fetchBalances$9 = async (chainConnector, tokens, addressesByToken) => {
6471
6241
  const registry = new types.TypeRegistry();
6472
6242
  const Psp22Abi = new apiContract.Abi(psp22Abi);
6473
6243
  const balanceRequests = Object.entries(addressesByToken).flatMap(([tokenId, addresses]) => addresses.map(address => [tokenId, address])).flatMap(async ([tokenId, address]) => {
@@ -6628,7 +6398,7 @@ const SubTokensModule = hydrate => {
6628
6398
  },
6629
6399
  async fetchBalances(addressesByToken) {
6630
6400
  util$1.assert(chainConnectors.substrate, "This module requires a substrate chain connector");
6631
- const queries = await buildQueries(chainConnector, chaindataProvider$1, addressesByToken);
6401
+ const queries = await buildQueries$3(chainConnector, chaindataProvider$1, addressesByToken);
6632
6402
  const result = await new RpcStateQueryHelper(chainConnectors.substrate, queries).fetch();
6633
6403
  const balances = result?.filter(b => b !== null) ?? [];
6634
6404
  return new Balances(balances);
@@ -6645,7 +6415,7 @@ const SubTokensModule = hydrate => {
6645
6415
  const chainId = token.networkId;
6646
6416
  const chain = await chaindataProvider$1.getNetworkById(chainId, "polkadot");
6647
6417
  util$1.assert(chain?.genesisHash, `Chain ${chainId} not found in store`);
6648
- const miniMetadata = await getMiniMetadata(chaindataProvider$1, chainConnector, chainId, moduleType);
6418
+ const miniMetadata = await getMiniMetadata$9(chaindataProvider$1, chainConnector, chainId, moduleType);
6649
6419
  const tokensPallet = miniMetadata?.extra?.palletId ?? defaultPalletId;
6650
6420
  const onChainId = (() => {
6651
6421
  try {
@@ -6746,7 +6516,7 @@ const SubTokensModule = hydrate => {
6746
6516
  };
6747
6517
  };
6748
6518
  async function buildNetworkQueries(networkId, chainConnector, chaindataProvider, addressesByToken, signal) {
6749
- const miniMetadata = await getMiniMetadata(chaindataProvider, chainConnector, networkId, moduleType, signal);
6519
+ const miniMetadata = await getMiniMetadata$9(chaindataProvider, chainConnector, networkId, moduleType, signal);
6750
6520
  const chain = await chaindataProvider.getNetworkById(networkId, "polkadot");
6751
6521
  const tokens = await chaindataProvider.getTokensMapById();
6752
6522
  if (!chain) return [];
@@ -6817,7 +6587,7 @@ async function buildNetworkQueries(networkId, chainConnector, chaindataProvider,
6817
6587
  });
6818
6588
  });
6819
6589
  }
6820
- async function buildQueries(chainConnector, chaindataProvider$1, addressesByToken, signal) {
6590
+ async function buildQueries$3(chainConnector, chaindataProvider$1, addressesByToken, signal) {
6821
6591
  const byNetwork = lodash.keys(addressesByToken).reduce((acc, tokenId) => {
6822
6592
  const networkId = chaindataProvider.parseSubTokensTokenId(tokenId).networkId;
6823
6593
  if (!acc[networkId]) acc[networkId] = {};
@@ -6831,6 +6601,3806 @@ async function buildQueries(chainConnector, chaindataProvider$1, addressesByToke
6831
6601
 
6832
6602
  const defaultBalanceModules = [EvmErc20Module, EvmNativeModule, EvmUniswapV2Module, SubAssetsModule, SubForeignAssetsModule, SubNativeModule, SubPsp22Module, SubTokensModule];
6833
6603
 
6604
+ const MODULE_TYPE$8 = chaindataProvider.EvmErc20TokenSchema.shape.type.value;
6605
+ const PLATFORM$8 = chaindataProvider.EvmErc20TokenSchema.shape.platform.value;
6606
+
6607
+ // to be used by chaindata too
6608
+ z__default.default.strictObject({
6609
+ contractAddress: chaindataProvider.EvmErc20TokenSchema.shape.contractAddress,
6610
+ ...TokenConfigBaseSchema.shape
6611
+ });
6612
+
6613
+ class BalanceFetchError extends Error {
6614
+ constructor(message, tokenId, address, cause) {
6615
+ super(message);
6616
+ this.name = "BalanceFetchError";
6617
+ this.tokenId = tokenId;
6618
+ this.address = address;
6619
+ if (cause) this.cause = cause;
6620
+ }
6621
+ }
6622
+ class BalanceFetchNetworkError extends Error {
6623
+ constructor(message, evmNetworkId, cause) {
6624
+ super(message);
6625
+ this.name = "BalanceFetchNetworkError";
6626
+ this.evmNetworkId = evmNetworkId;
6627
+ if (cause) this.cause = cause;
6628
+ }
6629
+ }
6630
+
6631
+ const getBalanceDefs = addressesByToken => {
6632
+ return addressesByToken.flatMap(([token, addresses]) => addresses.map(address => ({
6633
+ token,
6634
+ address
6635
+ })));
6636
+ };
6637
+
6638
+ const fetchBalances$8 = async ({
6639
+ networkId,
6640
+ addressesByToken,
6641
+ connector
6642
+ }) => {
6643
+ const client = await connector.getPublicClientForEvmNetwork(networkId);
6644
+ if (!client) throw new Error(`Could not get rpc provider for evm network ${networkId}`);
6645
+ for (const [token, addresses] of addressesByToken) {
6646
+ 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}`);
6647
+ for (const address of addresses) if (!util.isEthereumAddress(address)) throw new Error(`Invalid ethereum address for EVM ERC20 balance module: ${address} for token ${token.id}`);
6648
+ }
6649
+ const balanceDefs = getBalanceDefs(addressesByToken);
6650
+ if (client.chain?.contracts?.erc20Aggregator && balanceDefs.length > 1) {
6651
+ const erc20Aggregator = client.chain.contracts.erc20Aggregator;
6652
+ return fetchWithAggregator$1(client, balanceDefs, erc20Aggregator.address);
6653
+ }
6654
+ return fetchWithoutAggregator$1(client, balanceDefs);
6655
+ };
6656
+ const fetchWithoutAggregator$1 = async (client, balanceDefs) => {
6657
+ if (balanceDefs.length === 0) return {
6658
+ success: [],
6659
+ errors: []
6660
+ };
6661
+ log.debug("fetching %s balances without aggregator", MODULE_TYPE$8, balanceDefs.length);
6662
+ const results = await Promise.allSettled(balanceDefs.map(async ({
6663
+ token,
6664
+ address
6665
+ }) => {
6666
+ try {
6667
+ const result = await client.readContract({
6668
+ abi: viem.erc20Abi,
6669
+ address: token.contractAddress,
6670
+ functionName: "balanceOf",
6671
+ args: [address]
6672
+ });
6673
+ const balance = {
6674
+ address,
6675
+ tokenId: token.id,
6676
+ value: result.toString(),
6677
+ source: MODULE_TYPE$8,
6678
+ networkId: chaindataProvider.parseEvmErc20TokenId(token.id).networkId,
6679
+ status: "cache"
6680
+ };
6681
+ return balance;
6682
+ } catch (err) {
6683
+ throw new BalanceFetchError(`Failed to get balance for token ${token.id} and address ${address} on chain ${client.chain?.id}`, token.id, address, err);
6684
+ }
6685
+ }));
6686
+ return results.reduce((acc, result) => {
6687
+ if (result.status === "fulfilled") acc.success.push(result.value);else {
6688
+ const error = result.reason;
6689
+ acc.errors.push({
6690
+ tokenId: error.tokenId,
6691
+ address: error.address,
6692
+ error
6693
+ });
6694
+ }
6695
+ return acc;
6696
+ }, {
6697
+ success: [],
6698
+ errors: []
6699
+ });
6700
+ };
6701
+ const fetchWithAggregator$1 = async (client, balanceDefs, erc20BalancesAggregatorAddress) => {
6702
+ if (balanceDefs.length === 0) return {
6703
+ success: [],
6704
+ errors: []
6705
+ };
6706
+ log.debug("fetching %s balances with aggregator", MODULE_TYPE$8, balanceDefs.length);
6707
+ try {
6708
+ const erc20Balances = await client.readContract({
6709
+ abi: erc20BalancesAggregatorAbi,
6710
+ address: erc20BalancesAggregatorAddress,
6711
+ functionName: "balances",
6712
+ args: [balanceDefs.map(b => ({
6713
+ account: b.address,
6714
+ token: b.token.contractAddress
6715
+ }))]
6716
+ });
6717
+ const success = balanceDefs.map((balanceDef, index) => ({
6718
+ address: balanceDef.address,
6719
+ tokenId: balanceDef.token.id,
6720
+ value: erc20Balances[index].toString(),
6721
+ source: MODULE_TYPE$8,
6722
+ networkId: chaindataProvider.parseTokenId(balanceDef.token.id).networkId,
6723
+ status: "cache"
6724
+ }));
6725
+ return {
6726
+ success,
6727
+ errors: []
6728
+ };
6729
+ } catch (err) {
6730
+ const errors = balanceDefs.map(balanceDef => ({
6731
+ tokenId: balanceDef.token.id,
6732
+ address: balanceDef.address,
6733
+ error: new BalanceFetchNetworkError(`Failed to get balances for evm-erc20 tokens on chain ${client.chain?.id}`, String(client.chain?.id), err)
6734
+ }));
6735
+ return {
6736
+ success: [],
6737
+ errors
6738
+ };
6739
+ }
6740
+ };
6741
+
6742
+ const getErc20ContractData$1 = async (client, contractAddress) => {
6743
+ try {
6744
+ const contract = getTypedContract$1(client, viem.erc20Abi, contractAddress);
6745
+
6746
+ // eslint-disable-next-line no-var
6747
+ var [symbol, decimals, name] = await Promise.all([contract.read.symbol(), contract.read.decimals(), contract.read.name()]);
6748
+ } catch (e) {
6749
+ if (e instanceof viem.ContractFunctionExecutionError) {
6750
+ // try to perform the contract read with bytes32 symbol
6751
+ const contract = getTypedContract$1(client, viem.erc20Abi_bytes32, contractAddress);
6752
+
6753
+ // eslint-disable-next-line no-var
6754
+ var [bytesSymbol, decimals, nameSymbol] = await Promise.all([contract.read.symbol(), contract.read.decimals(), contract.read.name()]);
6755
+ symbol = viem.hexToString(bytesSymbol).replace(/\0/g, "").trim(); // remove NULL characters
6756
+ name = viem.hexToString(nameSymbol).replace(/\0/g, "").trim(); // remove NULL characters
6757
+ } else throw e;
6758
+ }
6759
+ return {
6760
+ symbol,
6761
+ decimals,
6762
+ name
6763
+ };
6764
+ };
6765
+ const getTypedContract$1 = (client, abi, contractAddress) => viem.getContract({
6766
+ address: contractAddress,
6767
+ abi,
6768
+ client: {
6769
+ public: client
6770
+ }
6771
+ });
6772
+
6773
+ const TokenCacheSchema$1 = chaindataProvider.EvmErc20TokenSchema.pick({
6774
+ symbol: true,
6775
+ decimals: true,
6776
+ name: true
6777
+ });
6778
+ const fetchTokens$8 = async ({
6779
+ networkId,
6780
+ tokens,
6781
+ connector,
6782
+ cache
6783
+ }) => {
6784
+ const result = [];
6785
+ for (const tokenConfig of tokens) {
6786
+ const tokenId = chaindataProvider.evmErc20TokenId(networkId, tokenConfig.contractAddress);
6787
+ if (!cache[tokenId] || !TokenCacheSchema$1.safeParse(cache[tokenId]).success) {
6788
+ const client = await connector.getPublicClientForEvmNetwork(networkId);
6789
+ if (!client) {
6790
+ log.warn(`No client found for network ${networkId} while fetching EVM ERC20 tokens`);
6791
+ continue;
6792
+ }
6793
+ try {
6794
+ const {
6795
+ name,
6796
+ decimals,
6797
+ symbol
6798
+ } = await getErc20ContractData$1(client, tokenConfig.contractAddress);
6799
+ cache[tokenId] = {
6800
+ id: tokenId,
6801
+ symbol,
6802
+ decimals,
6803
+ name
6804
+ };
6805
+ } catch (err) {
6806
+ log.warn(`Failed to fetch ERC20 token data for ${tokenConfig.contractAddress}`, err);
6807
+ continue;
6808
+ }
6809
+ }
6810
+ const base = {
6811
+ type: MODULE_TYPE$8,
6812
+ platform: PLATFORM$8,
6813
+ networkId
6814
+ };
6815
+ const token = lodash.assign(base, cache[tokenId], tokenConfig);
6816
+ const parsed = chaindataProvider.EvmErc20TokenSchema.safeParse(token);
6817
+ if (!parsed.success) {
6818
+ log.warn("Ignoring token with invalid EvmErc20TokenSchema", token);
6819
+ continue;
6820
+ }
6821
+ result.push(parsed.data);
6822
+ }
6823
+ return result;
6824
+ };
6825
+
6826
+ const getMiniMetadata$8 = () => {
6827
+ throw new Error("MiniMetadata is not supported for ethereum tokens");
6828
+ };
6829
+
6830
+ const getTransferCallData$8 = ({
6831
+ from,
6832
+ to,
6833
+ value,
6834
+ token
6835
+ }) => {
6836
+ if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$8)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$8}.`);
6837
+ if (!util.isEthereumAddress(from)) throw new Error("Invalid from address");
6838
+ if (!util.isEthereumAddress(to)) throw new Error("Invalid to address");
6839
+ const data = viem.encodeFunctionData({
6840
+ abi: viem.erc20Abi,
6841
+ functionName: "transfer",
6842
+ args: [to, BigInt(value)]
6843
+ });
6844
+ return {
6845
+ from,
6846
+ to: token.contractAddress,
6847
+ data
6848
+ };
6849
+ };
6850
+
6851
+ const SUBSCRIPTION_INTERVAL$8 = 6_000;
6852
+ const subscribeBalances$8 = ({
6853
+ networkId,
6854
+ addressesByToken,
6855
+ connector
6856
+ }) => {
6857
+ return new rxjs.Observable(subscriber => {
6858
+ const abortController = new AbortController();
6859
+ const poll = async () => {
6860
+ try {
6861
+ if (abortController.signal.aborted) return;
6862
+ const balances = await fetchBalances$8({
6863
+ networkId,
6864
+ addressesByToken,
6865
+ connector
6866
+ });
6867
+ if (abortController.signal.aborted) return;
6868
+ subscriber.next(balances);
6869
+ setTimeout(poll, SUBSCRIPTION_INTERVAL$8);
6870
+ } catch (error) {
6871
+ log.error("Error", {
6872
+ module: MODULE_TYPE$8,
6873
+ networkId,
6874
+ addressesByToken,
6875
+ error
6876
+ });
6877
+ subscriber.error(error);
6878
+ }
6879
+ };
6880
+ poll();
6881
+ return () => {
6882
+ abortController.abort();
6883
+ };
6884
+ }).pipe(rxjs.distinctUntilChanged(lodash.isEqual));
6885
+ };
6886
+
6887
+ const EvmErc20BalanceModule = {
6888
+ type: MODULE_TYPE$8,
6889
+ platform: PLATFORM$8,
6890
+ getMiniMetadata: getMiniMetadata$8,
6891
+ fetchTokens: fetchTokens$8,
6892
+ fetchBalances: fetchBalances$8,
6893
+ subscribeBalances: subscribeBalances$8,
6894
+ getTransferCallData: getTransferCallData$8
6895
+ };
6896
+
6897
+ const MODULE_TYPE$7 = chaindataProvider.EvmNativeTokenSchema.shape.type.value;
6898
+ const PLATFORM$7 = chaindataProvider.EvmNativeTokenSchema.shape.platform.value;
6899
+
6900
+ // to be used by chaindata too
6901
+ z__default.default.strictObject({
6902
+ ...TokenConfigBaseSchema.shape
6903
+ });
6904
+
6905
+ const fetchBalances$7 = async ({
6906
+ networkId,
6907
+ addressesByToken,
6908
+ connector
6909
+ }) => {
6910
+ const client = await connector.getPublicClientForEvmNetwork(networkId);
6911
+ if (!client) throw new Error(`Could not get rpc provider for evm network ${networkId}`);
6912
+ for (const [token, addresses] of addressesByToken) {
6913
+ 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}`);
6914
+ for (const address of addresses) if (!util.isEthereumAddress(address)) throw new Error(`Invalid ethereum address for EVM ERC20 balance module: ${address} for token ${token.id}`);
6915
+ }
6916
+ const balanceDefs = getBalanceDefs(addressesByToken);
6917
+ if (client.chain?.contracts?.multicall3 && balanceDefs.length > 1) {
6918
+ const multicall3 = client.chain.contracts.multicall3;
6919
+ return fetchWithMulticall(client, balanceDefs, multicall3.address);
6920
+ }
6921
+ return fetchWithoutMulticall(client, balanceDefs);
6922
+ };
6923
+ const fetchWithoutMulticall = async (client, balanceDefs) => {
6924
+ if (balanceDefs.length === 0) return {
6925
+ success: [],
6926
+ errors: []
6927
+ };
6928
+ log.debug("fetching %s balances without multicall3", MODULE_TYPE$7, balanceDefs.length);
6929
+ const results = await Promise.allSettled(balanceDefs.map(async ({
6930
+ token,
6931
+ address
6932
+ }) => {
6933
+ try {
6934
+ const result = await client.getBalance({
6935
+ address
6936
+ });
6937
+ const balance = {
6938
+ address,
6939
+ tokenId: token.id,
6940
+ value: result.toString(),
6941
+ source: MODULE_TYPE$7,
6942
+ networkId: chaindataProvider.parseTokenId(token.id).networkId,
6943
+ status: "live"
6944
+ };
6945
+ return balance;
6946
+ } catch (err) {
6947
+ throw new BalanceFetchError(`Failed to get balance for token ${token.id} and address ${address} on chain ${client.chain?.id}`, token.id, address, err);
6948
+ }
6949
+ }));
6950
+ return results.reduce((acc, result) => {
6951
+ if (result.status === "fulfilled") acc.success.push(result.value);else {
6952
+ const error = result.reason;
6953
+ acc.errors.push({
6954
+ tokenId: error.tokenId,
6955
+ address: error.address,
6956
+ error
6957
+ });
6958
+ }
6959
+ return acc;
6960
+ }, {
6961
+ success: [],
6962
+ errors: []
6963
+ });
6964
+ };
6965
+ const fetchWithMulticall = async (client, balanceDefs, multicall3Address) => {
6966
+ if (balanceDefs.length === 0) return {
6967
+ success: [],
6968
+ errors: []
6969
+ };
6970
+ log.debug("fetching %s balances with multicall3", MODULE_TYPE$7, balanceDefs.length);
6971
+ try {
6972
+ const callResults = await client.multicall({
6973
+ contracts: balanceDefs.map(({
6974
+ address
6975
+ }) => ({
6976
+ address: multicall3Address,
6977
+ abi: abiMulticall,
6978
+ functionName: "getEthBalance",
6979
+ args: [address]
6980
+ }))
6981
+ });
6982
+ return callResults.reduce((acc, result, index) => {
6983
+ if (result.status === "success") {
6984
+ acc.success.push({
6985
+ address: balanceDefs[index].address,
6986
+ tokenId: balanceDefs[index].token.id,
6987
+ value: result.result.toString(),
6988
+ source: MODULE_TYPE$7,
6989
+ networkId: chaindataProvider.parseTokenId(balanceDefs[index].token.id).networkId,
6990
+ status: "live"
6991
+ });
6992
+ }
6993
+ if (result.status === "failure") {
6994
+ acc.errors.push({
6995
+ tokenId: balanceDefs[index].token.id,
6996
+ address: balanceDefs[index].address,
6997
+ 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)
6998
+ });
6999
+ }
7000
+ return acc;
7001
+ }, {
7002
+ success: [],
7003
+ errors: []
7004
+ });
7005
+ } catch (err) {
7006
+ const errors = balanceDefs.map(balanceDef => ({
7007
+ tokenId: balanceDef.token.id,
7008
+ address: balanceDef.address,
7009
+ error: new BalanceFetchNetworkError(`Failed to get balances for evm-erc20 tokens on chain ${client.chain?.id}`, String(client.chain?.id), err)
7010
+ }));
7011
+ return {
7012
+ success: [],
7013
+ errors
7014
+ };
7015
+ }
7016
+ };
7017
+
7018
+ const fetchTokens$7 = async ({
7019
+ networkId,
7020
+ tokens
7021
+ }) => {
7022
+ // assume there is one and only one token in the array
7023
+ if (tokens.length !== 1) throw new Error("EVM Native module expects the nativeCurrency to be passed as a single token in the array");
7024
+ const token = lodash.assign({
7025
+ id: chaindataProvider.evmNativeTokenId(networkId),
7026
+ type: MODULE_TYPE$7,
7027
+ platform: PLATFORM$7,
7028
+ networkId,
7029
+ isDefault: true
7030
+ }, tokens[0]);
7031
+ const parsed = chaindataProvider.EvmNativeTokenSchema.safeParse(token);
7032
+ if (!parsed.success) {
7033
+ log.warn("Ignoring token with invalid EvmErc20TokenSchema", token);
7034
+ return [];
7035
+ }
7036
+ return [parsed.data];
7037
+ };
7038
+
7039
+ const getMiniMetadata$7 = () => {
7040
+ throw new Error("MiniMetadata is not supported for ethereum tokens");
7041
+ };
7042
+
7043
+ const getTransferCallData$7 = ({
7044
+ from,
7045
+ to,
7046
+ value,
7047
+ token
7048
+ }) => {
7049
+ if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$7)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$7}.`);
7050
+ if (!util.isEthereumAddress(from)) throw new Error("Invalid from address");
7051
+ if (!util.isEthereumAddress(to)) throw new Error("Invalid to address");
7052
+ return {
7053
+ from,
7054
+ to,
7055
+ value,
7056
+ data: "0x"
7057
+ };
7058
+ };
7059
+
7060
+ const SUBSCRIPTION_INTERVAL$7 = 6_000;
7061
+ const subscribeBalances$7 = ({
7062
+ networkId,
7063
+ addressesByToken,
7064
+ connector
7065
+ }) => {
7066
+ return new rxjs.Observable(subscriber => {
7067
+ const abortController = new AbortController();
7068
+ const poll = async () => {
7069
+ try {
7070
+ if (abortController.signal.aborted) return;
7071
+ const balances = await fetchBalances$7({
7072
+ networkId,
7073
+ addressesByToken,
7074
+ connector
7075
+ });
7076
+ if (abortController.signal.aborted) return;
7077
+ subscriber.next(balances);
7078
+ setTimeout(poll, SUBSCRIPTION_INTERVAL$7);
7079
+ } catch (error) {
7080
+ log.error("Error", {
7081
+ module: MODULE_TYPE$7,
7082
+ networkId,
7083
+ addressesByToken,
7084
+ error
7085
+ });
7086
+ subscriber.error(error);
7087
+ }
7088
+ };
7089
+ poll();
7090
+ return () => {
7091
+ abortController.abort();
7092
+ };
7093
+ }).pipe(rxjs.distinctUntilChanged(lodash.isEqual));
7094
+ };
7095
+
7096
+ const EvmNativeBalanceModule = {
7097
+ type: MODULE_TYPE$7,
7098
+ platform: PLATFORM$7,
7099
+ getMiniMetadata: getMiniMetadata$7,
7100
+ fetchTokens: fetchTokens$7,
7101
+ fetchBalances: fetchBalances$7,
7102
+ subscribeBalances: subscribeBalances$7,
7103
+ getTransferCallData: getTransferCallData$7
7104
+ };
7105
+
7106
+ const MODULE_TYPE$6 = chaindataProvider.EvmUniswapV2TokenSchema.shape.type.value;
7107
+ const PLATFORM$6 = chaindataProvider.EvmUniswapV2TokenSchema.shape.platform.value;
7108
+
7109
+ // to be used by chaindata too
7110
+ z__default.default.strictObject({
7111
+ contractAddress: chaindataProvider.EvmUniswapV2TokenSchema.shape.contractAddress,
7112
+ ...TokenConfigBaseSchema.shape
7113
+ });
7114
+
7115
+ const fetchBalances$6 = async ({
7116
+ networkId,
7117
+ addressesByToken,
7118
+ connector
7119
+ }) => {
7120
+ const client = await connector.getPublicClientForEvmNetwork(networkId);
7121
+ if (!client) throw new Error(`Could not get rpc provider for evm network ${networkId}`);
7122
+ for (const [token, addresses] of addressesByToken) {
7123
+ 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}`);
7124
+ for (const address of addresses) if (!util.isEthereumAddress(address)) throw new Error(`Invalid ethereum address for EVM ERC20 balance module: ${address} for token ${token.id}`);
7125
+ }
7126
+ const balanceDefs = getBalanceDefs(addressesByToken);
7127
+ if (client.chain?.contracts?.erc20Aggregator && balanceDefs.length > 1) {
7128
+ const erc20Aggregator = client.chain.contracts.erc20Aggregator;
7129
+ return fetchWithAggregator(client, balanceDefs, erc20Aggregator.address);
7130
+ }
7131
+ return fetchWithoutAggregator(client, balanceDefs);
7132
+ };
7133
+ const fetchWithoutAggregator = async (client, balanceDefs) => {
7134
+ if (balanceDefs.length === 0) return {
7135
+ success: [],
7136
+ errors: []
7137
+ };
7138
+ log.debug("fetching %s balances without aggregator", MODULE_TYPE$6, balanceDefs.length);
7139
+ const results = await Promise.allSettled(balanceDefs.map(async ({
7140
+ token,
7141
+ address
7142
+ }) => {
7143
+ try {
7144
+ const result = await client.readContract({
7145
+ abi: viem.erc20Abi,
7146
+ address: token.contractAddress,
7147
+ functionName: "balanceOf",
7148
+ args: [address]
7149
+ });
7150
+ const balance = {
7151
+ address,
7152
+ tokenId: token.id,
7153
+ value: result.toString(),
7154
+ source: MODULE_TYPE$6,
7155
+ networkId: chaindataProvider.parseTokenId(token.id).networkId,
7156
+ status: "cache"
7157
+ };
7158
+ return balance;
7159
+ } catch (err) {
7160
+ throw new BalanceFetchError(`Failed to get balance for token ${token.id} and address ${address} on chain ${client.chain?.id}`, token.id, address, err);
7161
+ }
7162
+ }));
7163
+ return results.reduce((acc, result) => {
7164
+ if (result.status === "fulfilled") acc.success.push(result.value);else {
7165
+ const error = result.reason;
7166
+ acc.errors.push({
7167
+ tokenId: error.tokenId,
7168
+ address: error.address,
7169
+ error
7170
+ });
7171
+ }
7172
+ return acc;
7173
+ }, {
7174
+ success: [],
7175
+ errors: []
7176
+ });
7177
+ };
7178
+ const fetchWithAggregator = async (client, balanceDefs, erc20BalancesAggregatorAddress) => {
7179
+ if (balanceDefs.length === 0) return {
7180
+ success: [],
7181
+ errors: []
7182
+ };
7183
+ log.debug("fetching %s balances with aggregator", MODULE_TYPE$6, balanceDefs.length);
7184
+ try {
7185
+ const erc20Balances = await client.readContract({
7186
+ abi: erc20BalancesAggregatorAbi,
7187
+ address: erc20BalancesAggregatorAddress,
7188
+ functionName: "balances",
7189
+ args: [balanceDefs.map(b => ({
7190
+ account: b.address,
7191
+ token: b.token.contractAddress
7192
+ }))]
7193
+ });
7194
+ const success = balanceDefs.map((balanceDef, index) => ({
7195
+ address: balanceDef.address,
7196
+ tokenId: balanceDef.token.id,
7197
+ value: erc20Balances[index].toString(),
7198
+ source: MODULE_TYPE$6,
7199
+ networkId: chaindataProvider.parseTokenId(balanceDef.token.id).networkId,
7200
+ status: "cache"
7201
+ }));
7202
+ return {
7203
+ success,
7204
+ errors: []
7205
+ };
7206
+ } catch (err) {
7207
+ const errors = balanceDefs.map(balanceDef => ({
7208
+ tokenId: balanceDef.token.id,
7209
+ address: balanceDef.address,
7210
+ error: new BalanceFetchNetworkError(`Failed to get balances for evm-erc20 tokens on chain ${client.chain?.id}`, String(client.chain?.id), err)
7211
+ }));
7212
+ return {
7213
+ success: [],
7214
+ errors
7215
+ };
7216
+ }
7217
+ };
7218
+
7219
+ const getErc20ContractData = async (client, contractAddress) => {
7220
+ try {
7221
+ const contract = getTypedContract(client, viem.erc20Abi, contractAddress);
7222
+
7223
+ // eslint-disable-next-line no-var
7224
+ var [symbol, decimals, name] = await Promise.all([contract.read.symbol(), contract.read.decimals(), contract.read.name()]);
7225
+ } catch (e) {
7226
+ if (e instanceof viem.ContractFunctionExecutionError) {
7227
+ // try to perform the contract read with bytes32 symbol
7228
+ const contract = getTypedContract(client, viem.erc20Abi_bytes32, contractAddress);
7229
+
7230
+ // eslint-disable-next-line no-var
7231
+ var [bytesSymbol, decimals, nameSymbol] = await Promise.all([contract.read.symbol(), contract.read.decimals(), contract.read.name()]);
7232
+ symbol = viem.hexToString(bytesSymbol).replace(/\0/g, "").trim(); // remove NULL characters
7233
+ name = viem.hexToString(nameSymbol).replace(/\0/g, "").trim(); // remove NULL characters
7234
+ } else throw e;
7235
+ }
7236
+ return {
7237
+ symbol,
7238
+ decimals,
7239
+ name
7240
+ };
7241
+ };
7242
+ const getTypedContract = (client, abi, contractAddress) => viem.getContract({
7243
+ address: contractAddress,
7244
+ abi,
7245
+ client: {
7246
+ public: client
7247
+ }
7248
+ });
7249
+ const getUniswapV2PairContractData = async (client, contractAddress) => {
7250
+ const contract = getTypedContract(client, uniswapV2PairAbi, contractAddress);
7251
+
7252
+ // eslint-disable-next-line no-var
7253
+ var [token0, token1, decimals, name] = await Promise.all([contract.read.token0(), contract.read.token1(), contract.read.decimals(), contract.read.name()]);
7254
+ return {
7255
+ token0,
7256
+ token1,
7257
+ decimals,
7258
+ name
7259
+ };
7260
+ };
7261
+
7262
+ const TokenCacheSchema = chaindataProvider.EvmUniswapV2TokenSchema.pick({
7263
+ symbol: true,
7264
+ decimals: true,
7265
+ name: true,
7266
+ tokenAddress0: true,
7267
+ tokenAddress1: true,
7268
+ decimals0: true,
7269
+ decimals1: true,
7270
+ symbol0: true,
7271
+ symbol1: true
7272
+ });
7273
+ const fetchTokens$6 = async ({
7274
+ networkId,
7275
+ tokens,
7276
+ connector,
7277
+ cache
7278
+ }) => {
7279
+ const result = [];
7280
+ for (const tokenConfig of tokens) {
7281
+ const tokenId = chaindataProvider.evmUniswapV2TokenId(networkId, tokenConfig.contractAddress);
7282
+ if (!cache[tokenId] || !TokenCacheSchema.safeParse(cache[tokenId]).success) {
7283
+ const client = await connector.getPublicClientForEvmNetwork(networkId);
7284
+ if (!client) {
7285
+ log.warn(`No client found for network ${networkId} while fetching EVM ERC20 tokens`);
7286
+ continue;
7287
+ }
7288
+ try {
7289
+ const {
7290
+ token0,
7291
+ token1,
7292
+ name,
7293
+ decimals
7294
+ } = await getUniswapV2PairContractData(client, tokenConfig.contractAddress);
7295
+ const {
7296
+ symbol: symbol0,
7297
+ decimals: decimals0
7298
+ } = await getErc20ContractData(client, token0);
7299
+ const {
7300
+ symbol: symbol1,
7301
+ decimals: decimals1
7302
+ } = await getErc20ContractData(client, token1);
7303
+ cache[tokenId] = {
7304
+ id: tokenId,
7305
+ symbol: `${symbol0}/${symbol1}`,
7306
+ decimals,
7307
+ name,
7308
+ tokenAddress0: token0,
7309
+ tokenAddress1: token1,
7310
+ decimals0,
7311
+ decimals1,
7312
+ symbol0,
7313
+ symbol1
7314
+ };
7315
+ } catch (err) {
7316
+ log.warn(`Failed to fetch UniswapV2 token data for ${tokenConfig.contractAddress}`, err.shortMessage);
7317
+ continue;
7318
+ }
7319
+ }
7320
+ const base = {
7321
+ type: MODULE_TYPE$6,
7322
+ platform: PLATFORM$6,
7323
+ networkId
7324
+ };
7325
+ const token = lodash.assign(base, cache[tokenId], tokenConfig);
7326
+ const parsed = chaindataProvider.EvmUniswapV2TokenSchema.safeParse(token);
7327
+ if (!parsed.success) {
7328
+ log.warn("Ignoring token with invalid EvmErc20TokenSchema", token);
7329
+ continue;
7330
+ }
7331
+ result.push(parsed.data);
7332
+ }
7333
+ return result;
7334
+ };
7335
+
7336
+ const getMiniMetadata$6 = () => {
7337
+ throw new Error("MiniMetadata is not supported for ethereum tokens");
7338
+ };
7339
+
7340
+ const getTransferCallData$6 = ({
7341
+ from,
7342
+ to,
7343
+ value,
7344
+ token
7345
+ }) => {
7346
+ if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$6)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$6}.`);
7347
+ if (!util.isEthereumAddress(from)) throw new Error("Invalid from address");
7348
+ if (!util.isEthereumAddress(to)) throw new Error("Invalid to address");
7349
+ const data = viem.encodeFunctionData({
7350
+ abi: viem.erc20Abi,
7351
+ functionName: "transfer",
7352
+ args: [to, BigInt(value)]
7353
+ });
7354
+ return {
7355
+ from,
7356
+ to: token.contractAddress,
7357
+ data
7358
+ };
7359
+ };
7360
+
7361
+ const SUBSCRIPTION_INTERVAL$6 = 6_000;
7362
+ const subscribeBalances$6 = ({
7363
+ networkId,
7364
+ addressesByToken,
7365
+ connector
7366
+ }) => {
7367
+ return new rxjs.Observable(subscriber => {
7368
+ const abortController = new AbortController();
7369
+ const poll = async () => {
7370
+ try {
7371
+ if (abortController.signal.aborted) return;
7372
+ const balances = await fetchBalances$6({
7373
+ networkId,
7374
+ addressesByToken,
7375
+ connector
7376
+ });
7377
+ if (abortController.signal.aborted) return;
7378
+ subscriber.next(balances);
7379
+ setTimeout(poll, SUBSCRIPTION_INTERVAL$6);
7380
+ } catch (error) {
7381
+ log.error("Error", {
7382
+ module: MODULE_TYPE$6,
7383
+ networkId,
7384
+ addressesByToken,
7385
+ error
7386
+ });
7387
+ subscriber.error(error);
7388
+ }
7389
+ };
7390
+ poll();
7391
+ return () => {
7392
+ abortController.abort();
7393
+ };
7394
+ }).pipe(rxjs.distinctUntilChanged(lodash.isEqual));
7395
+ };
7396
+
7397
+ const EvmUniswapV2BalanceModule = {
7398
+ type: MODULE_TYPE$6,
7399
+ platform: PLATFORM$6,
7400
+ getMiniMetadata: getMiniMetadata$6,
7401
+ fetchTokens: fetchTokens$6,
7402
+ fetchBalances: fetchBalances$6,
7403
+ subscribeBalances: subscribeBalances$6,
7404
+ getTransferCallData: getTransferCallData$6
7405
+ };
7406
+
7407
+ const MODULE_TYPE$5 = chaindataProvider.SubAssetsTokenSchema.shape.type.value;
7408
+ const PLATFORM$5 = chaindataProvider.SubAssetsTokenSchema.shape.platform.value;
7409
+
7410
+ // to be used by chaindata too
7411
+ z__default.default.strictObject({
7412
+ assetId: chaindataProvider.SubAssetsTokenSchema.shape.assetId,
7413
+ ...TokenConfigBaseSchema.shape
7414
+ });
7415
+
7416
+ const fetchBalances$5 = async ({
7417
+ networkId,
7418
+ addressesByToken,
7419
+ connector,
7420
+ miniMetadata
7421
+ }) => {
7422
+ const balanceDefs = getBalanceDefs(addressesByToken);
7423
+ if (!miniMetadata?.data) {
7424
+ log.warn("MiniMetadata is required for fetching balances");
7425
+ return {
7426
+ success: [],
7427
+ errors: balanceDefs.map(def => ({
7428
+ tokenId: def.token.id,
7429
+ address: def.address,
7430
+ error: new Error("Minimetadata is required for fetching balances")
7431
+ }))
7432
+ };
7433
+ }
7434
+ if (miniMetadata.source !== MODULE_TYPE$5) {
7435
+ log.warn(`Ignoring miniMetadata with source ${miniMetadata.source} in ${MODULE_TYPE$5}.`);
7436
+ return {
7437
+ success: [],
7438
+ errors: balanceDefs.map(def => ({
7439
+ tokenId: def.token.id,
7440
+ address: def.address,
7441
+ error: new Error(`Invalid request: miniMetadata source is not ${MODULE_TYPE$5}`)
7442
+ }))
7443
+ };
7444
+ }
7445
+ if (miniMetadata.chainId !== networkId) {
7446
+ log.warn(`Ignoring miniMetadata with chainId ${miniMetadata.chainId} in ${MODULE_TYPE$5}. Expected chainId is ${networkId}`);
7447
+ return {
7448
+ success: [],
7449
+ errors: balanceDefs.map(def => ({
7450
+ tokenId: def.token.id,
7451
+ address: def.address,
7452
+ error: new Error(`Invalid request: Expected chainId is ${networkId}`)
7453
+ }))
7454
+ };
7455
+ }
7456
+ const queries = buildQueries$2(networkId, balanceDefs, miniMetadata);
7457
+ const balances = await new RpcStateQueryHelper(connector, queries).fetch();
7458
+ return balanceDefs.reduce((acc, def) => {
7459
+ const balance = balances.find(b => b?.address === def.address && b?.tokenId === def.token.id);
7460
+ if (balance) acc.success.push(balance);
7461
+ //if no entry consider empty balance
7462
+ else acc.success.push({
7463
+ address: def.address,
7464
+ networkId,
7465
+ tokenId: def.token.id,
7466
+ source: MODULE_TYPE$5,
7467
+ status: "live",
7468
+ values: [{
7469
+ type: "free",
7470
+ label: "free",
7471
+ amount: "0"
7472
+ }, {
7473
+ type: "locked",
7474
+ label: "frozen",
7475
+ amount: "0"
7476
+ }]
7477
+ });
7478
+ return acc;
7479
+ }, {
7480
+ success: [],
7481
+ errors: []
7482
+ });
7483
+ };
7484
+ const buildQueries$2 = (networkId, balanceDefs, miniMetadata) => {
7485
+ const networkStorageCoders = buildNetworkStorageCoders(networkId, miniMetadata, {
7486
+ storage: ["Assets", "Account"]
7487
+ });
7488
+ return balanceDefs.map(({
7489
+ token,
7490
+ address
7491
+ }) => {
7492
+ const scaleCoder = networkStorageCoders?.storage;
7493
+ const stateKey = tryEncode(scaleCoder, Number(token.assetId), address) ??
7494
+ // Asset Hub
7495
+ tryEncode(scaleCoder, BigInt(token.assetId), address); // Astar
7496
+
7497
+ if (!stateKey) {
7498
+ log.warn(`Invalid assetId / address in ${networkId} storage query ${token.assetId} / ${address}`);
7499
+ return null;
7500
+ }
7501
+ const decodeResult = change => {
7502
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
7503
+
7504
+ const decoded = scale.decodeScale(scaleCoder, change, `Failed to decode substrate-assets balance on chain ${networkId}`) ?? {
7505
+ balance: 0n,
7506
+ status: {
7507
+ type: "Liquid"
7508
+ }};
7509
+ const isFrozen = decoded?.status?.type === "Frozen";
7510
+ const amount = (decoded?.balance ?? 0n).toString();
7511
+
7512
+ // due to the following balance calculations, which are made in the `Balance` type:
7513
+ //
7514
+ // total balance = (free balance) + (reserved balance)
7515
+ // transferable balance = (free balance) - (frozen balance)
7516
+ //
7517
+ // when `isFrozen` is true we need to set **both** the `free` and `frozen` amounts
7518
+ // of this balance to the value we received from the RPC.
7519
+ //
7520
+ // if we only set the `frozen` amount, then the `total` calculation will be incorrect!
7521
+ const free = amount;
7522
+ const frozen = token.isFrozen || isFrozen ? amount : "0";
7523
+
7524
+ // include balance values even if zero, so that newly-zero values overwrite old values
7525
+ const balanceValues = [{
7526
+ type: "free",
7527
+ label: "free",
7528
+ amount: free.toString()
7529
+ }, {
7530
+ type: "locked",
7531
+ label: "frozen",
7532
+ amount: frozen.toString()
7533
+ }];
7534
+ const balance = {
7535
+ source: "substrate-assets",
7536
+ status: "live",
7537
+ address,
7538
+ networkId,
7539
+ tokenId: token.id,
7540
+ values: balanceValues
7541
+ };
7542
+ return balance;
7543
+ };
7544
+ return {
7545
+ chainId: networkId,
7546
+ stateKey,
7547
+ decodeResult
7548
+ };
7549
+ }).filter(util.isNotNil);
7550
+ };
7551
+ const tryEncode = (scaleCoder, ...args) => {
7552
+ try {
7553
+ return scaleCoder?.keys?.enc?.(...args);
7554
+ } catch {
7555
+ return null;
7556
+ }
7557
+ };
7558
+
7559
+ const fetchTokens$5 = async ({
7560
+ networkId,
7561
+ tokens,
7562
+ connector,
7563
+ miniMetadata
7564
+ }) => {
7565
+ const anyMiniMetadata = miniMetadata;
7566
+ if (!anyMiniMetadata?.data) return [];
7567
+ const {
7568
+ builder
7569
+ } = scale.parseMetadataRpc(anyMiniMetadata.data);
7570
+ const assetCodec = builder.buildStorage("Assets", "Asset");
7571
+ const metadataCodec = builder.buildStorage("Assets", "Metadata");
7572
+ const [allAssetStorageKeys, allMetadataStorageKeys] = await Promise.all([connector.send(networkId, "state_getKeys", [scale.getStorageKeyPrefix("Assets", "Asset")]), connector.send(networkId, "state_getKeys", [scale.getStorageKeyPrefix("Assets", "Metadata")])]);
7573
+ const [assetStorageResults, metadataStorageResults] = await Promise.all([connector.send(networkId, "state_queryStorageAt", [allAssetStorageKeys]), connector.send(networkId, "state_queryStorageAt", [allMetadataStorageKeys])]);
7574
+ const assetStorageEntries = assetStorageResults[0].changes;
7575
+ const metadataStorageEntries = metadataStorageResults[0].changes;
7576
+ const assetByAssetId = lodash.keyBy(assetStorageEntries.map(([key, value]) => {
7577
+ const [assetId] = assetCodec.keys.dec(key);
7578
+ const asset = assetCodec.value.dec(value);
7579
+ return {
7580
+ assetId,
7581
+ existentialDeposit: asset.min_balance,
7582
+ isSufficient: asset.is_sufficient
7583
+ };
7584
+ }), a => a.assetId);
7585
+ const metadataByAssetId = lodash.keyBy(metadataStorageEntries.map(([key, value]) => {
7586
+ const [assetId] = metadataCodec.keys.dec(key);
7587
+ const metadata = metadataCodec.value.dec(value);
7588
+ return {
7589
+ assetId,
7590
+ decimals: metadata.decimals,
7591
+ isFrozen: metadata.is_frozen,
7592
+ name: metadata.name?.asText(),
7593
+ symbol: metadata.symbol?.asText()
7594
+ };
7595
+ }), a => a.assetId);
7596
+ const allTokens = lodash.keys(assetByAssetId).map(assetId => lodash.assign({}, assetByAssetId[assetId], metadataByAssetId[assetId] ?? undefined));
7597
+ const configTokenByAssetId = lodash.keyBy(tokens, t => t.assetId);
7598
+ return allTokens.map(asset => ({
7599
+ id: chaindataProvider.subAssetTokenId(networkId, String(asset.assetId)),
7600
+ type: MODULE_TYPE$5,
7601
+ platform: "polkadot",
7602
+ networkId,
7603
+ assetId: String(asset.assetId),
7604
+ isSufficient: asset.isSufficient,
7605
+ isFrozen: asset.isFrozen,
7606
+ name: asset.name,
7607
+ symbol: asset.symbol,
7608
+ decimals: asset.decimals ?? 0,
7609
+ existentialDeposit: String(asset.existentialDeposit),
7610
+ isDefault: true
7611
+ }))
7612
+ // keep all tokens listed in the config + all tokens marked as sufficient
7613
+ .filter(token => {
7614
+ const configToken = configTokenByAssetId[token.assetId];
7615
+ return configToken || token.isSufficient;
7616
+ })
7617
+ // apply config overrides
7618
+ .map(token => {
7619
+ const configToken = configTokenByAssetId[token.assetId];
7620
+ return configToken ? lodash.assign({}, token, configToken) : token;
7621
+ })
7622
+ // validate results
7623
+ .filter(t => {
7624
+ const parsed = chaindataProvider.SubAssetsTokenSchema.safeParse(t);
7625
+ if (!parsed.success) log.warn(`Ignoring invalid token ${MODULE_TYPE$5}`, t);
7626
+ return parsed.success;
7627
+ });
7628
+ };
7629
+
7630
+ const getConstantValue = (metadataRpc, pallet, constant) => {
7631
+ const {
7632
+ unifiedMetadata,
7633
+ builder
7634
+ } = scale.parseMetadataRpc(metadataRpc);
7635
+ const codec = builder.buildConstant(pallet, constant);
7636
+ const encodedValue = unifiedMetadata.pallets.find(({
7637
+ name
7638
+ }) => name === pallet)?.constants.find(({
7639
+ name
7640
+ }) => name === constant)?.value;
7641
+ if (!encodedValue) throw new Error(`Constant ${pallet}.${constant} not found`);
7642
+ return codec.dec(encodedValue);
7643
+ };
7644
+
7645
+ const hasStorageItem = (metadata, palletName, itemName) => {
7646
+ const pallet = metadata.pallets.find(p => p.name === palletName);
7647
+ if (!pallet || !pallet.storage) return false;
7648
+ return pallet.storage.items.some(item => item.name === itemName);
7649
+ };
7650
+ const hasStorageItems = (metadata, palletName, itemNames) => {
7651
+ const pallet = metadata.pallets.find(p => p.name === palletName);
7652
+ if (!pallet || !pallet.storage) return false;
7653
+ return itemNames.every(itemName => pallet.storage?.items.some(item => item.name === itemName));
7654
+ };
7655
+ const hasRuntimeApi = (metadata, apiName, method) => {
7656
+ const api = metadata.apis.find(api => api.name === apiName);
7657
+ if (!api || !api.methods) return false;
7658
+ return api.methods.some(m => m.name === method);
7659
+ };
7660
+
7661
+ const getMiniMetadata$5 = ({
7662
+ networkId,
7663
+ specVersion,
7664
+ metadataRpc
7665
+ }) => {
7666
+ const source = MODULE_TYPE$5;
7667
+ const chainId = networkId;
7668
+ const systemVersion = getConstantValue(metadataRpc, "System", "Version");
7669
+ if (specVersion !== systemVersion.spec_version) log.warn("specVersion mismatch", {
7670
+ networkId,
7671
+ specVersion,
7672
+ systemVersion
7673
+ });
7674
+ const id = deriveMiniMetadataId({
7675
+ source,
7676
+ chainId,
7677
+ specVersion
7678
+ });
7679
+ const {
7680
+ unifiedMetadata
7681
+ } = scale.parseMetadataRpc(metadataRpc);
7682
+ if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
7683
+ return {
7684
+ id,
7685
+ source,
7686
+ chainId,
7687
+ specVersion,
7688
+ version: chaindataProvider.MINIMETADATA_VERSION,
7689
+ data: getData$3(metadataRpc),
7690
+ extra: null
7691
+ };
7692
+ };
7693
+ const getData$3 = metadataRpc => {
7694
+ const {
7695
+ metadata,
7696
+ unifiedMetadata
7697
+ } = scale.parseMetadataRpc(metadataRpc);
7698
+
7699
+ // ensure the network has all the required bits
7700
+ if (!hasStorageItems(unifiedMetadata, "Assets", ["Account", "Asset", "Metadata"])) return null;
7701
+ scale.compactMetadata(metadata, [{
7702
+ pallet: "Assets",
7703
+ items: ["Account", "Asset", "Metadata"]
7704
+ }]);
7705
+ return scale.encodeMetadata(metadata);
7706
+ };
7707
+
7708
+ const getTransferCallData$5 = ({
7709
+ from,
7710
+ to,
7711
+ value,
7712
+ token,
7713
+ type,
7714
+ metadataRpc
7715
+ }) => {
7716
+ if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$5)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$5}.`);
7717
+ const {
7718
+ builder
7719
+ } = scale.parseMetadataRpc(metadataRpc);
7720
+ const method = getTransferMethod$3(type);
7721
+ const {
7722
+ codec,
7723
+ location
7724
+ } = builder.buildCall("Assets", method);
7725
+ const args = getEncodedArgs$2(method, token.assetId, to, value, codec);
7726
+ const callData = polkadotApi.Binary.fromBytes(utils.mergeUint8([new Uint8Array(location), args]));
7727
+ return {
7728
+ address: from,
7729
+ method: callData.asHex()
7730
+ };
7731
+ };
7732
+ const getTransferMethod$3 = type => {
7733
+ switch (type) {
7734
+ case "keep-alive":
7735
+ return "transfer_keep_alive";
7736
+ case "all":
7737
+ return "transfer_all";
7738
+ case "allow-death":
7739
+ return "transfer";
7740
+ }
7741
+ };
7742
+ const getEncodedArgs$2 = (method, assetId, to, value, argsCodec) => {
7743
+ try {
7744
+ switch (method) {
7745
+ case "transfer_keep_alive":
7746
+ case "transfer":
7747
+ return getTransferEncodedArgs$2(assetId, to, value, argsCodec);
7748
+ case "transfer_all":
7749
+ return getTransferAllEncodedArgs$2(assetId, to, argsCodec);
7750
+ }
7751
+ } catch {
7752
+ throw new Error(`Failed to encode arguments for method ${method}: ${assetId}, ${to}, ${value}`);
7753
+ }
7754
+ };
7755
+ const getEncodedValue$2 = (codec, possibleValue) => {
7756
+ for (const getArgs of possibleValue) {
7757
+ try {
7758
+ return codec.enc(getArgs());
7759
+ } catch (error) {
7760
+ // wrong inputs, ignore and try the next one
7761
+ }
7762
+ }
7763
+ throw new Error("Failed to encode");
7764
+ };
7765
+
7766
+ // same inputs for both KeepAlive and allowDeath
7767
+ const getTransferEncodedArgs$2 = (assetId, to, value, codec) => {
7768
+ return getEncodedValue$2(codec, [() => ({
7769
+ id: Number(assetId),
7770
+ // for most networks
7771
+ target: polkadotApi.Enum("Id", to),
7772
+ amount: BigInt(value)
7773
+ }), () => ({
7774
+ id: BigInt(assetId),
7775
+ // for Astar
7776
+ target: polkadotApi.Enum("Id", to),
7777
+ amount: BigInt(value)
7778
+ })]);
7779
+ };
7780
+ const getTransferAllEncodedArgs$2 = (assetId, to, codec) => {
7781
+ return getEncodedValue$2(codec, [() => ({
7782
+ id: Number(assetId),
7783
+ // for most networks
7784
+ target: polkadotApi.Enum("Id", to),
7785
+ keep_alive: false
7786
+ }), () => ({
7787
+ id: BigInt(assetId),
7788
+ // for Astar
7789
+ target: polkadotApi.Enum("Id", to),
7790
+ keep_alive: false
7791
+ })]);
7792
+ };
7793
+
7794
+ const SUBSCRIPTION_INTERVAL$5 = 6_000;
7795
+ const subscribeBalances$5 = ({
7796
+ networkId,
7797
+ addressesByToken,
7798
+ connector,
7799
+ miniMetadata
7800
+ }) => {
7801
+ return new rxjs.Observable(subscriber => {
7802
+ const abortController = new AbortController();
7803
+
7804
+ // on hydration balances are fetched using a runtimeApi, which can't be subscribed to.
7805
+ // => poll values for each block
7806
+ const poll = async () => {
7807
+ try {
7808
+ if (abortController.signal.aborted) return;
7809
+ const balances = await fetchBalances$5({
7810
+ networkId,
7811
+ addressesByToken,
7812
+ connector,
7813
+ miniMetadata
7814
+ });
7815
+ if (abortController.signal.aborted) return;
7816
+ subscriber.next(balances);
7817
+ setTimeout(poll, SUBSCRIPTION_INTERVAL$5);
7818
+ } catch (error) {
7819
+ log.error("Error", {
7820
+ module: MODULE_TYPE$5,
7821
+ networkId,
7822
+ miniMetadata,
7823
+ addressesByToken,
7824
+ error
7825
+ });
7826
+ subscriber.error(error);
7827
+ }
7828
+ };
7829
+ poll();
7830
+ return () => {
7831
+ abortController.abort();
7832
+ };
7833
+ }).pipe(rxjs.distinctUntilChanged(lodash.isEqual));
7834
+ };
7835
+
7836
+ const SubAssetsBalanceModule = {
7837
+ type: MODULE_TYPE$5,
7838
+ platform: PLATFORM$5,
7839
+ getMiniMetadata: getMiniMetadata$5,
7840
+ fetchTokens: fetchTokens$5,
7841
+ fetchBalances: fetchBalances$5,
7842
+ subscribeBalances: subscribeBalances$5,
7843
+ getTransferCallData: getTransferCallData$5
7844
+ };
7845
+
7846
+ const MODULE_TYPE$4 = chaindataProvider.SubForeignAssetsTokenSchema.shape.type.value;
7847
+ const PLATFORM$4 = chaindataProvider.SubForeignAssetsTokenSchema.shape.platform.value;
7848
+
7849
+ // to be used by chaindata too
7850
+ z__default.default.strictObject({
7851
+ onChainId: chaindataProvider.SubForeignAssetsTokenSchema.shape.onChainId,
7852
+ ...TokenConfigBaseSchema.shape
7853
+ });
7854
+
7855
+ const fetchBalances$4 = async ({
7856
+ networkId,
7857
+ addressesByToken,
7858
+ connector,
7859
+ miniMetadata
7860
+ }) => {
7861
+ const balanceDefs = getBalanceDefs(addressesByToken);
7862
+ if (!miniMetadata?.data) {
7863
+ log.warn("MiniMetadata is required for fetching balances");
7864
+ return {
7865
+ success: [],
7866
+ errors: balanceDefs.map(def => ({
7867
+ tokenId: def.token.id,
7868
+ address: def.address,
7869
+ error: new Error("Minimetadata is required for fetching balances")
7870
+ }))
7871
+ };
7872
+ }
7873
+ if (miniMetadata.source !== MODULE_TYPE$4) {
7874
+ log.warn(`Ignoring miniMetadata with source ${miniMetadata.source} in ${MODULE_TYPE$4}.`);
7875
+ return {
7876
+ success: [],
7877
+ errors: balanceDefs.map(def => ({
7878
+ tokenId: def.token.id,
7879
+ address: def.address,
7880
+ error: new Error(`Invalid request: miniMetadata source is not ${MODULE_TYPE$4}`)
7881
+ }))
7882
+ };
7883
+ }
7884
+ if (miniMetadata.chainId !== networkId) {
7885
+ log.warn(`Ignoring miniMetadata with chainId ${miniMetadata.chainId} in ${MODULE_TYPE$4}. Expected chainId is ${networkId}`);
7886
+ return {
7887
+ success: [],
7888
+ errors: balanceDefs.map(def => ({
7889
+ tokenId: def.token.id,
7890
+ address: def.address,
7891
+ error: new Error(`Invalid request: Expected chainId is ${networkId}`)
7892
+ }))
7893
+ };
7894
+ }
7895
+ const queries = buildQueries$1(networkId, balanceDefs, miniMetadata);
7896
+ const balances = await new RpcStateQueryHelper(connector, queries).fetch();
7897
+ return balanceDefs.reduce((acc, def) => {
7898
+ const balance = balances.find(b => b?.address === def.address && b?.tokenId === def.token.id);
7899
+ if (balance) acc.success.push(balance);
7900
+ //if no entry consider empty balance
7901
+ else acc.success.push({
7902
+ address: def.address,
7903
+ networkId,
7904
+ tokenId: def.token.id,
7905
+ source: MODULE_TYPE$4,
7906
+ status: "live",
7907
+ values: [{
7908
+ type: "free",
7909
+ label: "free",
7910
+ amount: "0"
7911
+ }, {
7912
+ type: "locked",
7913
+ label: "frozen",
7914
+ amount: "0"
7915
+ }]
7916
+ });
7917
+ return acc;
7918
+ }, {
7919
+ success: [],
7920
+ errors: []
7921
+ });
7922
+ };
7923
+ const buildQueries$1 = (networkId, balanceDefs, miniMetadata) => {
7924
+ const networkStorageCoders = buildNetworkStorageCoders(networkId, miniMetadata, {
7925
+ storage: ["ForeignAssets", "Account"]
7926
+ });
7927
+ return balanceDefs.map(({
7928
+ token,
7929
+ address
7930
+ }) => {
7931
+ const scaleCoder = networkStorageCoders?.storage;
7932
+ const getStateKey = onChainId => {
7933
+ try {
7934
+ return scaleCoder?.keys?.enc?.(scale.papiParse(onChainId), address);
7935
+ } catch {
7936
+ return null;
7937
+ }
7938
+ };
7939
+ const stateKey = getStateKey(token.onChainId);
7940
+ if (!stateKey) {
7941
+ log.warn(`Invalid assetId / address in ${networkId} storage query ${token.onChainId} / ${address}`);
7942
+ return null;
7943
+ }
7944
+ const decodeResult = change => {
7945
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
7946
+
7947
+ const decoded = scale.decodeScale(scaleCoder, change, `Failed to decode substrate-assets balance on chain ${networkId}`) ?? {
7948
+ balance: 0n,
7949
+ is_frozen: false,
7950
+ status: {
7951
+ type: "Liquid"
7952
+ }};
7953
+ const isFrozen = decoded.is_frozen ?? decoded?.status?.type === "Frozen";
7954
+ const amount = (decoded?.balance ?? 0n).toString();
7955
+
7956
+ // due to the following balance calculations, which are made in the `Balance` type:
7957
+ //
7958
+ // total balance = (free balance) + (reserved balance)
7959
+ // transferable balance = (free balance) - (frozen balance)
7960
+ //
7961
+ // when `isFrozen` is true we need to set **both** the `free` and `frozen` amounts
7962
+ // of this balance to the value we received from the RPC.
7963
+ //
7964
+ // if we only set the `frozen` amount, then the `total` calculation will be incorrect!
7965
+ const free = amount;
7966
+ const frozen = token.isFrozen || isFrozen ? amount : "0";
7967
+
7968
+ // include balance values even if zero, so that newly-zero values overwrite old values
7969
+ const balanceValues = [{
7970
+ type: "free",
7971
+ label: "free",
7972
+ amount: free.toString()
7973
+ }, {
7974
+ type: "locked",
7975
+ label: "frozen",
7976
+ amount: frozen.toString()
7977
+ }];
7978
+ const balance = {
7979
+ source: "substrate-assets",
7980
+ status: "live",
7981
+ address,
7982
+ networkId,
7983
+ tokenId: token.id,
7984
+ values: balanceValues
7985
+ };
7986
+ return balance;
7987
+ };
7988
+ return {
7989
+ chainId: networkId,
7990
+ stateKey,
7991
+ decodeResult
7992
+ };
7993
+ }).filter(util.isNotNil);
7994
+ };
7995
+
7996
+ const fetchTokens$4 = async ({
7997
+ networkId,
7998
+ tokens,
7999
+ connector,
8000
+ miniMetadata
8001
+ }) => {
8002
+ const anyMiniMetadata = miniMetadata;
8003
+ if (!anyMiniMetadata?.data) return [];
8004
+ const {
8005
+ builder
8006
+ } = scale.parseMetadataRpc(anyMiniMetadata.data);
8007
+ const assetCodec = builder.buildStorage("ForeignAssets", "Asset");
8008
+ const metadataCodec = builder.buildStorage("ForeignAssets", "Metadata");
8009
+ const [allAssetStorageKeys, allMetadataStorageKeys] = await Promise.all([connector.send(networkId, "state_getKeys", [scale.getStorageKeyPrefix("ForeignAssets", "Asset")]), connector.send(networkId, "state_getKeys", [scale.getStorageKeyPrefix("ForeignAssets", "Metadata")])]);
8010
+ const [assetStorageResults, metadataStorageResults] = await Promise.all([connector.send(networkId, "state_queryStorageAt", [allAssetStorageKeys]), connector.send(networkId, "state_queryStorageAt", [allMetadataStorageKeys])]);
8011
+ const assetStorageEntries = assetStorageResults[0].changes;
8012
+ const metadataStorageEntries = metadataStorageResults[0].changes;
8013
+ const assetByOnChainId = lodash.keyBy(assetStorageEntries.map(([key, value]) => {
8014
+ const [decodedKey] = assetCodec.keys.dec(key);
8015
+ const onChainId = scale.papiStringify(decodedKey);
8016
+ const asset = assetCodec.value.dec(value);
8017
+ return {
8018
+ onChainId,
8019
+ existentialDeposit: asset.min_balance,
8020
+ isSufficient: asset.is_sufficient
8021
+ };
8022
+ }), a => a.onChainId);
8023
+ const metadataByOnChainId = lodash.keyBy(metadataStorageEntries.map(([key, value]) => {
8024
+ const [decodedKey] = metadataCodec.keys.dec(key);
8025
+ const onChainId = scale.papiStringify(decodedKey);
8026
+ const metadata = metadataCodec.value.dec(value);
8027
+ return {
8028
+ onChainId,
8029
+ decimals: metadata.decimals,
8030
+ isFrozen: metadata.is_frozen,
8031
+ name: metadata.name?.asText(),
8032
+ symbol: metadata.symbol?.asText()
8033
+ };
8034
+ }), a => a.onChainId);
8035
+ const allTokens = lodash.keys(assetByOnChainId).map(onChainId => lodash.assign({}, assetByOnChainId[onChainId], metadataByOnChainId[onChainId] ?? undefined));
8036
+ const configTokenByOnChainId = lodash.keyBy(tokens, t => t.onChainId);
8037
+ return allTokens.map(asset => ({
8038
+ id: chaindataProvider.subForeignAssetTokenId(networkId, asset.onChainId),
8039
+ type: MODULE_TYPE$4,
8040
+ platform: "polkadot",
8041
+ networkId,
8042
+ onChainId: String(asset.onChainId),
8043
+ isSufficient: asset.isSufficient,
8044
+ isFrozen: asset.isFrozen,
8045
+ name: asset.name,
8046
+ symbol: asset.symbol,
8047
+ decimals: asset.decimals ?? 0,
8048
+ existentialDeposit: String(asset.existentialDeposit),
8049
+ isDefault: true
8050
+ }))
8051
+ // keep all tokens listed in the config + all tokens marked as sufficient
8052
+ .filter(token => {
8053
+ const configToken = configTokenByOnChainId[token.onChainId];
8054
+ return configToken || token.isSufficient;
8055
+ })
8056
+ // apply config overrides
8057
+ .map(token => {
8058
+ const configToken = configTokenByOnChainId[token.onChainId];
8059
+ return configToken ? lodash.assign({}, token, configToken) : token;
8060
+ })
8061
+ // validate results
8062
+ .filter(t => {
8063
+ const parsed = chaindataProvider.SubForeignAssetsTokenSchema.safeParse(t);
8064
+ if (!parsed.success) log.warn(`Ignoring invalid token ${MODULE_TYPE$4}`, t);
8065
+ return parsed.success;
8066
+ });
8067
+ };
8068
+
8069
+ const getMiniMetadata$4 = ({
8070
+ networkId,
8071
+ specVersion,
8072
+ metadataRpc
8073
+ }) => {
8074
+ const source = MODULE_TYPE$4;
8075
+ const chainId = networkId;
8076
+ const systemVersion = getConstantValue(metadataRpc, "System", "Version");
8077
+ if (specVersion !== systemVersion.spec_version) log.warn("specVersion mismatch", {
8078
+ networkId,
8079
+ specVersion,
8080
+ systemVersion
8081
+ });
8082
+ const id = deriveMiniMetadataId({
8083
+ source,
8084
+ chainId,
8085
+ specVersion
8086
+ });
8087
+ const {
8088
+ unifiedMetadata
8089
+ } = scale.parseMetadataRpc(metadataRpc);
8090
+ if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
8091
+ return {
8092
+ id,
8093
+ source,
8094
+ chainId,
8095
+ specVersion,
8096
+ version: chaindataProvider.MINIMETADATA_VERSION,
8097
+ data: getData$2(metadataRpc),
8098
+ extra: null
8099
+ };
8100
+ };
8101
+ const getData$2 = metadataRpc => {
8102
+ const {
8103
+ metadata,
8104
+ unifiedMetadata
8105
+ } = scale.parseMetadataRpc(metadataRpc);
8106
+
8107
+ // ensure the network has all the required bits
8108
+ if (!hasStorageItems(unifiedMetadata, "ForeignAssets", ["Account", "Asset", "Metadata"])) return null;
8109
+ scale.compactMetadata(metadata, [{
8110
+ pallet: "ForeignAssets",
8111
+ items: ["Account", "Asset", "Metadata"]
8112
+ }]);
8113
+ return scale.encodeMetadata(metadata);
8114
+ };
8115
+
8116
+ const getTransferCallData$4 = ({
8117
+ from,
8118
+ to,
8119
+ value,
8120
+ token,
8121
+ type,
8122
+ metadataRpc
8123
+ }) => {
8124
+ if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$4)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$4}.`);
8125
+ const {
8126
+ builder
8127
+ } = scale.parseMetadataRpc(metadataRpc);
8128
+ const method = getTransferMethod$2(type);
8129
+ const {
8130
+ codec,
8131
+ location
8132
+ } = builder.buildCall("ForeignAssets", method);
8133
+ const args = getEncodedArgs$1(method, token.onChainId, to, value, codec);
8134
+ const callData = polkadotApi.Binary.fromBytes(utils.mergeUint8([new Uint8Array(location), args]));
8135
+ return {
8136
+ address: from,
8137
+ method: callData.asHex()
8138
+ };
8139
+ };
8140
+ const getTransferMethod$2 = type => {
8141
+ switch (type) {
8142
+ case "keep-alive":
8143
+ return "transfer_keep_alive";
8144
+ case "all":
8145
+ return "transfer_all";
8146
+ case "allow-death":
8147
+ return "transfer";
8148
+ }
8149
+ };
8150
+ const getEncodedArgs$1 = (method, onChainId, to, value, argsCodec) => {
8151
+ try {
8152
+ switch (method) {
8153
+ case "transfer_keep_alive":
8154
+ case "transfer":
8155
+ return getTransferEncodedArgs$1(onChainId, to, value, argsCodec);
8156
+ case "transfer_all":
8157
+ return getTransferAllEncodedArgs$1(onChainId, to, argsCodec);
8158
+ }
8159
+ } catch {
8160
+ throw new Error(`Failed to encode arguments for method ${method}: ${onChainId}, ${to}, ${value}`);
8161
+ }
8162
+ };
8163
+ const getEncodedValue$1 = (codec, possibleValue) => {
8164
+ for (const getArgs of possibleValue) {
8165
+ try {
8166
+ return codec.enc(getArgs());
8167
+ } catch (error) {
8168
+ // wrong inputs, ignore and try the next one
8169
+ }
8170
+ }
8171
+ throw new Error("Failed to encode");
8172
+ };
8173
+
8174
+ // same inputs for both KeepAlive and allowDeath
8175
+ const getTransferEncodedArgs$1 = (onChainId, to, value, codec) => {
8176
+ return getEncodedValue$1(codec, [() => ({
8177
+ id: scale.papiParse(onChainId),
8178
+ // for most networks
8179
+ target: polkadotApi.Enum("Id", to),
8180
+ amount: BigInt(value)
8181
+ })]);
8182
+ };
8183
+ const getTransferAllEncodedArgs$1 = (onChainId, to, codec) => {
8184
+ return getEncodedValue$1(codec, [() => ({
8185
+ id: scale.papiParse(onChainId),
8186
+ // for most networks
8187
+ target: polkadotApi.Enum("Id", to),
8188
+ keep_alive: false
8189
+ })]);
8190
+ };
8191
+
8192
+ const SUBSCRIPTION_INTERVAL$4 = 6_000;
8193
+ const subscribeBalances$4 = ({
8194
+ networkId,
8195
+ addressesByToken,
8196
+ connector,
8197
+ miniMetadata
8198
+ }) => {
8199
+ return new rxjs.Observable(subscriber => {
8200
+ const abortController = new AbortController();
8201
+
8202
+ // on hydration balances are fetched using a runtimeApi, which can't be subscribed to.
8203
+ // => poll values for each block
8204
+ const poll = async () => {
8205
+ try {
8206
+ if (abortController.signal.aborted) return;
8207
+ const balances = await fetchBalances$4({
8208
+ networkId,
8209
+ addressesByToken,
8210
+ connector,
8211
+ miniMetadata
8212
+ });
8213
+ if (abortController.signal.aborted) return;
8214
+ subscriber.next(balances);
8215
+ setTimeout(poll, SUBSCRIPTION_INTERVAL$4);
8216
+ } catch (error) {
8217
+ log.error("Error", {
8218
+ module: MODULE_TYPE$4,
8219
+ networkId,
8220
+ miniMetadata,
8221
+ addressesByToken,
8222
+ error
8223
+ });
8224
+ subscriber.error(error);
8225
+ }
8226
+ };
8227
+ poll();
8228
+ return () => {
8229
+ abortController.abort();
8230
+ };
8231
+ }).pipe(rxjs.distinctUntilChanged(lodash.isEqual));
8232
+ };
8233
+
8234
+ const SubForeignAssetsBalanceModule = {
8235
+ type: MODULE_TYPE$4,
8236
+ platform: PLATFORM$4,
8237
+ getMiniMetadata: getMiniMetadata$4,
8238
+ fetchTokens: fetchTokens$4,
8239
+ fetchBalances: fetchBalances$4,
8240
+ subscribeBalances: subscribeBalances$4,
8241
+ getTransferCallData: getTransferCallData$4
8242
+ };
8243
+
8244
+ // to be used by chaindata too
8245
+ z__default.default.strictObject({
8246
+ onChainId: chaindataProvider.SubHydrationTokenSchema.shape.onChainId,
8247
+ ...TokenConfigBaseSchema.shape
8248
+ });
8249
+
8250
+ const MODULE_TYPE$3 = chaindataProvider.SubHydrationTokenSchema.shape.type.value;
8251
+ const PLATFORM$3 = chaindataProvider.SubHydrationTokenSchema.shape.platform.value;
8252
+
8253
+ const fetchRuntimeCallResult = async (connector, networkId, metadataRpc, apiName, method, args) => {
8254
+ const {
8255
+ builder
8256
+ } = scale.parseMetadataRpc(metadataRpc);
8257
+ const call = builder.buildRuntimeCall(apiName, method);
8258
+ const hex = await connector.send(networkId, "state_call", [`${apiName}_${method}`, scale.toHex(call.args.enc(args))]);
8259
+ return call.value.dec(hex);
8260
+ };
8261
+
8262
+ const tryGetConstantValue = (metadataRpc, pallet, constant) => {
8263
+ const {
8264
+ unifiedMetadata,
8265
+ builder
8266
+ } = scale.parseMetadataRpc(metadataRpc);
8267
+ const encodedValue = unifiedMetadata.pallets.find(({
8268
+ name
8269
+ }) => name === pallet)?.constants.find(({
8270
+ name
8271
+ }) => name === constant)?.value;
8272
+ if (!encodedValue) return null;
8273
+ const codec = builder.buildConstant(pallet, constant);
8274
+ return codec.dec(encodedValue);
8275
+ };
8276
+
8277
+ const fetchBalances$3 = async ({
8278
+ networkId,
8279
+ addressesByToken,
8280
+ connector,
8281
+ miniMetadata
8282
+ }) => {
8283
+ const balanceDefs = getBalanceDefs(addressesByToken);
8284
+ if (!miniMetadata?.data) {
8285
+ log.warn("MiniMetadata is required for fetching balances");
8286
+ return {
8287
+ success: [],
8288
+ errors: balanceDefs.map(def => ({
8289
+ tokenId: def.token.id,
8290
+ address: def.address,
8291
+ error: new Error("Minimetadata is required for fetching balances")
8292
+ }))
8293
+ };
8294
+ }
8295
+ if (miniMetadata.source !== MODULE_TYPE$3) {
8296
+ log.warn(`Ignoring miniMetadata with source ${miniMetadata.source} in ${MODULE_TYPE$3}.`);
8297
+ return {
8298
+ success: [],
8299
+ errors: balanceDefs.map(def => ({
8300
+ tokenId: def.token.id,
8301
+ address: def.address,
8302
+ error: new Error(`Invalid request: miniMetadata source is not ${MODULE_TYPE$3}`)
8303
+ }))
8304
+ };
8305
+ }
8306
+ if (miniMetadata.chainId !== networkId) {
8307
+ log.warn(`Ignoring miniMetadata with chainId ${miniMetadata.chainId} in ${MODULE_TYPE$3}. Expected chainId is ${networkId}`);
8308
+ return {
8309
+ success: [],
8310
+ errors: balanceDefs.map(def => ({
8311
+ tokenId: def.token.id,
8312
+ address: def.address,
8313
+ error: new Error(`Invalid request: Expected chainId is ${networkId}`)
8314
+ }))
8315
+ };
8316
+ }
8317
+ const addresses = lodash.uniq(balanceDefs.map(def => def.address));
8318
+ try {
8319
+ const res = await Promise.all(addresses.map(address => fetchRuntimeCallResult(connector, networkId, miniMetadata.data, "CurrenciesApi", "accounts", [address])));
8320
+ const fetchedBalances = addresses.flatMap((address, index) => {
8321
+ return res[index].map(([onChainId, balance]) => ({
8322
+ address,
8323
+ onChainId,
8324
+ free: balance.free.toString(),
8325
+ reserved: balance.reserved.toString(),
8326
+ frozen: balance.frozen.toString()
8327
+ })).filter(b => b.onChainId !== undefined);
8328
+ });
8329
+ const balancesByKey = lodash.keyBy(fetchedBalances, b => `${b.address}:${b.onChainId}`);
8330
+ const success = addressesByToken.reduce((acc, [token, addresses]) => {
8331
+ if (token.type === MODULE_TYPE$3) for (const address of addresses) {
8332
+ const rawBalance = balancesByKey[`${address}:${token.onChainId}`];
8333
+
8334
+ // the endpoint only returns entries for which the address has a non-zero balance
8335
+ // => generate an zero balance object if not found
8336
+ const balance = {
8337
+ address,
8338
+ networkId,
8339
+ tokenId: token.id,
8340
+ source: MODULE_TYPE$3,
8341
+ status: "cache",
8342
+ values: [{
8343
+ type: "free",
8344
+ label: "free",
8345
+ amount: rawBalance?.free.toString() ?? "0"
8346
+ }, {
8347
+ type: "reserved",
8348
+ label: "reserved",
8349
+ amount: rawBalance?.reserved.toString() ?? "0"
8350
+ }, {
8351
+ type: "locked",
8352
+ label: "frozen",
8353
+ amount: rawBalance?.frozen.toString() ?? "0"
8354
+ }]
8355
+ };
8356
+ acc.push(balance);
8357
+ }
8358
+ return acc;
8359
+ }, []);
8360
+ return {
8361
+ success,
8362
+ errors: []
8363
+ };
8364
+ } catch (err) {
8365
+ log.warn("Failed to fetch balances for substrate-hydration", err);
8366
+ const errors = balanceDefs.map(def => ({
8367
+ tokenId: def.token.id,
8368
+ address: def.address,
8369
+ error: new Error(`Failed to fetch balance for ${def.address} on ${networkId}`)
8370
+ }));
8371
+ return {
8372
+ success: [],
8373
+ errors
8374
+ };
8375
+ }
8376
+ };
8377
+
8378
+ const fetchTokens$3 = async ({
8379
+ networkId,
8380
+ tokens,
8381
+ connector,
8382
+ miniMetadata
8383
+ }) => {
8384
+ const anyMiniMetadata = miniMetadata;
8385
+ if (!anyMiniMetadata?.data) return [];
8386
+ const {
8387
+ builder
8388
+ } = scale.parseMetadataRpc(anyMiniMetadata.data);
8389
+ const assetsCodec = builder.buildStorage("AssetRegistry", "Assets");
8390
+ const allAssetStorageKeys = await connector.send(networkId, "state_getKeys", [scale.getStorageKeyPrefix("AssetRegistry", "Assets")]);
8391
+ const assetStorageResults = await connector.send(networkId, "state_queryStorageAt", [allAssetStorageKeys]);
8392
+ const assetStorageEntries = assetStorageResults[0].changes;
8393
+ const configTokenByAssetId = lodash.keyBy(tokens, t => t.onChainId);
8394
+ return assetStorageEntries.map(([key, value]) => {
8395
+ // parse results
8396
+ const [onChainId] = assetsCodec.keys.dec(key);
8397
+ const asset = assetsCodec.value.dec(value);
8398
+ return {
8399
+ onChainId,
8400
+ assetType: asset.asset_type.type,
8401
+ isSufficient: asset.is_sufficient,
8402
+ name: asset.name?.asText(),
8403
+ symbol: asset.symbol?.asText(),
8404
+ decimals: asset.decimals,
8405
+ existentialDeposit: asset.existential_deposit.toString()
8406
+ };
8407
+ })
8408
+ // exclude unsupported asset types
8409
+ .filter(({
8410
+ assetType
8411
+ }) => ["Erc20", "Token"].includes(assetType))
8412
+ // convert asset to a SubHydrationToken
8413
+ .map(asset => ({
8414
+ id: chaindataProvider.subHydrationTokenId(networkId, asset.onChainId),
8415
+ type: MODULE_TYPE$3,
8416
+ platform: "polkadot",
8417
+ networkId,
8418
+ onChainId: asset.onChainId,
8419
+ assetType: asset.assetType,
8420
+ // Erc20 or Token,
8421
+ isSufficient: asset.isSufficient,
8422
+ name: asset.name,
8423
+ symbol: asset.symbol,
8424
+ decimals: asset.decimals ?? 0,
8425
+ existentialDeposit: asset.existentialDeposit,
8426
+ isDefault: true
8427
+ }))
8428
+ // keep all tokens listed in the config + all tokens marked as sufficient
8429
+ .filter(token => {
8430
+ const configToken = configTokenByAssetId[token.onChainId];
8431
+ return configToken || token.isSufficient;
8432
+ })
8433
+ // apply config overrides
8434
+ .map(token => {
8435
+ const configToken = configTokenByAssetId[token.onChainId];
8436
+ return configToken ? lodash.assign({}, token, configToken) : token;
8437
+ })
8438
+ // validate results
8439
+ .filter(t => {
8440
+ const parsed = chaindataProvider.SubHydrationTokenSchema.safeParse(t);
8441
+ if (!parsed.success) log.warn(`Ignoring invalid token ${MODULE_TYPE$3}`, t);
8442
+ return parsed.success;
8443
+ });
8444
+ };
8445
+
8446
+ const getMiniMetadata$3 = ({
8447
+ networkId,
8448
+ specVersion,
8449
+ metadataRpc
8450
+ }) => {
8451
+ const source = MODULE_TYPE$3;
8452
+ const chainId = networkId;
8453
+ const systemVersion = getConstantValue(metadataRpc, "System", "Version");
8454
+ if (specVersion !== systemVersion.spec_version) log.warn("specVersion mismatch", {
8455
+ networkId,
8456
+ specVersion,
8457
+ systemVersion
8458
+ });
8459
+ const id = deriveMiniMetadataId({
8460
+ source,
8461
+ chainId,
8462
+ specVersion
8463
+ });
8464
+ const {
8465
+ unifiedMetadata
8466
+ } = scale.parseMetadataRpc(metadataRpc);
8467
+ if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
8468
+ return {
8469
+ id,
8470
+ source,
8471
+ chainId,
8472
+ specVersion,
8473
+ version: chaindataProvider.MINIMETADATA_VERSION,
8474
+ data: getData$1(metadataRpc),
8475
+ extra: null
8476
+ };
8477
+ };
8478
+ const getData$1 = metadataRpc => {
8479
+ const {
8480
+ metadata,
8481
+ unifiedMetadata
8482
+ } = scale.parseMetadataRpc(metadataRpc);
8483
+
8484
+ // ensure the network has all the required bits
8485
+ if (!hasStorageItem(unifiedMetadata, "AssetRegistry", "Assets") || !hasStorageItem(unifiedMetadata, "Tokens", "Accounts") || !hasRuntimeApi(unifiedMetadata, "CurrenciesApi", "accounts")) return null;
8486
+ scale.compactMetadata(metadata, [{
8487
+ pallet: "AssetRegistry",
8488
+ items: ["Assets"]
8489
+ },
8490
+ // token specs
8491
+ {
8492
+ pallet: "Tokens",
8493
+ items: ["Accounts"]
8494
+ } // balances for tokens
8495
+ ], [{
8496
+ runtimeApi: "CurrenciesApi",
8497
+ methods: ["accounts"]
8498
+ }]);
8499
+ return scale.encodeMetadata(metadata);
8500
+ };
8501
+
8502
+ const getTransferCallData$3 = ({
8503
+ from,
8504
+ to,
8505
+ value,
8506
+ token,
8507
+ metadataRpc
8508
+ }) => {
8509
+ if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$3)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$3}.`);
8510
+
8511
+ // there is only one transfer method, no existential deposit handling.
8512
+ // => leave this to the frontend and dry runs
8513
+ const {
8514
+ builder
8515
+ } = scale.parseMetadataRpc(metadataRpc);
8516
+ const {
8517
+ codec,
8518
+ location
8519
+ } = builder.buildCall("Currencies", "transfer");
8520
+ const args = {
8521
+ dest: to,
8522
+ currency_id: token.onChainId,
8523
+ amount: BigInt(value)
8524
+ };
8525
+ const callData = polkadotApi.Binary.fromBytes(utils.mergeUint8([new Uint8Array(location), codec.enc(args)]));
8526
+ return {
8527
+ address: from,
8528
+ method: callData.asHex()
8529
+ };
8530
+ };
8531
+
8532
+ const SUBSCRIPTION_INTERVAL$3 = 6_000;
8533
+ const subscribeBalances$3 = ({
8534
+ networkId,
8535
+ addressesByToken,
8536
+ connector,
8537
+ miniMetadata
8538
+ }) => {
8539
+ return new rxjs.Observable(subscriber => {
8540
+ const abortController = new AbortController();
8541
+
8542
+ // on hydration balances are fetched using a runtimeApi, which can't be subscribed to.
8543
+ // => poll values for each block
8544
+ const poll = async () => {
8545
+ try {
8546
+ if (abortController.signal.aborted) return;
8547
+ const balances = await fetchBalances$3({
8548
+ networkId,
8549
+ addressesByToken,
8550
+ connector,
8551
+ miniMetadata
8552
+ });
8553
+ if (abortController.signal.aborted) return;
8554
+ subscriber.next(balances);
8555
+ setTimeout(poll, SUBSCRIPTION_INTERVAL$3);
8556
+ } catch (error) {
8557
+ log.error("Error", {
8558
+ module: MODULE_TYPE$3,
8559
+ networkId,
8560
+ miniMetadata,
8561
+ addressesByToken,
8562
+ error
8563
+ });
8564
+ subscriber.error(error);
8565
+ }
8566
+ };
8567
+ poll();
8568
+ return () => {
8569
+ abortController.abort();
8570
+ };
8571
+ }).pipe(rxjs.distinctUntilChanged(lodash.isEqual));
8572
+ };
8573
+
8574
+ const SubHydrationBalanceModule = {
8575
+ type: MODULE_TYPE$3,
8576
+ platform: PLATFORM$3,
8577
+ getMiniMetadata: getMiniMetadata$3,
8578
+ fetchTokens: fetchTokens$3,
8579
+ fetchBalances: fetchBalances$3,
8580
+ subscribeBalances: subscribeBalances$3,
8581
+ getTransferCallData: getTransferCallData$3
8582
+ };
8583
+
8584
+ const MODULE_TYPE$2 = chaindataProvider.SubNativeTokenSchema.shape.type.value;
8585
+ const PLATFORM$2 = chaindataProvider.SubNativeTokenSchema.shape.platform.value;
8586
+
8587
+ // to be used by chaindata too
8588
+ z__default.default.strictObject({
8589
+ ...TokenConfigBaseSchema.shape
8590
+ });
8591
+
8592
+ // Do not use this type outside of this module
8593
+
8594
+ // Do not use this type outside of this module
8595
+
8596
+ // Do not use this type outside of this module
8597
+
8598
+ /**
8599
+ * Pass some these into an `RpcStateQueryHelper` in order to easily batch multiple state queries into the one rpc call.
8600
+ */
8601
+
8602
+ const fetchQueriesPack = async (connector, networkId, queries) => {
8603
+ const allStateKeys = queries.flatMap(({
8604
+ stateKeys
8605
+ }) => stateKeys).filter(util.isNotNil);
8606
+
8607
+ // doing a query with only null keys would throw an error => return early
8608
+ if (!allStateKeys.length) return queries.map(({
8609
+ stateKeys,
8610
+ decodeResult
8611
+ }) => decodeResult(stateKeys.map(() => null)));
8612
+ const response = await connector.send(networkId, "state_queryStorageAt", [allStateKeys]);
8613
+ const results = queries.reduce((acc, {
8614
+ stateKeys,
8615
+ decodeResult
8616
+ }) => {
8617
+ const changes = stateKeys.map(stateKey => {
8618
+ if (!stateKey) return null;
8619
+ const change = response[0].changes.find(([key]) => key === stateKey);
8620
+ if (!change) return null;
8621
+ return change[1];
8622
+ });
8623
+ acc.push(decodeResult(changes));
8624
+ return acc;
8625
+ }, []);
8626
+ return results;
8627
+ };
8628
+
8629
+ /**
8630
+ * Used by a variety of balance modules to help batch multiple state queries into the one rpc call.
8631
+ */
8632
+ // export class RpcStateQueriesHelper<T> {
8633
+ // #connector: ChainConnector
8634
+ // #queries: Array<RpcStateQueries<T>>
8635
+
8636
+ // constructor(connector: ChainConnector, queries: Array<RpcStateQueries<T>>) {
8637
+ // this.#connector = connector
8638
+ // this.#queries = queries
8639
+ // }
8640
+
8641
+ // async subscribe(
8642
+ // networkId: DotNetworkId,
8643
+ // callback: SubscriptionCallback<T[]>,
8644
+ // timeout: number | false = false,
8645
+ // subscribeMethod = "state_subscribeStorage",
8646
+ // responseMethod = "state_storage",
8647
+ // unsubscribeMethod = "state_unsubscribeStorage",
8648
+ // ): Promise<UnsubscribeFn> {
8649
+ // const params = [this.#queries.flatMap(({ stateKeys }) => stateKeys)]
8650
+
8651
+ // const unsub = this.#connector.subscribe(
8652
+ // networkId,
8653
+ // subscribeMethod,
8654
+ // responseMethod,
8655
+ // params,
8656
+ // (error, result) => {
8657
+ // error
8658
+ // ? callback(error)
8659
+ // : callback(null, this.#distributeChangesToQueryDecoders.call(this, chainId, result))
8660
+ // },
8661
+ // timeout,
8662
+ // )
8663
+
8664
+ // const subscriptions = queries.map(([chainId, queries]) => {
8665
+ // const params = [queries.map(({ stateKey }) => stateKey)]
8666
+
8667
+ // const unsub = this.#connector.subscribe(
8668
+ // networkId,
8669
+ // subscribeMethod,
8670
+ // responseMethod,
8671
+ // params,
8672
+ // (error, result) => {
8673
+ // error
8674
+ // ? callback(error)
8675
+ // : callback(null, this.#distributeChangesToQueryDecoders.call(this, chainId, result))
8676
+ // },
8677
+ // timeout,
8678
+ // )
8679
+
8680
+ // return () => unsub.then((unsubscribe) => unsubscribe(unsubscribeMethod))
8681
+ // })
8682
+
8683
+ // return () => subscriptions.forEach((unsubscribe) => unsubscribe())
8684
+ // }
8685
+
8686
+ // async fetch(method = "state_queryStorageAt"): Promise<T[]> {
8687
+ // const queriesByChain = groupBy(this.#queries, "chainId")
8688
+
8689
+ // const resultsByChain = await Promise.all(
8690
+ // Object.entries(queriesByChain).map(async ([chainId, queries]) => {
8691
+ // const params = [queries.map(({ stateKey }) => stateKey)]
8692
+
8693
+ // const result = (await this.#connector.send(chainId, method, params))[0]
8694
+ // return this.#distributeChangesToQueryDecoders.call(this, chainId, result)
8695
+ // }),
8696
+ // )
8697
+
8698
+ // return resultsByChain.flatMap((result) => result)
8699
+ // }
8700
+
8701
+ // #distributeChangesToQueryDecoders(chainId: DotNetworkId, result: unknown): T[] {
8702
+ // if (typeof result !== "object" || result === null) return []
8703
+ // if (!hasOwnProperty(result, "changes") || typeof result.changes !== "object") return []
8704
+ // if (!Array.isArray(result.changes)) return []
8705
+
8706
+ // return result.changes.flatMap(([reference, change]: [unknown, unknown]): [T] | [] => {
8707
+ // if (typeof reference !== "string") {
8708
+ // log.warn(`Received non-string reference in RPC result: ${reference}`)
8709
+ // return []
8710
+ // }
8711
+
8712
+ // if (typeof change !== "string" && change !== null) {
8713
+ // log.warn(`Received non-string and non-null change in RPC result: ${reference} | ${change}`)
8714
+ // return []
8715
+ // }
8716
+
8717
+ // const query = this.#queries.find(
8718
+ // ({ chainId: cId, stateKey }) => cId === chainId && stateKey === reference,
8719
+ // )
8720
+ // if (!query) {
8721
+ // log.warn(
8722
+ // `Failed to find query:\n${reference} in\n${this.#queries.map(({ stateKey }) => stateKey)}`,
8723
+ // )
8724
+ // return []
8725
+ // }
8726
+
8727
+ // return [query.decodeResult(change)]
8728
+ // })
8729
+ // }
8730
+ // }
8731
+
8732
+ const SUBTENSOR_ROOT_NETUID = 0;
8733
+ const SUBTENSOR_MIN_STAKE_AMOUNT_PLANK = 1000000n;
8734
+ const TAO_DECIMALS = 9n;
8735
+ const SCALE_FACTOR = 10n ** TAO_DECIMALS; // Equivalent to 10e9 for precision
8736
+ const ONE_ALPHA_TOKEN = SCALE_FACTOR;
8737
+ const calculateAlphaPrice = ({
8738
+ dynamicInfo
8739
+ }) => {
8740
+ if (!dynamicInfo) return 0n;
8741
+ const {
8742
+ alpha_in,
8743
+ tao_in
8744
+ } = dynamicInfo;
8745
+
8746
+ // Scale taoIn before division to preserve precision
8747
+ const result = tao_in * SCALE_FACTOR / alpha_in;
8748
+ return result; // Scaled price as bigint
8749
+ };
8750
+ const calculateTaoAmountFromAlpha = ({
8751
+ alphaPrice,
8752
+ alphaStaked
8753
+ }) => {
8754
+ if (!alphaStaked || !alphaPrice) return 0n;
8755
+ const expectedAlpha = alphaStaked * alphaPrice;
8756
+ return expectedAlpha / SCALE_FACTOR;
8757
+ };
8758
+ const calculateTaoFromDynamicInfo = ({
8759
+ dynamicInfo,
8760
+ alphaStaked
8761
+ }) => {
8762
+ const alphaPrice = calculateAlphaPrice({
8763
+ dynamicInfo
8764
+ });
8765
+ return calculateTaoAmountFromAlpha({
8766
+ alphaPrice,
8767
+ alphaStaked
8768
+ });
8769
+ };
8770
+
8771
+ // per address, lists of values to add to the native balance
8772
+
8773
+ const getSubtensorStakingBalances$ = (connector, networkId, balanceDefs, miniMetadata) => {
8774
+ const addresses = balanceDefs.map(def => def.address);
8775
+ const token = balanceDefs[0].token;
8776
+ if (!addresses.length || !token || !miniMetadata.extra.hasSubtensorPallet || !miniMetadata.data) return rxjs.of({});
8777
+
8778
+ // we are only doing runtime calls, there is no way to subscribe to changes, except polling
8779
+ // => start immediately, then repeat every 30 seconds
8780
+ return rxjs.timer(0, 30000).pipe(rxjs.switchMap(() => rxjs.from(fetchStakeInfoByAddress(connector, networkId, miniMetadata, addresses)).pipe(rxjs.switchMap(stakeInfoByAddress => fetchStakingBalanceValuesByAddress(connector, networkId, miniMetadata, stakeInfoByAddress)))));
8781
+ };
8782
+ const fetchStakingBalanceValuesByAddress = async (connector, networkId, miniMetadata, stakeInfoByAddress) => {
8783
+ const uniqueNetuids = lodash.uniq(lodash.values(stakeInfoByAddress).flatMap(infos => infos.map(info => info.netuid))).filter(netuid => netuid !== SUBTENSOR_ROOT_NETUID);
8784
+ const dynamicInfoByNetuid = await fetchDynamicInfoByNetuid(connector, networkId, miniMetadata, uniqueNetuids);
8785
+ return lodash.fromPairs(lodash.toPairs(stakeInfoByAddress).map(([address, stakeInfos]) => {
8786
+ const stakesBalances = stakeInfos.filter(({
8787
+ stake
8788
+ }) => stake >= SUBTENSOR_MIN_STAKE_AMOUNT_PLANK).map(({
8789
+ hotkey,
8790
+ netuid,
8791
+ stake
8792
+ }) => ({
8793
+ hotkey,
8794
+ netuid: Number(netuid),
8795
+ stake: BigInt(stake),
8796
+ dynamicInfo: dynamicInfoByNetuid[Number(netuid)]
8797
+ })).map(({
8798
+ hotkey,
8799
+ stake,
8800
+ netuid,
8801
+ dynamicInfo
8802
+ }) => {
8803
+ const {
8804
+ token_symbol,
8805
+ subnet_name,
8806
+ subnet_identity
8807
+ } = dynamicInfo ?? {};
8808
+ const tokenSymbol = new TextDecoder().decode(Uint8Array.from(token_symbol ?? []));
8809
+ const subnetName = new TextDecoder().decode(Uint8Array.from(subnet_name ?? []));
8810
+ const subnetIdentity = subnet_identity ? lodash.fromPairs(lodash.toPairs(subnet_identity).map(([key, binary]) => [key, binary.asText()])) : undefined;
8811
+
8812
+ // Add 1n balance if failed to fetch dynamic info, so the position is not ignored by Balance lib and is displayed in the UI.
8813
+ const alphaStakedInTao = dynamicInfo ? calculateTaoFromDynamicInfo({
8814
+ dynamicInfo,
8815
+ alphaStaked: stake
8816
+ }) : 1n;
8817
+ const alphaToTaoRate = calculateTaoFromDynamicInfo({
8818
+ dynamicInfo: dynamicInfo ?? null,
8819
+ alphaStaked: ONE_ALPHA_TOKEN
8820
+ }).toString();
8821
+ const stakeByNetuid = Number(netuid) === SUBTENSOR_ROOT_NETUID ? stake : alphaStakedInTao;
8822
+ const balanceValue = {
8823
+ source: "subtensor-staking",
8824
+ type: "subtensor",
8825
+ label: "subtensor-staking",
8826
+ amount: stakeByNetuid.toString(),
8827
+ meta: {
8828
+ type: "subtensor-staking",
8829
+ hotkey,
8830
+ netuid,
8831
+ amountStaked: stake.toString(),
8832
+ alphaToTaoRate,
8833
+ dynamicInfo: {
8834
+ tokenSymbol,
8835
+ subnetName,
8836
+ subnetIdentity: {
8837
+ ...subnetIdentity,
8838
+ subnetName: subnetIdentity?.subnet_name || subnetName
8839
+ }
8840
+ }
8841
+ }
8842
+ };
8843
+ return balanceValue;
8844
+ });
8845
+ return [address, stakesBalances];
8846
+ }));
8847
+ };
8848
+ const fetchStakeInfoByAddress = async (connector, networkId, miniMetadata, addresses) => {
8849
+ const pairs = await Promise.all(addresses.map(async address => [address, await viem.withRetry(() => fetchRuntimeCallResult(connector, networkId, miniMetadata.data, "StakeInfoRuntimeApi", "get_stake_info_for_coldkey", [address]), {
8850
+ delay: 500,
8851
+ retryCount: 3
8852
+ })]));
8853
+ return lodash.fromPairs(pairs);
8854
+ };
8855
+
8856
+ // assume dynamic info doesnt change over the course of a browser session
8857
+ const dynamicInfoCache = new Map();
8858
+ const getCacheKey = (networkId, netuid) => `${networkId}:${netuid}`;
8859
+ const fetchDynamicInfoByNetuid = async (connector, networkId, miniMetadata, uniqueNetuids) => {
8860
+ const fetchInfo = async netuid => {
8861
+ if (netuid === SUBTENSOR_ROOT_NETUID) return null;
8862
+ const cacheKey = getCacheKey(networkId, netuid);
8863
+ if (!dynamicInfoCache.has(cacheKey)) {
8864
+ await viem.withRetry(async () => {
8865
+ const result = await fetchRuntimeCallResult(connector, networkId, miniMetadata.data, "SubnetInfoRuntimeApi", "get_dynamic_info", [netuid]);
8866
+ dynamicInfoCache.set(cacheKey, result); // Cache successful response
8867
+
8868
+ return result;
8869
+ }, {
8870
+ delay: 500,
8871
+ retryCount: 3
8872
+ });
8873
+ }
8874
+ return dynamicInfoCache.get(cacheKey) ?? null;
8875
+ };
8876
+ const results = await Promise.all(uniqueNetuids.map(async netuid => [netuid, await fetchInfo(netuid)]));
8877
+ return lodash.fromPairs(results);
8878
+ };
8879
+
8880
+ const getOtherType = input => `other-${input}`;
8881
+
8882
+ /**
8883
+ * For converting the value of `lock?.id?.toUtf8?.()` which is retrieved from
8884
+ * the Balances.Locks storage key into a useful classification for our UI
8885
+ */
8886
+ const getLockedType = input => {
8887
+ if (typeof input !== "string") return getOtherType("unknown");
8888
+ if (input.includes("vesting")) return "vesting";
8889
+ if (input.includes("calamvst")) return "vesting"; // vesting on manta network
8890
+ if (input.includes("ormlvest")) return "vesting"; // vesting ORML tokens
8891
+ if (input.includes("pyconvot")) return "democracy";
8892
+ if (input.includes("democrac")) return "democracy";
8893
+ if (input.includes("democracy")) return "democracy";
8894
+ if (input.includes("phrelect")) return "democracy"; // specific to council
8895
+ if (input.includes("staking")) return "staking";
8896
+ if (input.includes("stkngdel")) return "staking"; // staking delegator
8897
+ if (input.includes("stkngcol")) return "staking"; // staking collator
8898
+ if (input.includes("kiltpstk")) return "staking"; // Kilt specific staking
8899
+ if (input.includes("dapstake")) return "dapp-staking"; // Astar specific
8900
+ if (input.includes("appstake")) return "dapp-staking"; // Quartz (unique) specific
8901
+ if (input.includes("dappstaking")) return "dapp-staking";
8902
+
8903
+ // Joystream specifics https://github.com/Joystream/pioneer/blob/dev/packages/ui/src/accounts/model/lockTypes.ts
8904
+ if (input.includes("voting")) return "democracy";
8905
+ if (input.includes("candidac")) return "democracy"; // Council Candidate
8906
+ if (input.includes("councilo")) return "democracy"; // Councilor
8907
+ if (input.includes("proposal")) return "democracy";
8908
+ if (input.includes("boundsta")) return "staking"; // Bound Staking Account
8909
+ if (input.includes("invitemb")) return getOtherType(input); // Invite member
8910
+ if (input.includes("bounty")) return getOtherType(input);
8911
+ if (input.startsWith("wg-")) return getOtherType(input);
8912
+
8913
+ // ignore technical or undocumented lock types
8914
+ if (input.includes("pdexlock")) return getOtherType(input);
8915
+ if (input.includes("phala/sp")) return getOtherType(input);
8916
+ if (input.includes("aca/earn")) return getOtherType(input);
8917
+ if (input.includes("stk_stks")) return getOtherType(input);
8918
+
8919
+ // eslint-disable-next-line no-console
8920
+ console.warn(`unknown locked type: ${input}`);
8921
+ return getOtherType(input);
8922
+ };
8923
+
8924
+ const buildBaseQueries = (networkId, balanceDefs, miniMetadata) => {
8925
+ const networkStorageCoders = buildNetworkStorageCoders(networkId, miniMetadata, {
8926
+ account: ["System", "Account"],
8927
+ stakingLedger: ["Staking", "Ledger"],
8928
+ reserves: ["Balances", "Reserves"],
8929
+ // unused ??
8930
+ holds: ["Balances", "Holds"],
8931
+ locks: ["Balances", "Locks"],
8932
+ freezes: ["Balances", "Freezes"],
8933
+ poolMembers: ["NominationPools", "PoolMembers"]
8934
+ });
8935
+ if (!networkStorageCoders) throw new Error(`No network storage coders found for networkId: ${networkId}`);
8936
+ return balanceDefs.map(({
8937
+ token,
8938
+ address
8939
+ }) => {
8940
+ const accountStateKey = networkStorageCoders.account ? networkStorageCoders.account.keys.enc(address) : null;
8941
+ const locksStateKey = networkStorageCoders.locks ? networkStorageCoders.locks.keys.enc(address) : null;
8942
+ const freezesStateKey = networkStorageCoders.freezes ? networkStorageCoders.freezes.keys.enc(address) : null;
8943
+ const holdsStateKey = networkStorageCoders.holds ? networkStorageCoders.holds.keys.enc(address) : null;
8944
+ const stakingLedgerStateKey = networkStorageCoders.stakingLedger ? networkStorageCoders.stakingLedger.keys.enc(address) : null;
8945
+ const poolMemberStateKey = networkStorageCoders.poolMembers ? networkStorageCoders.poolMembers.keys.enc(address) : null;
8946
+ const stateKeys = [accountStateKey, locksStateKey, freezesStateKey, holdsStateKey, stakingLedgerStateKey, poolMemberStateKey];
8947
+ return {
8948
+ stateKeys,
8949
+ decodeResult: changes => {
8950
+ const balance = {
8951
+ source: "substrate-native",
8952
+ status: "live",
8953
+ address,
8954
+ networkId,
8955
+ tokenId: token.id,
8956
+ values: [],
8957
+ useLegacyTransferableCalculation: miniMetadata.extra.useLegacyTransferableCalculation
8958
+ };
8959
+ let nomPoolMemberInfo = null;
8960
+ const [accountChange, lockChange, freezesChange, holdsChange, stakingLedgerChange, nomPoolMemberChange] = changes;
8961
+ if (networkStorageCoders.account) {
8962
+ // for account balance we decode even empty values
8963
+ const baseValues = decodeBaseResult(networkStorageCoders.account, accountChange, networkId);
8964
+ balance.values.push(...baseValues);
8965
+ }
8966
+ if (networkStorageCoders.locks && lockChange) {
8967
+ const lockValues = decodeLocksResult(networkStorageCoders.locks, lockChange, networkId);
8968
+ balance.values.push(...lockValues);
8969
+ }
8970
+ if (networkStorageCoders.freezes && freezesChange) {
8971
+ const freezesValues = decodeFreezesResult(networkStorageCoders.freezes, freezesChange, networkId);
8972
+ balance.values.push(...freezesValues);
8973
+ }
8974
+ if (networkStorageCoders.holds && holdsChange) {
8975
+ const holdsValues = decodeHoldsResult(networkStorageCoders.holds, holdsChange, networkId);
8976
+ balance.values.push(...holdsValues);
8977
+ }
8978
+ if (networkStorageCoders.stakingLedger && stakingLedgerChange) {
8979
+ const stakingLedgerValues = decodeStakingLedgerResult(networkStorageCoders.stakingLedger, stakingLedgerChange, networkId);
8980
+ balance.values.push(...stakingLedgerValues);
8981
+ }
8982
+ if (networkStorageCoders.poolMembers && nomPoolMemberChange) {
8983
+ const nomPoolMemberValue = decodePoolMemberResult(networkStorageCoders.poolMembers, nomPoolMemberChange, networkId);
8984
+ if (nomPoolMemberValue) nomPoolMemberInfo = nomPoolMemberValue;
8985
+ }
8986
+ return {
8987
+ balance,
8988
+ nomPoolMemberInfo
8989
+ };
8990
+ }
8991
+ };
8992
+ }).filter(util.isNotNil);
8993
+ };
8994
+
8995
+ // AccountInfo is the state_storage data format for nativeToken balances
8996
+ // Theory: new chains will be at least on metadata v14, and so we won't need to hardcode their AccountInfo type.
8997
+ // But for chains we want to support which aren't on metadata v14, hardcode them here:
8998
+ // If the chain upgrades to metadata v14, this override will be ignored :)
8999
+ // const RegularAccountInfoFallback = Struct({
9000
+ // nonce: u32,
9001
+ // consumers: u32,
9002
+ // providers: u32,
9003
+ // sufficients: u32,
9004
+ // data: Struct({ free: u128, reserved: u128, miscFrozen: u128, feeFrozen: u128 }),
9005
+ // })
9006
+ // const NoSufficientsAccountInfoFallback = Struct({
9007
+ // nonce: u32,
9008
+ // consumers: u32,
9009
+ // providers: u32,
9010
+ // data: Struct({ free: u128, reserved: u128, miscFrozen: u128, feeFrozen: u128 }),
9011
+ // })
9012
+ // const AccountInfoOverrides: Record<
9013
+ // string,
9014
+ // typeof RegularAccountInfoFallback | typeof NoSufficientsAccountInfoFallback | undefined
9015
+ // > = {
9016
+ // // crown-sterlin is not yet on metadata v14
9017
+ // "crown-sterling": NoSufficientsAccountInfoFallback,
9018
+
9019
+ // // crust is not yet on metadata v14
9020
+ // "crust": NoSufficientsAccountInfoFallback,
9021
+
9022
+ // // kulupu is not yet on metadata v14
9023
+ // "kulupu": RegularAccountInfoFallback,
9024
+
9025
+ // // nftmart is not yet on metadata v14
9026
+ // "nftmart": RegularAccountInfoFallback,
9027
+ // }
9028
+
9029
+ const decodeBaseResult = (coder, value, networkId) => {
9030
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9031
+
9032
+ const decoded = scale.decodeScale(coder, value, `Failed to decode base native balance on chain ${networkId}`);
9033
+ const free = (decoded?.data?.free ?? 0n).toString();
9034
+ const reserved = (decoded?.data?.reserved ?? 0n).toString();
9035
+ const miscLock = ((decoded?.data?.miscFrozen ?? 0n) + (
9036
+ // new chains don't split their `frozen` amount into `feeFrozen` and `miscFrozen`.
9037
+ // for these chains, we'll use the `frozen` amount as `miscFrozen`.
9038
+ decoded?.data?.frozen ?? 0n)).toString();
9039
+ const feesLock = (decoded?.data?.feeFrozen ?? 0n).toString();
9040
+
9041
+ // even if these values are 0, we still need to add them to the balanceJson.values array
9042
+ // so that the balance pool can handle newly zeroed balances
9043
+ // const existingValues = Object.fromEntries(
9044
+ // balanceJson.values.map((v) => [getValueId(v), v]),
9045
+ // )
9046
+ const newValues = [{
9047
+ type: "free",
9048
+ label: "free",
9049
+ amount: free.toString()
9050
+ }, {
9051
+ type: "reserved",
9052
+ label: "reserved",
9053
+ amount: reserved.toString()
9054
+ }, {
9055
+ type: "locked",
9056
+ label: "misc",
9057
+ amount: miscLock.toString()
9058
+ }, {
9059
+ type: "locked",
9060
+ label: "fees",
9061
+ amount: feesLock.toString()
9062
+ }];
9063
+ return newValues;
9064
+ };
9065
+ const decodeLocksResult = (coder, value, networkId) => {
9066
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9067
+
9068
+ const decoded = scale.decodeScale(coder, value, `Failed to decode lock on chain ${networkId}`);
9069
+ const locksQueryLocks = decoded?.map?.(lock => ({
9070
+ type: "locked",
9071
+ source: "substrate-native-locks",
9072
+ label: getLockedType(lock?.id?.asText?.()),
9073
+ meta: {
9074
+ id: lock?.id?.asText?.()
9075
+ },
9076
+ amount: (lock?.amount ?? 0n).toString()
9077
+ })) ?? [];
9078
+ return locksQueryLocks;
9079
+
9080
+ // // locked values should be replaced entirely, not merged or appended
9081
+ // const nonLockValues = balanceJson.values.filter(
9082
+ // (v) => v.source !== "substrate-native-locks",
9083
+ // )
9084
+ // balanceJson.values = nonLockValues.concat(locksQueryLocks)
9085
+
9086
+ // // fix any double-counting between Balances.Locks (for staking locks) and Staking.Ledger (for unbonding locks)
9087
+ // balanceJson.values = updateStakingLocksUsingUnbondingLocks(balanceJson.values)
9088
+ };
9089
+ const decodeFreezesResult = (coder, value, networkId) => {
9090
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9091
+
9092
+ const decoded = scale.decodeScale(coder, value, `Failed to decode freeze on chain ${networkId}`);
9093
+ const freezesValues = decoded?.map?.(lock => ({
9094
+ type: "locked",
9095
+ source: "substrate-native-freezes",
9096
+ label: getLockedType(lock?.id?.type?.toLowerCase?.()),
9097
+ amount: lock?.amount?.toString?.() ?? "0"
9098
+ })) ?? [];
9099
+ return freezesValues;
9100
+
9101
+ // // freezes values should be replaced entirely, not merged or appended
9102
+ // const nonFreezesValues = balanceJson.values.filter(
9103
+ // (v) => v.source !== "substrate-native-freezes",
9104
+ // )
9105
+ // balanceJson.values = nonFreezesValues.concat(freezesQueryLocks)
9106
+
9107
+ // return balanceJson
9108
+ };
9109
+ const decodeHoldsResult = (coder, value, networkId) => {
9110
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9111
+
9112
+ const decoded = scale.decodeScale(coder, value, `Failed to decode holds on chain ${networkId}`);
9113
+
9114
+ // at this time we re only interested in DelegatedStaking holds, to determine if nom pool staked amount is included in reserved or not
9115
+ const holdsValues = decoded?.filter(hold => hold.id?.type).map(hold => ({
9116
+ type: "locked",
9117
+ source: "substrate-native-holds",
9118
+ label: hold.id.type,
9119
+ // anount needs to be 0 or a row could appear in the UI, this entry is just for information
9120
+ amount: "0",
9121
+ meta: {
9122
+ amount: (hold?.amount ?? 0n).toString()
9123
+ }
9124
+ })) ?? [];
9125
+ return holdsValues;
9126
+
9127
+ // // values should be replaced entirely, not merged or appended
9128
+ // const nonHoldsValues = balanceJson.values.filter(
9129
+ // (v) => v.source !== "substrate-native-holds",
9130
+ // )
9131
+ // balanceJson.values = nonHoldsValues.concat(holdsQueryLocks)
9132
+
9133
+ // return balanceJson
9134
+ };
9135
+ const decodeStakingLedgerResult = (coder, value, networkId) => {
9136
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9137
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9138
+
9139
+ const decoded = scale.decodeScale(coder, value, `Failed to decode unbonding query on chain ${networkId}`);
9140
+ const totalUnlocking = decoded?.unlocking?.reduce?.((acc, unlocking) => acc + unlocking.value, 0n) ?? 0n;
9141
+ const stakingLedgerResults = totalUnlocking <= 0n ? [] : [{
9142
+ type: "locked",
9143
+ source: "substrate-native-unbonding",
9144
+ label: "Unbonding",
9145
+ amount: totalUnlocking.toString()
9146
+ }];
9147
+ return stakingLedgerResults;
9148
+
9149
+ // if (totalUnlocking <= 0n) unbondingQueryLocks = []
9150
+ // else {
9151
+ // unbondingQueryLocks = [
9152
+ // {
9153
+ // type: "locked",
9154
+ // source: "substrate-native-unbonding",
9155
+ // label: "Unbonding",
9156
+ // amount: totalUnlocking.toString(),
9157
+ // },
9158
+ // ]
9159
+ // }
9160
+
9161
+ // // unbonding values should be replaced entirely, not merged or appended
9162
+ // const nonUnbondingValues = balanceJson.values.filter(
9163
+ // (v) => v.source !== "substrate-native-unbonding",
9164
+ // )
9165
+ // balanceJson.values = nonUnbondingValues.concat(unbondingQueryLocks)
9166
+
9167
+ // // fix any double-counting between Balances.Locks (for staking locks) and Staking.Ledger (for unbonding locks)
9168
+ // balanceJson.values = updateStakingLocksUsingUnbondingLocks(balanceJson.values)
9169
+
9170
+ // return balanceJson
9171
+ };
9172
+ const decodePoolMemberResult = (coder, value, networkId) => {
9173
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9174
+
9175
+ const decoded = scale.decodeScale(coder, value, `Failed to decode poolMembers on chain ${networkId}`);
9176
+ if (!decoded) return null;
9177
+ const poolId = decoded.pool_id.toString();
9178
+ const points = decoded.points.toString();
9179
+ const unbondingEras = Array.from(decoded.unbonding_eras ?? []).flatMap(entry => {
9180
+ if (entry === undefined) return [];
9181
+ const [key, value] = Array.from(entry);
9182
+ const era = key.toString();
9183
+ const amount = value.toString();
9184
+ if (typeof era !== "string" || typeof amount !== "string") return [];
9185
+ return {
9186
+ era,
9187
+ amount
9188
+ };
9189
+ });
9190
+ return {
9191
+ poolId,
9192
+ points,
9193
+ unbondingEras
9194
+ };
9195
+ };
9196
+
9197
+ // const getBaseQuery = (
9198
+ // networkId: string,
9199
+ // address: string,
9200
+ // coder: ScaleStorageCoder,
9201
+ // ): RpcStateQuery<Array<AmountWithLabel<string>>> | null => {
9202
+ // // For chains which are using metadata < v14
9203
+ // const getFallbackStateKey = () => {
9204
+ // const addressBytes = decodeAnyAddress(address) // TODO replace with modern api, this is slow
9205
+ // const addressHash = blake2Concat(addressBytes).replace(/^0x/, "")
9206
+ // const moduleHash = "26aa394eea5630e07c48ae0c9558cef7" // util_crypto.xxhashAsHex("System", 128);
9207
+ // const storageHash = "b99d880ec681799c0cf30e8886371da9" // util_crypto.xxhashAsHex("Account", 128);
9208
+ // const moduleStorageHash = `${moduleHash}${storageHash}` // System.Account is the state_storage key prefix for nativeToken balances
9209
+ // return `0x${moduleStorageHash}${addressHash}`
9210
+ // }
9211
+
9212
+ // // const scaleCoder = chainStorageCoders.get(chainId)?.base
9213
+ // // NOTE: Only use fallback key when `scaleCoder` is not defined
9214
+ // // i.e. when chain doesn't have metadata v14/v15
9215
+ // const stateKey = coder
9216
+ // ? encodeStateKey(coder, `Invalid address in ${networkId} base query ${address}`, address)
9217
+ // : getFallbackStateKey()
9218
+ // if (!stateKey) return null
9219
+
9220
+ // const decodeResult = (change: string | null) => {
9221
+ // // BEGIN: Handle chains which use metadata < v14
9222
+ // let oldChainBalance = null
9223
+ // if (!coder) {
9224
+ // const scaleAccountInfo = AccountInfoOverrides[networkId]
9225
+ // if (scaleAccountInfo === undefined) {
9226
+ // // chain metadata version is < 15 and we also don't have an override hardcoded in
9227
+ // // the best way to handle this case: log a warning and return an empty balance
9228
+ // log.debug(
9229
+ // `Native token on chain ${networkId} has no balance type for decoding. Defaulting to a balance of 0 (zero).`,
9230
+ // )
9231
+ // return []
9232
+ // }
9233
+
9234
+ // try {
9235
+ // // eslint-disable-next-line no-var
9236
+ // oldChainBalance = change === null ? null : scaleAccountInfo.dec(change)
9237
+ // } catch (error) {
9238
+ // log.warn(
9239
+ // `Failed to create pre-metadataV14 balance type for native on chain ${networkId}: ${error?.toString()}`,
9240
+ // )
9241
+ // return []
9242
+ // }
9243
+ // }
9244
+ // // END: Handle chains which use metadata < v14
9245
+
9246
+ // /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9247
+ // type DecodedType = {
9248
+ // data?: {
9249
+ // flags?: bigint
9250
+ // free?: bigint
9251
+ // frozen?: bigint
9252
+ // reserved?: bigint
9253
+
9254
+ // // deprecated fields (they only show up on old chains)
9255
+ // feeFrozen?: bigint
9256
+ // miscFrozen?: bigint
9257
+ // }
9258
+ // }
9259
+ // const decoded =
9260
+ // decodeScale<DecodedType>(
9261
+ // coder,
9262
+ // change,
9263
+ // `Failed to decode base native balance on chain ${networkId}`,
9264
+ // ) ?? oldChainBalance
9265
+
9266
+ // const free = (decoded?.data?.free ?? 0n).toString()
9267
+ // const reserved = (decoded?.data?.reserved ?? 0n).toString()
9268
+ // const miscLock = (
9269
+ // (decoded?.data?.miscFrozen ?? 0n) +
9270
+ // // new chains don't split their `frozen` amount into `feeFrozen` and `miscFrozen`.
9271
+ // // for these chains, we'll use the `frozen` amount as `miscFrozen`.
9272
+ // ((decoded?.data as DecodedType["data"])?.frozen ?? 0n)
9273
+ // ).toString()
9274
+ // const feesLock = (decoded?.data?.feeFrozen ?? 0n).toString()
9275
+
9276
+ // // even if these values are 0, we still need to add them to the balanceJson.values array
9277
+ // // so that the balance pool can handle newly zeroed balances
9278
+ // // const existingValues = Object.fromEntries(
9279
+ // // balanceJson.values.map((v) => [getValueId(v), v]),
9280
+ // // )
9281
+ // const newValues: AmountWithLabel<string>[] = [
9282
+ // { type: "free", label: "free", amount: free.toString() },
9283
+ // { type: "reserved", label: "reserved", amount: reserved.toString() },
9284
+ // { type: "locked", label: "misc", amount: miscLock.toString() },
9285
+ // { type: "locked", label: "fees", amount: feesLock.toString() },
9286
+ // ]
9287
+
9288
+ // return newValues
9289
+
9290
+ // // const newValuesObj = Object.fromEntries(newValues.map((v) => [getValueId(v), v]))
9291
+
9292
+ // // balanceJson.values = Object.values({ ...existingValues, ...newValuesObj })
9293
+
9294
+ // // return balanceJson
9295
+ // }
9296
+
9297
+ // return { chainId: networkId, stateKey, decodeResult }
9298
+ // }
9299
+
9300
+ /**
9301
+ * Each nominationPool in the nominationPools pallet has access to some accountIds which have no
9302
+ * associated private key. Instead, they are derived from this function.
9303
+ */
9304
+ const nompoolAccountId = (palletId, poolId, index) => {
9305
+ const utf8Encoder = new TextEncoder();
9306
+ const encModPrefix = utf8Encoder.encode("modl");
9307
+ const encPalletId = utf8Encoder.encode(palletId);
9308
+ const encIndex = new Uint8Array([index]);
9309
+ const encPoolId = scaleTs.u32.enc(typeof poolId === "string" ? parseInt(poolId, 10) : poolId);
9310
+ const length = encModPrefix.length + encPalletId.length + encIndex.length + encPoolId.length;
9311
+ const remainingBytes = 32 - length;
9312
+ const encEmptyH256 = new Uint8Array(remainingBytes);
9313
+ const bytes = utils.mergeUint8([encModPrefix, encPalletId, encIndex, encPoolId, encEmptyH256]);
9314
+ return polkadotApi.AccountId().dec(bytes);
9315
+ };
9316
+ /** The stash account for the nomination pool */
9317
+ const nompoolStashAccountId = (palletId, poolId) => nompoolAccountId(palletId, poolId, 0);
9318
+
9319
+ const buildNomPoolQueries = (networkId, partialBalances, miniMetadata) => {
9320
+ const networkStorageCoders = getNomPoolCoders(networkId, miniMetadata);
9321
+ if (!networkStorageCoders) throw new Error(`No network storage coders found for networkId: ${networkId}`);
9322
+ return partialBalances.map(({
9323
+ balance,
9324
+ nomPoolMemberInfo
9325
+ }) => {
9326
+ const stateKeys = getNomPoolStateKeys(networkStorageCoders, nomPoolMemberInfo, miniMetadata.extra);
9327
+ return {
9328
+ stateKeys,
9329
+ decodeResult: changes => {
9330
+ if (!nomPoolMemberInfo || !stateKeys.length || changes.includes(null)) return balance;
9331
+ const accountPoints = nomPoolMemberInfo?.points ?? "0";
9332
+ const {
9333
+ poolPoints = "0"
9334
+ } = decodePoolPoints(networkStorageCoders.bondedPools, changes[0], networkId);
9335
+ const {
9336
+ poolTotalActiveStake = "0"
9337
+ } = decodePoolStake(networkStorageCoders.ledger, changes[1], networkId);
9338
+ const {
9339
+ metadata = "0"
9340
+ } = decodePoolMeta(networkStorageCoders.metadata, changes[2], networkId);
9341
+ const amount = accountPoints === "0" || poolPoints === "0" || poolTotalActiveStake === "0" ? 0n : BigInt(poolTotalActiveStake) * BigInt(accountPoints) / BigInt(poolPoints);
9342
+ const unbondingAmount = nomPoolMemberInfo.unbondingEras.reduce((total, {
9343
+ amount
9344
+ }) => total + BigInt(amount ?? "0"), 0n);
9345
+ return {
9346
+ ...balance,
9347
+ values: [...(balance.values ?? []), {
9348
+ source: "nompools-staking",
9349
+ type: "nompool",
9350
+ label: "nompools-staking",
9351
+ amount: amount.toString(),
9352
+ meta: {
9353
+ type: "nompool",
9354
+ poolId: nomPoolMemberInfo.poolId,
9355
+ description: metadata
9356
+ }
9357
+ }, {
9358
+ source: "nompools-staking",
9359
+ type: "nompool",
9360
+ label: "nompools-unbonding",
9361
+ amount: unbondingAmount.toString(),
9362
+ meta: {
9363
+ poolId: nomPoolMemberInfo.poolId,
9364
+ description: metadata ?? `Pool ${nomPoolMemberInfo.poolId}`,
9365
+ unbonding: true
9366
+ }
9367
+ }]
9368
+ };
9369
+ }
9370
+ };
9371
+ });
9372
+ };
9373
+ const getNomPoolCoders = (networkId, miniMetadata) => {
9374
+ return buildNetworkStorageCoders(networkId, miniMetadata, {
9375
+ poolMembers: ["NominationPools", "PoolMembers"],
9376
+ bondedPools: ["NominationPools", "BondedPools"],
9377
+ ledger: ["Staking", "Ledger"],
9378
+ metadata: ["NominationPools", "Metadata"]
9379
+ });
9380
+ };
9381
+ const decodePoolPoints = (coder, value, networkId) => {
9382
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9383
+
9384
+ const decoded = scale.decodeScale(coder, value, `Failed to decode bondedPools on chain ${networkId}`);
9385
+ return {
9386
+ poolPoints: decoded?.points.toString()
9387
+ };
9388
+ };
9389
+ const decodePoolStake = (coder, value, networkId) => {
9390
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9391
+
9392
+ const decoded = scale.decodeScale(coder, value, `Failed to decode ledger on chain ${networkId}`);
9393
+ return {
9394
+ poolTotalActiveStake: decoded?.active.toString()
9395
+ };
9396
+ };
9397
+ const decodePoolMeta = (coder, value, networkId) => {
9398
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
9399
+
9400
+ const decoded = scale.decodeScale(coder, value, `Failed to decode metadata on chain ${networkId}`);
9401
+ const metadata = decoded?.asText();
9402
+ return {
9403
+ metadata
9404
+ };
9405
+ };
9406
+ const getNomPoolStateKeys = (coders, nomPoolMemberInfo, extra) => {
9407
+ if (!nomPoolMemberInfo || !extra.nominationPoolsPalletId || !coders?.bondedPools || !coders.ledger || !coders.metadata) return [];
9408
+ const poolId = nomPoolMemberInfo.poolId;
9409
+ const stashAddress = nompoolStashAccountId(extra.nominationPoolsPalletId, poolId);
9410
+ const poolPointsStateKey = coders.bondedPools.keys.enc(poolId);
9411
+ const poolStakeStateKey = coders.ledger.keys.enc(stashAddress);
9412
+ const poolMetaStateKey = coders.metadata.keys.enc(poolId);
9413
+ return [poolPointsStateKey, poolStakeStateKey, poolMetaStateKey];
9414
+ };
9415
+
9416
+ const fetchBalances$2 = async ({
9417
+ networkId,
9418
+ addressesByToken,
9419
+ connector,
9420
+ miniMetadata
9421
+ }) => {
9422
+ const balanceDefs = getBalanceDefs(addressesByToken);
9423
+ if (!miniMetadata?.data) {
9424
+ log.warn("MiniMetadata is required for fetching balances");
9425
+ return {
9426
+ success: [],
9427
+ errors: balanceDefs.map(def => ({
9428
+ tokenId: def.token.id,
9429
+ address: def.address,
9430
+ error: new Error("Minimetadata is required for fetching balances")
9431
+ }))
9432
+ };
9433
+ }
9434
+ if (miniMetadata.source !== MODULE_TYPE$2) {
9435
+ log.warn(`Ignoring miniMetadata with source ${miniMetadata.source} in ${MODULE_TYPE$2}.`);
9436
+ return {
9437
+ success: [],
9438
+ errors: balanceDefs.map(def => ({
9439
+ tokenId: def.token.id,
9440
+ address: def.address,
9441
+ error: new Error(`Invalid request: miniMetadata source is not ${MODULE_TYPE$2}`)
9442
+ }))
9443
+ };
9444
+ }
9445
+ if (miniMetadata.chainId !== networkId) {
9446
+ log.warn(`Ignoring miniMetadata with chainId ${miniMetadata.chainId} in ${MODULE_TYPE$2}. Expected chainId is ${networkId}`);
9447
+ return {
9448
+ success: [],
9449
+ errors: balanceDefs.map(def => ({
9450
+ tokenId: def.token.id,
9451
+ address: def.address,
9452
+ error: new Error(`Invalid request: Expected chainId is ${networkId}`)
9453
+ }))
9454
+ };
9455
+ }
9456
+ const queries = buildBaseQueries(networkId, balanceDefs, miniMetadata);
9457
+ const partialBalances = await fetchQueriesPack(connector, networkId, queries);
9458
+
9459
+ // now for each balance that includes nomPoolStaking, we need to fetch the metadata for the pool
9460
+ const nomPoolQueries = buildNomPoolQueries(networkId, partialBalances, miniMetadata);
9461
+ const balances = await fetchQueriesPack(connector, networkId, nomPoolQueries);
9462
+
9463
+ // TODO ⚠️ dedupe locks
9464
+
9465
+ const subtensorBalances$ = getSubtensorStakingBalances$(connector, networkId, balanceDefs, miniMetadata);
9466
+ const subtensorBalancesByAddress = await rxjs.firstValueFrom(subtensorBalances$);
9467
+ for (const [address, subtensorBalances] of Object.entries(subtensorBalancesByAddress)) {
9468
+ const balance = balances.find(b => b.address === address);
9469
+ if (balance?.values) balance.values.push(...subtensorBalances);
9470
+ }
9471
+ return {
9472
+ success: balances,
9473
+ errors: []
9474
+ };
9475
+ };
9476
+
9477
+ const fetchTokens$2 = async ({
9478
+ networkId,
9479
+ tokens,
9480
+ connector,
9481
+ miniMetadata
9482
+ }) => {
9483
+ if (miniMetadata.extra.disable) return [];
9484
+ const {
9485
+ tokenSymbol: symbol,
9486
+ tokenDecimals: decimals
9487
+ } = await getChainProperties(connector, networkId);
9488
+ if (!miniMetadata.extra.existentialDeposit) log.warn(`Substrate native module: existentialDeposit is undefined for ${networkId}, using 0`);
9489
+ const tokenConfig = tokens[0];
9490
+ const nativeToken = {
9491
+ id: chaindataProvider.subNativeTokenId(networkId),
9492
+ type: "substrate-native",
9493
+ platform: "polkadot",
9494
+ networkId,
9495
+ isDefault: true,
9496
+ symbol: symbol,
9497
+ name: symbol,
9498
+ decimals: decimals,
9499
+ existentialDeposit: miniMetadata.extra.existentialDeposit ?? "0"
9500
+ };
9501
+ return [lodash.assign(nativeToken, tokenConfig)];
9502
+ };
9503
+ const DotNetworkPropertiesSimple = z__default.default.object({
9504
+ tokenDecimals: z__default.default.number().optional().default(0),
9505
+ tokenSymbol: z__default.default.string().optional().default("Unit")
9506
+ });
9507
+ const DotNetworkPropertiesArray = z__default.default.object({
9508
+ tokenDecimals: z__default.default.array(z__default.default.number()).nonempty(),
9509
+ tokenSymbol: z__default.default.array(z__default.default.string()).nonempty()
9510
+ });
9511
+ const DotNetworkPropertiesSchema = z__default.default.union([DotNetworkPropertiesSimple, DotNetworkPropertiesArray]).transform(val => ({
9512
+ tokenDecimals: Array.isArray(val.tokenDecimals) ? val.tokenDecimals[0] : val.tokenDecimals,
9513
+ tokenSymbol: Array.isArray(val.tokenSymbol) ? val.tokenSymbol[0] : val.tokenSymbol
9514
+ }));
9515
+ const getChainProperties = async (connector, networkId) => {
9516
+ const properties = await connector.send(networkId, "system_properties", [], true);
9517
+ return DotNetworkPropertiesSchema.parse(properties);
9518
+ };
9519
+
9520
+ const getMiniMetadata$2 = ({
9521
+ networkId,
9522
+ specVersion,
9523
+ metadataRpc,
9524
+ config
9525
+ }) => {
9526
+ const source = MODULE_TYPE$2;
9527
+ const chainId = networkId;
9528
+ const systemVersion = getConstantValue(metadataRpc, "System", "Version");
9529
+ if (specVersion !== systemVersion.spec_version) log.warn("specVersion mismatch", {
9530
+ networkId,
9531
+ specVersion,
9532
+ systemVersion
9533
+ });
9534
+ const id = deriveMiniMetadataId({
9535
+ source,
9536
+ chainId,
9537
+ specVersion
9538
+ });
9539
+ const {
9540
+ metadata,
9541
+ unifiedMetadata
9542
+ } = scale.parseMetadataRpc(metadataRpc);
9543
+ if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
9544
+ if (config?.disable) return {
9545
+ id,
9546
+ source,
9547
+ chainId,
9548
+ specVersion,
9549
+ version: chaindataProvider.MINIMETADATA_VERSION,
9550
+ data: null,
9551
+ extra: {
9552
+ disable: true
9553
+ }
9554
+ };
9555
+ const existentialDeposit = tryGetConstantValue(metadataRpc, "Balances", "ExistentialDeposit")?.toString();
9556
+ const nominationPoolsPalletId = tryGetConstantValue(metadataRpc, "NominationPools", "PalletId")?.asText();
9557
+ const hasSubtensorPallet = !!tryGetConstantValue(metadataRpc, "SubtensorModule", "KeySwapCost");
9558
+ const hasFreezesItem = Boolean(unifiedMetadata.pallets.find(({
9559
+ name
9560
+ }) => name === "Balances")?.storage?.items.find(({
9561
+ name
9562
+ }) => name === "Freezes"));
9563
+ const useLegacyTransferableCalculation = !hasFreezesItem;
9564
+ scale.compactMetadata(metadata, [{
9565
+ pallet: "System",
9566
+ constants: ["Version", "SS58Prefix"],
9567
+ items: ["Account"]
9568
+ }, {
9569
+ pallet: "Balances",
9570
+ items: ["Reserves", "Holds", "Locks", "Freezes"]
9571
+ }, {
9572
+ pallet: "NominationPools",
9573
+ items: ["PoolMembers", "BondedPools", "Metadata"]
9574
+ }, {
9575
+ pallet: "Staking",
9576
+ items: ["Ledger"]
9577
+ },
9578
+ // TotalColdkeyStake is used until v.2.2.1, then it is replaced by StakingHotkeys+Stake
9579
+ // Need to keep TotalColdkeyStake for a while so chaindata keeps including it in miniMetadatas, so it doesnt break old versions of the wallet
9580
+ // TODO: Since chaindata v4 this is safe to now delete
9581
+ {
9582
+ pallet: "SubtensorModule",
9583
+ items: ["TotalColdkeyStake", "StakingHotkeys", "Stake"]
9584
+ }], [{
9585
+ runtimeApi: "StakeInfoRuntimeApi",
9586
+ methods: ["get_stake_info_for_coldkey"]
9587
+ }, {
9588
+ runtimeApi: "SubnetInfoRuntimeApi",
9589
+ methods: ["get_dynamic_info"]
9590
+ }]);
9591
+ return {
9592
+ id,
9593
+ source,
9594
+ chainId,
9595
+ specVersion,
9596
+ version: chaindataProvider.MINIMETADATA_VERSION,
9597
+ data: scale.encodeMetadata(metadata),
9598
+ extra: {
9599
+ useLegacyTransferableCalculation,
9600
+ existentialDeposit,
9601
+ nominationPoolsPalletId,
9602
+ hasSubtensorPallet
9603
+ }
9604
+ };
9605
+ };
9606
+
9607
+ const getTransferCallData$2 = ({
9608
+ from,
9609
+ to,
9610
+ value,
9611
+ token,
9612
+ type,
9613
+ metadataRpc
9614
+ }) => {
9615
+ if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$2)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$2}.`);
9616
+ const {
9617
+ unifiedMetadata,
9618
+ lookupFn,
9619
+ builder
9620
+ } = scale.parseMetadataRpc(metadataRpc);
9621
+ const method = getTransferMethod$1(type, unifiedMetadata, lookupFn);
9622
+ const {
9623
+ codec,
9624
+ location
9625
+ } = builder.buildCall("Balances", method);
9626
+ const args = getEncodedArgs(method, to, value, codec);
9627
+ const callData = polkadotApi.Binary.fromBytes(utils.mergeUint8([new Uint8Array(location), args]));
9628
+ return {
9629
+ address: from,
9630
+ method: callData.asHex()
9631
+ };
9632
+ };
9633
+ const getTransferMethod$1 = (type, unifiedMetadata, lookupFn) => {
9634
+ switch (type) {
9635
+ case "keep-alive":
9636
+ return "transfer_keep_alive";
9637
+ case "all":
9638
+ return "transfer_all";
9639
+ case "allow-death":
9640
+ {
9641
+ const callType = unifiedMetadata.pallets.find(pallet => pallet.name === "Balances")?.calls?.type;
9642
+ if (callType) {
9643
+ const palletCalls = lookupFn(callType);
9644
+ if (palletCalls.type === "enum" && palletCalls.value["transfer_allow_death"]) return "transfer_allow_death";
9645
+ }
9646
+
9647
+ // legacy fallback
9648
+ return "transfer";
9649
+ }
9650
+ }
9651
+ };
9652
+ const getEncodedArgs = (method, to, value, argsCodec) => {
9653
+ try {
9654
+ switch (method) {
9655
+ case "transfer_allow_death":
9656
+ case "transfer_keep_alive":
9657
+ case "transfer":
9658
+ return getTransferEncodedArgs(to, value, argsCodec);
9659
+ case "transfer_all":
9660
+ return getTransferAllEncodedArgs(to, argsCodec);
9661
+ }
9662
+ } catch {
9663
+ throw new Error(`Failed to encode arguments for method ${method}, ${to}, ${value}`);
9664
+ }
9665
+ };
9666
+ const getEncodedValue = (codec, possibleValue) => {
9667
+ for (const getArgs of possibleValue) {
9668
+ try {
9669
+ return codec.enc(getArgs());
9670
+ } catch {
9671
+ // wrong inputs, ignore and try the next one
9672
+ }
9673
+ }
9674
+ throw new Error("Failed to encode");
9675
+ };
9676
+
9677
+ // same inputs for both KeepAlive and allowDeath
9678
+ const getTransferEncodedArgs = (to, value, codec) => {
9679
+ return getEncodedValue(codec, [() => ({
9680
+ dest: polkadotApi.Enum("Id", to),
9681
+ value: BigInt(value)
9682
+ })]);
9683
+ };
9684
+ const getTransferAllEncodedArgs = (to, codec) => {
9685
+ return getEncodedValue(codec, [() => ({
9686
+ dest: polkadotApi.Enum("Id", to),
9687
+ keep_alive: false
9688
+ })]);
9689
+ };
9690
+
9691
+ const SUBSCRIPTION_INTERVAL$2 = 6_000;
9692
+ const subscribeBalances$2 = ({
9693
+ networkId,
9694
+ addressesByToken,
9695
+ connector,
9696
+ miniMetadata
9697
+ }) => {
9698
+ return new rxjs.Observable(subscriber => {
9699
+ const abortController = new AbortController();
9700
+
9701
+ // on hydration balances are fetched using a runtimeApi, which can't be subscribed to.
9702
+ // => poll values for each block
9703
+ const poll = async () => {
9704
+ try {
9705
+ if (abortController.signal.aborted) return;
9706
+ const balances = await fetchBalances$2({
9707
+ networkId,
9708
+ addressesByToken,
9709
+ connector,
9710
+ miniMetadata
9711
+ });
9712
+ if (abortController.signal.aborted) return;
9713
+ subscriber.next(balances);
9714
+ setTimeout(poll, SUBSCRIPTION_INTERVAL$2);
9715
+ } catch (error) {
9716
+ log.error("Error", {
9717
+ module: MODULE_TYPE$2,
9718
+ networkId,
9719
+ miniMetadata,
9720
+ addressesByToken,
9721
+ error
9722
+ });
9723
+ subscriber.error(error);
9724
+ }
9725
+ };
9726
+ poll();
9727
+ return () => {
9728
+ abortController.abort();
9729
+ };
9730
+ }).pipe(rxjs.distinctUntilChanged(lodash.isEqual));
9731
+ };
9732
+
9733
+ const SubNativeBalanceModule = {
9734
+ type: MODULE_TYPE$2,
9735
+ platform: PLATFORM$2,
9736
+ getMiniMetadata: getMiniMetadata$2,
9737
+ fetchTokens: fetchTokens$2,
9738
+ fetchBalances: fetchBalances$2,
9739
+ subscribeBalances: subscribeBalances$2,
9740
+ getTransferCallData: getTransferCallData$2
9741
+ };
9742
+
9743
+ const MODULE_TYPE$1 = chaindataProvider.SubPsp22TokenSchema.shape.type.value;
9744
+ const PLATFORM$1 = chaindataProvider.SubPsp22TokenSchema.shape.platform.value;
9745
+
9746
+ // to be used by chaindata too
9747
+ z__default.default.strictObject({
9748
+ contractAddress: chaindataProvider.SubPsp22TokenSchema.shape.contractAddress,
9749
+ ...TokenConfigBaseSchema.shape
9750
+ });
9751
+
9752
+ const fetchBalances$1 = async ({
9753
+ networkId,
9754
+ addressesByToken,
9755
+ connector
9756
+ }) => {
9757
+ const balanceDefs = getBalanceDefs(addressesByToken);
9758
+ if (!balanceDefs.length) return {
9759
+ success: [],
9760
+ errors: []
9761
+ };
9762
+ const registry = new types.TypeRegistry();
9763
+ const Psp22Abi = new apiContract.Abi(psp22Abi);
9764
+ const contractCall = makeContractCaller({
9765
+ chainConnector: connector,
9766
+ chainId: networkId,
9767
+ registry
9768
+ });
9769
+ const results = await Promise.allSettled(balanceDefs.map(async ({
9770
+ token,
9771
+ address
9772
+ }) => {
9773
+ const result = await contractCall(address, token.contractAddress, Psp22Abi.findMessage("PSP22::balance_of").toU8a([address]));
9774
+ if (!result.result.isOk) throw new Error("Failed to fetch balance");
9775
+ const value = registry.createType("Balance", result.result.asOk.data).toString();
9776
+ const balance = {
9777
+ source: "substrate-psp22",
9778
+ status: "live",
9779
+ address,
9780
+ networkId: token.networkId,
9781
+ tokenId: token.id,
9782
+ value
9783
+ };
9784
+ return balance;
9785
+ }));
9786
+ return results.reduce((acc, result) => {
9787
+ if (result.status === "fulfilled") acc.success.push(result.value);else {
9788
+ const error = result.reason;
9789
+ acc.errors.push({
9790
+ tokenId: error.tokenId,
9791
+ address: error.address,
9792
+ error
9793
+ });
9794
+ }
9795
+ return acc;
9796
+ }, {
9797
+ success: [],
9798
+ errors: []
9799
+ });
9800
+ };
9801
+
9802
+ const fetchTokens$1 = async ({
9803
+ networkId,
9804
+ tokens,
9805
+ connector
9806
+ }) => {
9807
+ if (!tokens.length) return [];
9808
+ const registry = new types.TypeRegistry();
9809
+ const Psp22Abi = new apiContract.Abi(psp22Abi);
9810
+
9811
+ // TODO: Use `decodeOutput` from `./util/decodeOutput`
9812
+ const contractCall = makeContractCaller({
9813
+ chainConnector: connector,
9814
+ chainId: networkId,
9815
+ registry
9816
+ });
9817
+ const tokenList = {};
9818
+ for (const tokenConfig of tokens ?? []) {
9819
+ try {
9820
+ let symbol = tokenConfig?.symbol ?? "Unit";
9821
+ let decimals = tokenConfig?.decimals ?? 0;
9822
+ const contractAddress = tokenConfig?.contractAddress ?? undefined;
9823
+ if (contractAddress === undefined) continue;
9824
+ await (async () => {
9825
+ const [symbolResult, decimalsResult] = await Promise.all([contractCall(contractAddress, contractAddress, Psp22Abi.findMessage("PSP22Metadata::token_symbol").toU8a([])), contractCall(contractAddress, contractAddress, Psp22Abi.findMessage("PSP22Metadata::token_decimals").toU8a([]))]);
9826
+
9827
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9828
+ const symbolData = symbolResult.toJSON()?.result?.ok?.data;
9829
+ symbol = typeof symbolData === "string" && symbolData.startsWith("0x") ? util$1.u8aToString(registry.createType("Option<Vec<u8>>",
9830
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9831
+ symbolResult.toJSON()?.result?.ok?.data)?.value)?.replace(/\p{C}/gu, "") : symbol;
9832
+
9833
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9834
+ const decimalsData = decimalsResult.toJSON()?.result?.ok?.data;
9835
+ decimals = typeof decimalsData === "string" && decimalsData.startsWith("0x") ? util$1.hexToNumber(decimalsData) : decimals;
9836
+ })();
9837
+ const id = chaindataProvider.subPsp22TokenId(networkId, contractAddress);
9838
+ const token = {
9839
+ id,
9840
+ type: "substrate-psp22",
9841
+ platform: "polkadot",
9842
+ isDefault: tokenConfig.isDefault ?? true,
9843
+ symbol,
9844
+ decimals,
9845
+ name: tokenConfig?.name || symbol,
9846
+ logo: tokenConfig?.logo,
9847
+ contractAddress,
9848
+ networkId
9849
+ };
9850
+ if (tokenConfig?.coingeckoId) token.coingeckoId = tokenConfig?.coingeckoId;
9851
+ if (tokenConfig?.mirrorOf) token.mirrorOf = tokenConfig?.mirrorOf;
9852
+ tokenList[token.id] = token;
9853
+ } catch (error) {
9854
+ log.error(`Failed to build substrate-psp22 token ${tokenConfig.contractAddress} (${tokenConfig.symbol}) on ${networkId}`, error?.message ?? error);
9855
+ continue;
9856
+ }
9857
+ }
9858
+ return lodash.values(tokenList).filter(t => {
9859
+ const parsed = chaindataProvider.SubPsp22TokenSchema.safeParse(t);
9860
+ if (!parsed.success) log.warn(`Ignoring invalid token ${MODULE_TYPE$1}`, t);
9861
+ return parsed.success;
9862
+ });
9863
+ };
9864
+
9865
+ const getMiniMetadata$1 = ({
9866
+ networkId,
9867
+ specVersion,
9868
+ metadataRpc
9869
+ }) => {
9870
+ const source = MODULE_TYPE$1;
9871
+ const chainId = networkId;
9872
+ const systemVersion = getConstantValue(metadataRpc, "System", "Version");
9873
+ if (specVersion !== systemVersion.spec_version) log.warn("specVersion mismatch", {
9874
+ networkId,
9875
+ specVersion,
9876
+ systemVersion
9877
+ });
9878
+ const id = deriveMiniMetadataId({
9879
+ source,
9880
+ chainId,
9881
+ specVersion
9882
+ });
9883
+ const {
9884
+ unifiedMetadata
9885
+ } = scale.parseMetadataRpc(metadataRpc);
9886
+ if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
9887
+ return {
9888
+ id,
9889
+ source,
9890
+ chainId,
9891
+ specVersion,
9892
+ version: chaindataProvider.MINIMETADATA_VERSION,
9893
+ data: null,
9894
+ extra: null
9895
+ };
9896
+ };
9897
+
9898
+ const getTransferCallData$1 = async ({
9899
+ from,
9900
+ to,
9901
+ value,
9902
+ token,
9903
+ metadataRpc,
9904
+ connector
9905
+ }) => {
9906
+ if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE$1)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE$1}.`);
9907
+ const networkId = chaindataProvider.parseTokenId(token.id).networkId;
9908
+ const {
9909
+ builder
9910
+ } = scale.parseMetadataRpc(metadataRpc);
9911
+ const {
9912
+ codec,
9913
+ location
9914
+ } = builder.buildCall("Contracts", "call");
9915
+ const Psp22Abi = new apiContract.Abi(psp22Abi);
9916
+ const registry = new types.TypeRegistry();
9917
+ const contractCall = makeContractCaller({
9918
+ chainConnector: connector,
9919
+ chainId: networkId,
9920
+ registry
9921
+ });
9922
+
9923
+ // TODO use papi contract api
9924
+ const data = Psp22Abi.findMessage("PSP22::transfer").toU8a([to, value, undefined]);
9925
+ const hexData = registry.createType("Vec<u8>", data).toHex();
9926
+ const dryRunResult = await contractCall(from, token.contractAddress, data);
9927
+ const args = codec.enc({
9928
+ dest: polkadotApi.Enum("Id", token.contractAddress),
9929
+ value: 0,
9930
+ gas_limit: {
9931
+ ref_time: dryRunResult.gasRequired.refTime.toBigInt(),
9932
+ proof_size: dryRunResult.gasRequired.proofSize.toBigInt()
9933
+ },
9934
+ storage_deposit_limit: dryRunResult.storageDeposit.isCharge ? dryRunResult.storageDeposit.asCharge.toBigInt() : null,
9935
+ data: polkadotApi.Binary.fromHex(hexData)
9936
+ });
9937
+ const callData = polkadotApi.Binary.fromBytes(utils.mergeUint8([new Uint8Array(location), args]));
9938
+ return {
9939
+ address: from,
9940
+ method: callData.asHex()
9941
+ };
9942
+ };
9943
+
9944
+ const SUBSCRIPTION_INTERVAL$1 = 6_000;
9945
+ const subscribeBalances$1 = ({
9946
+ networkId,
9947
+ addressesByToken,
9948
+ connector,
9949
+ miniMetadata
9950
+ }) => {
9951
+ return new rxjs.Observable(subscriber => {
9952
+ const abortController = new AbortController();
9953
+
9954
+ // on hydration balances are fetched using a runtimeApi, which can't be subscribed to.
9955
+ // => poll values for each block
9956
+ const poll = async () => {
9957
+ try {
9958
+ if (abortController.signal.aborted) return;
9959
+ const balances = await fetchBalances$1({
9960
+ networkId,
9961
+ addressesByToken,
9962
+ connector,
9963
+ miniMetadata
9964
+ });
9965
+ if (abortController.signal.aborted) return;
9966
+ subscriber.next(balances);
9967
+ setTimeout(poll, SUBSCRIPTION_INTERVAL$1);
9968
+ } catch (error) {
9969
+ log.error("Error", {
9970
+ module: MODULE_TYPE$1,
9971
+ networkId,
9972
+ miniMetadata,
9973
+ addressesByToken,
9974
+ error
9975
+ });
9976
+ subscriber.error(error);
9977
+ }
9978
+ };
9979
+ poll();
9980
+ return () => {
9981
+ abortController.abort();
9982
+ };
9983
+ }).pipe(rxjs.distinctUntilChanged(lodash.isEqual));
9984
+ };
9985
+
9986
+ const SubPsp22BalanceModule = {
9987
+ type: MODULE_TYPE$1,
9988
+ platform: PLATFORM$1,
9989
+ getMiniMetadata: getMiniMetadata$1,
9990
+ fetchTokens: fetchTokens$1,
9991
+ fetchBalances: fetchBalances$1,
9992
+ subscribeBalances: subscribeBalances$1,
9993
+ getTransferCallData: getTransferCallData$1
9994
+ };
9995
+
9996
+ const MODULE_TYPE = chaindataProvider.SubTokensTokenSchema.shape.type.value;
9997
+ const PLATFORM = chaindataProvider.SubTokensTokenSchema.shape.platform.value;
9998
+
9999
+ // to be used by chaindata too
10000
+ z__default.default.strictObject({
10001
+ onChainId: chaindataProvider.SubTokensTokenSchema.shape.onChainId,
10002
+ ...TokenConfigBaseSchema.shape,
10003
+ // force these 3 fields because in this module we wont pull anything from chain
10004
+ symbol: z__default.default.string().nonempty(),
10005
+ decimals: z__default.default.number(),
10006
+ existentialDeposit: z__default.default.string().nonempty()
10007
+ });
10008
+
10009
+ // Do not use this type outside of this module
10010
+
10011
+ // Do not use this type outside of this module
10012
+
10013
+ const fetchBalances = async ({
10014
+ networkId,
10015
+ addressesByToken,
10016
+ connector,
10017
+ miniMetadata
10018
+ }) => {
10019
+ const balanceDefs = getBalanceDefs(addressesByToken);
10020
+ if (!miniMetadata?.data) {
10021
+ log.warn("MiniMetadata is required for fetching balances");
10022
+ return {
10023
+ success: [],
10024
+ errors: balanceDefs.map(def => ({
10025
+ tokenId: def.token.id,
10026
+ address: def.address,
10027
+ error: new Error("Minimetadata is required for fetching balances")
10028
+ }))
10029
+ };
10030
+ }
10031
+ if (miniMetadata.source !== MODULE_TYPE) {
10032
+ log.warn(`Ignoring miniMetadata with source ${miniMetadata.source} in ${MODULE_TYPE}.`);
10033
+ return {
10034
+ success: [],
10035
+ errors: balanceDefs.map(def => ({
10036
+ tokenId: def.token.id,
10037
+ address: def.address,
10038
+ error: new Error(`Invalid request: miniMetadata source is not ${MODULE_TYPE}`)
10039
+ }))
10040
+ };
10041
+ }
10042
+ if (miniMetadata.chainId !== networkId) {
10043
+ log.warn(`Ignoring miniMetadata with chainId ${miniMetadata.chainId} in ${MODULE_TYPE}. Expected chainId is ${networkId}`);
10044
+ return {
10045
+ success: [],
10046
+ errors: balanceDefs.map(def => ({
10047
+ tokenId: def.token.id,
10048
+ address: def.address,
10049
+ error: new Error(`Invalid request: Expected chainId is ${networkId}`)
10050
+ }))
10051
+ };
10052
+ }
10053
+ const queries = buildQueries(networkId, balanceDefs, miniMetadata);
10054
+ const balances = await new RpcStateQueryHelper(connector, queries).fetch();
10055
+ return balanceDefs.reduce((acc, def) => {
10056
+ const balance = balances.find(b => b?.address === def.address && b?.tokenId === def.token.id);
10057
+ if (balance) acc.success.push(balance);
10058
+ //if no entry consider empty balance
10059
+ else acc.success.push({
10060
+ address: def.address,
10061
+ networkId,
10062
+ tokenId: def.token.id,
10063
+ source: MODULE_TYPE,
10064
+ status: "live",
10065
+ values: [{
10066
+ type: "free",
10067
+ label: "free",
10068
+ amount: "0"
10069
+ }, {
10070
+ type: "locked",
10071
+ label: "frozen",
10072
+ amount: "0"
10073
+ }]
10074
+ });
10075
+ return acc;
10076
+ }, {
10077
+ success: [],
10078
+ errors: []
10079
+ });
10080
+ };
10081
+ const buildQueries = (networkId, balanceDefs, miniMetadata) => {
10082
+ const networkStorageCoders = buildNetworkStorageCoders(networkId, miniMetadata, {
10083
+ storage: [miniMetadata.extra.palletId, "Accounts"]
10084
+ });
10085
+ return balanceDefs.map(({
10086
+ token,
10087
+ address
10088
+ }) => {
10089
+ const scaleCoder = networkStorageCoders?.storage;
10090
+ const getStateKey = onChainId => {
10091
+ try {
10092
+ return scaleCoder.keys.enc(address, scale.papiParse(onChainId));
10093
+ } catch {
10094
+ return null;
10095
+ }
10096
+ };
10097
+ const stateKey = getStateKey(token.onChainId);
10098
+ if (!stateKey) {
10099
+ log.warn(`Invalid assetId / address in ${networkId} storage query ${token.onChainId} / ${address}`);
10100
+ return null;
10101
+ }
10102
+ const decodeResult = change => {
10103
+ /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */
10104
+
10105
+ const decoded = scale.decodeScale(scaleCoder, change, `Failed to decode substrate-tokens balance on chain ${networkId}`) ?? {
10106
+ free: 0n,
10107
+ reserved: 0n,
10108
+ frozen: 0n
10109
+ };
10110
+ const free = (decoded?.free ?? 0n).toString();
10111
+ const reserved = (decoded?.reserved ?? 0n).toString();
10112
+ const frozen = (decoded?.frozen ?? 0n).toString();
10113
+ const balanceValues = [{
10114
+ type: "free",
10115
+ label: "free",
10116
+ amount: free.toString()
10117
+ }, {
10118
+ type: "reserved",
10119
+ label: "reserved",
10120
+ amount: reserved.toString()
10121
+ }, {
10122
+ type: "locked",
10123
+ label: "frozen",
10124
+ amount: frozen.toString()
10125
+ }];
10126
+ return {
10127
+ source: "substrate-tokens",
10128
+ status: "live",
10129
+ address,
10130
+ networkId,
10131
+ tokenId: token.id,
10132
+ values: balanceValues
10133
+ };
10134
+ };
10135
+ return {
10136
+ chainId: networkId,
10137
+ stateKey,
10138
+ decodeResult
10139
+ };
10140
+ }).filter(util.isNotNil);
10141
+ };
10142
+
10143
+ const fetchTokens = async ({
10144
+ networkId,
10145
+ tokens,
10146
+ miniMetadata
10147
+ }) => {
10148
+ if (!miniMetadata?.data) return [];
10149
+
10150
+ // in this module we do not fetch any token information from the chain
10151
+ // this is because there are basically as many pallet implementations as there are networks (Expect Chaos, they said)
10152
+ // we rely on the config to provide all the info we need
10153
+ return tokens.map(tokenConfig => lodash.assign({
10154
+ id: chaindataProvider.subTokensTokenId(networkId, tokenConfig.onChainId),
10155
+ type: MODULE_TYPE,
10156
+ platform: PLATFORM,
10157
+ networkId,
10158
+ onChainId: tokenConfig.onChainId,
10159
+ symbol: tokenConfig.symbol ?? "Unit",
10160
+ decimals: tokenConfig.decimals ?? 0,
10161
+ name: tokenConfig.name ?? tokenConfig.symbol ?? "Unit",
10162
+ existentialDeposit: tokenConfig.existentialDeposit ?? "0",
10163
+ isDefault: true
10164
+ }, tokenConfig));
10165
+ };
10166
+
10167
+ const getMiniMetadata = ({
10168
+ networkId,
10169
+ specVersion,
10170
+ metadataRpc,
10171
+ config
10172
+ }) => {
10173
+ const source = MODULE_TYPE;
10174
+ const chainId = networkId;
10175
+ const systemVersion = getConstantValue(metadataRpc, "System", "Version");
10176
+ if (specVersion !== systemVersion.spec_version) log.warn("specVersion mismatch", {
10177
+ networkId,
10178
+ specVersion,
10179
+ systemVersion
10180
+ });
10181
+ const id = deriveMiniMetadataId({
10182
+ source,
10183
+ chainId,
10184
+ specVersion
10185
+ });
10186
+ const {
10187
+ unifiedMetadata
10188
+ } = scale.parseMetadataRpc(metadataRpc);
10189
+ if (unifiedMetadata.version < 14) throw new Error(`Unsupported metadata version: ${unifiedMetadata.version}. Minimum required is 14.`);
10190
+ const extra = {
10191
+ palletId: config?.palletId ?? "Tokens"
10192
+ };
10193
+ return {
10194
+ id,
10195
+ source,
10196
+ chainId,
10197
+ specVersion,
10198
+ version: chaindataProvider.MINIMETADATA_VERSION,
10199
+ data: getData(metadataRpc, extra.palletId),
10200
+ extra
10201
+ };
10202
+ };
10203
+ const getData = (metadataRpc, pallet) => {
10204
+ const {
10205
+ metadata,
10206
+ unifiedMetadata
10207
+ } = scale.parseMetadataRpc(metadataRpc);
10208
+
10209
+ // ensure the network has all the required bits
10210
+ if (!hasStorageItems(unifiedMetadata, pallet, ["Accounts"])) return null;
10211
+ scale.compactMetadata(metadata, [{
10212
+ pallet,
10213
+ items: ["Accounts"]
10214
+ }]);
10215
+ return scale.encodeMetadata(metadata);
10216
+ };
10217
+
10218
+ const getTransferCallData = ({
10219
+ from,
10220
+ to,
10221
+ value,
10222
+ token,
10223
+ type,
10224
+ metadataRpc,
10225
+ config
10226
+ }) => {
10227
+ if (!chaindataProvider.isTokenOfType(token, MODULE_TYPE)) throw new Error(`Token type ${token.type} is not ${MODULE_TYPE}.`);
10228
+ const {
10229
+ builder
10230
+ } = scale.parseMetadataRpc(metadataRpc);
10231
+
10232
+ // each chain has its own way of encoding the transfer call data
10233
+ // let's try our luck until one works!
10234
+ const options = getCallDataOptions(to, token, value, type, config);
10235
+ const callData = getCallDataFromOptions(builder, options);
10236
+ return {
10237
+ address: from,
10238
+ method: callData.asHex()
10239
+ };
10240
+ };
10241
+ const getTransferMethod = type => {
10242
+ switch (type) {
10243
+ case "keep-alive":
10244
+ return "transfer_keep_alive";
10245
+ case "all":
10246
+ return "transfer_all";
10247
+ case "allow-death":
10248
+ return "transfer";
10249
+ }
10250
+ };
10251
+ const getCallDataFromOptions = (builder, options) => {
10252
+ for (const {
10253
+ pallet,
10254
+ method,
10255
+ getArgs
10256
+ } of options) {
10257
+ try {
10258
+ return buildCallData(builder, pallet, method, getArgs());
10259
+ } catch {
10260
+ // wrong inputs, ignore and try the next one
10261
+ }
10262
+ }
10263
+ throw new Error("Failed to encode call data");
10264
+ };
10265
+ const buildCallData = (builder, pallet, method, args) => {
10266
+ const {
10267
+ location,
10268
+ codec
10269
+ } = builder.buildCall(pallet, method);
10270
+ return polkadotApi.Binary.fromBytes(utils.mergeUint8([new Uint8Array(location), codec.enc(args)]));
10271
+ };
10272
+ const getCallDataOptions = (to, token, value, type, config) => {
10273
+ const onChainId = scale.papiParse(token.onChainId);
10274
+ const method = getTransferMethod(type);
10275
+ return [{
10276
+ pallet: "Currencies",
10277
+ method: "transfer",
10278
+ getArgs: () => ({
10279
+ dest: polkadotApi.Enum("Id", to),
10280
+ currency_id: onChainId,
10281
+ amount: BigInt(value)
10282
+ })
10283
+ }, {
10284
+ pallet: "Currencies",
10285
+ method: "transfer",
10286
+ getArgs: () => ({
10287
+ dest: to,
10288
+ currency_id: onChainId,
10289
+ amount: BigInt(value)
10290
+ })
10291
+ }, {
10292
+ pallet: "Tokens",
10293
+ method,
10294
+ getArgs: () => method === "transfer_all" ? {
10295
+ dest: polkadotApi.Enum("Id", to),
10296
+ currency_id: onChainId,
10297
+ keepAlive: false
10298
+ } : {
10299
+ dest: polkadotApi.Enum("Id", to),
10300
+ currency_id: onChainId,
10301
+ amount: BigInt(value)
10302
+ }
10303
+ }, {
10304
+ pallet: "Tokens",
10305
+ method,
10306
+ getArgs: () => method === "transfer_all" ? {
10307
+ dest: to,
10308
+ currency_id: onChainId,
10309
+ keepAlive: false
10310
+ } : {
10311
+ dest: to,
10312
+ currency_id: onChainId,
10313
+ amount: BigInt(value)
10314
+ }
10315
+ }].concat(...(config?.palletId ? [{
10316
+ pallet: config.palletId,
10317
+ method,
10318
+ getArgs: () => method === "transfer_all" ? {
10319
+ dest: polkadotApi.Enum("Id", to),
10320
+ currency_id: onChainId,
10321
+ keepAlive: false
10322
+ } : {
10323
+ dest: polkadotApi.Enum("Id", to),
10324
+ currency_id: onChainId,
10325
+ amount: BigInt(value)
10326
+ }
10327
+ }, {
10328
+ pallet: config.palletId,
10329
+ method,
10330
+ getArgs: () => method === "transfer_all" ? {
10331
+ dest: to,
10332
+ currency_id: onChainId,
10333
+ keepAlive: false
10334
+ } : {
10335
+ dest: to,
10336
+ currency_id: onChainId,
10337
+ amount: BigInt(value)
10338
+ }
10339
+ }] : []));
10340
+ };
10341
+
10342
+ const SUBSCRIPTION_INTERVAL = 6_000;
10343
+ const subscribeBalances = ({
10344
+ networkId,
10345
+ addressesByToken,
10346
+ connector,
10347
+ miniMetadata
10348
+ }) => {
10349
+ return new rxjs.Observable(subscriber => {
10350
+ const abortController = new AbortController();
10351
+
10352
+ // on hydration balances are fetched using a runtimeApi, which can't be subscribed to.
10353
+ // => poll values for each block
10354
+ const poll = async () => {
10355
+ try {
10356
+ if (abortController.signal.aborted) return;
10357
+ const balances = await fetchBalances({
10358
+ networkId,
10359
+ addressesByToken,
10360
+ connector,
10361
+ miniMetadata
10362
+ });
10363
+ if (abortController.signal.aborted) return;
10364
+ subscriber.next(balances);
10365
+ setTimeout(poll, SUBSCRIPTION_INTERVAL);
10366
+ } catch (error) {
10367
+ log.error("Error", {
10368
+ module: MODULE_TYPE,
10369
+ networkId,
10370
+ miniMetadata,
10371
+ addressesByToken,
10372
+ error
10373
+ });
10374
+ subscriber.error(error);
10375
+ }
10376
+ };
10377
+ poll();
10378
+ return () => {
10379
+ abortController.abort();
10380
+ };
10381
+ }).pipe(rxjs.distinctUntilChanged(lodash.isEqual));
10382
+ };
10383
+
10384
+ const SubTokensBalanceModule = {
10385
+ type: MODULE_TYPE,
10386
+ platform: PLATFORM,
10387
+ getMiniMetadata,
10388
+ fetchTokens,
10389
+ fetchBalances,
10390
+ subscribeBalances,
10391
+ getTransferCallData
10392
+ };
10393
+
10394
+ const NEW_BALANCE_MODULES = [SubNativeBalanceModule, SubAssetsBalanceModule, SubHydrationBalanceModule, SubForeignAssetsBalanceModule, SubPsp22BalanceModule, SubTokensBalanceModule, EvmErc20BalanceModule, EvmUniswapV2BalanceModule, EvmNativeBalanceModule];
10395
+
10396
+ Object.defineProperty(exports, "MINIMETADATA_VERSION", {
10397
+ enumerable: true,
10398
+ get: function () { return chaindataProvider.MINIMETADATA_VERSION; }
10399
+ });
10400
+ Object.defineProperty(exports, "erc20Abi", {
10401
+ enumerable: true,
10402
+ get: function () { return viem.erc20Abi; }
10403
+ });
6834
10404
  exports.Balance = Balance;
6835
10405
  exports.BalanceFormatter = BalanceFormatter;
6836
10406
  exports.BalanceValueGetter = BalanceValueGetter;
@@ -6844,12 +10414,13 @@ exports.EvmNativeTokenConfigSchema = EvmNativeTokenConfigSchema;
6844
10414
  exports.EvmUniswapV2Module = EvmUniswapV2Module;
6845
10415
  exports.EvmUniswapV2TokenConfigSchema = EvmUniswapV2TokenConfigSchema;
6846
10416
  exports.FiatSumBalancesFormatter = FiatSumBalancesFormatter;
6847
- exports.ONE_ALPHA_TOKEN = ONE_ALPHA_TOKEN;
10417
+ exports.NEW_BALANCE_MODULES = NEW_BALANCE_MODULES;
10418
+ exports.ONE_ALPHA_TOKEN = ONE_ALPHA_TOKEN$1;
6848
10419
  exports.PlanckSumBalancesFormatter = PlanckSumBalancesFormatter;
6849
10420
  exports.RpcStateQueryHelper = RpcStateQueryHelper;
6850
- exports.SCALE_FACTOR = SCALE_FACTOR;
6851
- exports.SUBTENSOR_MIN_STAKE_AMOUNT_PLANK = SUBTENSOR_MIN_STAKE_AMOUNT_PLANK;
6852
- exports.SUBTENSOR_ROOT_NETUID = SUBTENSOR_ROOT_NETUID;
10421
+ exports.SCALE_FACTOR = SCALE_FACTOR$1;
10422
+ exports.SUBTENSOR_MIN_STAKE_AMOUNT_PLANK = SUBTENSOR_MIN_STAKE_AMOUNT_PLANK$1;
10423
+ exports.SUBTENSOR_ROOT_NETUID = SUBTENSOR_ROOT_NETUID$1;
6853
10424
  exports.SubAssetsModule = SubAssetsModule;
6854
10425
  exports.SubAssetsTokenConfigSchema = SubAssetsTokenConfigSchema;
6855
10426
  exports.SubForeignAssetsModule = SubForeignAssetsModule;
@@ -6866,9 +10437,9 @@ exports.abiMulticall = abiMulticall;
6866
10437
  exports.balances = balances;
6867
10438
  exports.buildNetworkStorageCoders = buildNetworkStorageCoders;
6868
10439
  exports.buildStorageCoders = buildStorageCoders;
6869
- exports.calculateAlphaPrice = calculateAlphaPrice;
6870
- exports.calculateTaoAmountFromAlpha = calculateTaoAmountFromAlpha;
6871
- exports.calculateTaoFromDynamicInfo = calculateTaoFromDynamicInfo;
10440
+ exports.calculateAlphaPrice = calculateAlphaPrice$1;
10441
+ exports.calculateTaoAmountFromAlpha = calculateTaoAmountFromAlpha$1;
10442
+ exports.calculateTaoFromDynamicInfo = calculateTaoFromDynamicInfo$1;
6872
10443
  exports.compress = compress;
6873
10444
  exports.configureStore = configureStore;
6874
10445
  exports.db = db;
@@ -6877,7 +10448,6 @@ exports.decompress = decompress;
6877
10448
  exports.defaultBalanceModules = defaultBalanceModules;
6878
10449
  exports.deriveMiniMetadataId = deriveMiniMetadataId;
6879
10450
  exports.detectTransferMethod = detectTransferMethod;
6880
- exports.erc20Abi = erc20Abi;
6881
10451
  exports.erc20BalancesAggregatorAbi = erc20BalancesAggregatorAbi;
6882
10452
  exports.excludeFromFeePayableLocks = excludeFromFeePayableLocks;
6883
10453
  exports.excludeFromTransferableAmount = excludeFromTransferableAmount;