@talismn/balances 0.0.0-pr2075-20250711181503 → 0.0.0-pr2075-20250712112227

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.
@@ -7,9 +7,9 @@ var lodashEs = require('lodash-es');
7
7
  var z = require('zod/v4');
8
8
  var anylogger = require('anylogger');
9
9
  var rxjs = require('rxjs');
10
+ var BigNumber = require('bignumber.js');
10
11
  var scale = require('@talismn/scale');
11
12
  var tokenRates = require('@talismn/token-rates');
12
- var BigNumber = require('bignumber.js');
13
13
  var utils = require('@polkadot-api/utils');
14
14
  var polkadotApi = require('polkadot-api');
15
15
  var upperFirst = require('lodash-es/upperFirst');
@@ -643,11 +643,11 @@ const fetchBalances$8 = async ({
643
643
  const balanceDefs = getBalanceDefs(tokensWithAddresses);
644
644
  if (client.chain?.contracts?.erc20Aggregator && balanceDefs.length > 1) {
645
645
  const erc20Aggregator = client.chain.contracts.erc20Aggregator;
646
- return fetchWithAggregator$1(client, balanceDefs, erc20Aggregator.address);
646
+ return fetchWithAggregator(client, balanceDefs, erc20Aggregator.address);
647
647
  }
648
- return fetchWithoutAggregator$1(client, balanceDefs);
648
+ return fetchWithoutAggregator(client, balanceDefs);
649
649
  };
650
- const fetchWithoutAggregator$1 = async (client, balanceDefs) => {
650
+ const fetchWithoutAggregator = async (client, balanceDefs) => {
651
651
  if (balanceDefs.length === 0) return {
652
652
  success: [],
653
653
  errors: []
@@ -691,7 +691,7 @@ const fetchWithoutAggregator$1 = async (client, balanceDefs) => {
691
691
  errors: []
692
692
  });
693
693
  };
694
- const fetchWithAggregator$1 = async (client, balanceDefs, erc20BalancesAggregatorAddress) => {
694
+ const fetchWithAggregator = async (client, balanceDefs, erc20BalancesAggregatorAddress) => {
695
695
  if (balanceDefs.length === 0) return {
696
696
  success: [],
697
697
  errors: []
@@ -1157,94 +1157,104 @@ const fetchBalances$6 = async ({
1157
1157
  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}`);
1158
1158
  }
1159
1159
  const balanceDefs = getBalanceDefs(tokensWithAddresses);
1160
- if (client.chain?.contracts?.erc20Aggregator && balanceDefs.length > 1) {
1161
- const erc20Aggregator = client.chain.contracts.erc20Aggregator;
1162
- return fetchWithAggregator(client, balanceDefs, erc20Aggregator.address);
1163
- }
1164
- return fetchWithoutAggregator(client, balanceDefs);
1160
+ return fetchPoolBalances(client, balanceDefs);
1165
1161
  };
1166
- const fetchWithoutAggregator = async (client, balanceDefs) => {
1162
+ const fetchPoolBalances = async (client, balanceDefs) => {
1167
1163
  if (balanceDefs.length === 0) return {
1168
1164
  success: [],
1169
1165
  errors: []
1170
1166
  };
1171
- const results = await Promise.allSettled(balanceDefs.map(async ({
1167
+
1168
+ // fetch pool specific info separately to prevent querying same contract info for multiple account addresses
1169
+ const pools = lodashEs.uniq(balanceDefs.map(def => def.token.contractAddress));
1170
+ const [poolResults, balanceResults] = await Promise.all([
1171
+ // pool supplies and reserves
1172
+ Promise.allSettled(pools.map(async address => {
1173
+ const contract = viem.getContract({
1174
+ address,
1175
+ abi: uniswapV2PairAbi,
1176
+ client
1177
+ });
1178
+ const [totalSupply, [reserve0, reserve1]] = await Promise.all([contract.read.totalSupply(), contract.read.getReserves()]);
1179
+ return {
1180
+ address,
1181
+ totalSupply,
1182
+ reserve0,
1183
+ reserve1
1184
+ };
1185
+ })),
1186
+ // balances for each address
1187
+ Promise.allSettled(balanceDefs.map(async ({
1172
1188
  token,
1173
1189
  address
1174
1190
  }) => {
1175
- try {
1176
- const result = await client.readContract({
1177
- abi: viem.erc20Abi,
1178
- address: token.contractAddress,
1179
- functionName: "balanceOf",
1180
- args: [address]
1181
- });
1182
- const balance = {
1183
- address,
1191
+ const balance = await client.readContract({
1192
+ address: token.contractAddress,
1193
+ abi: uniswapV2PairAbi,
1194
+ functionName: "balanceOf",
1195
+ args: [address]
1196
+ });
1197
+ return {
1198
+ pool: token.contractAddress,
1199
+ address,
1200
+ balance
1201
+ };
1202
+ }))]);
1203
+ const poolInfo = lodashEs.keyBy(poolResults.filter(r => r.status === "fulfilled").map(r => r.value), p => p.address);
1204
+ const results = balanceDefs.reduce((acc, {
1205
+ token,
1206
+ address
1207
+ }, i) => {
1208
+ const pool = poolInfo[token.contractAddress];
1209
+ if (!pool) {
1210
+ acc.errors.push({
1184
1211
  tokenId: token.id,
1185
- value: result.toString(),
1186
- source: MODULE_TYPE$6,
1187
- networkId: chaindataProvider.parseTokenId(token.id).networkId,
1188
- status: "live"
1189
- };
1190
- return balance;
1191
- } catch (err) {
1192
- throw new BalanceFetchError(`Failed to get balance for token ${token.id} and address ${address} on chain ${client.chain?.id}`, token.id, address, err);
1212
+ address,
1213
+ error: new BalanceFetchNetworkError(`Pool data not found for token ${token.id} at address ${token.contractAddress}`, chaindataProvider.parseTokenId(token.id).networkId)
1214
+ });
1215
+ return acc;
1193
1216
  }
1194
- }));
1195
- return results.reduce((acc, result) => {
1196
- if (result.status === "fulfilled") acc.success.push(result.value);else {
1197
- const error = result.reason;
1217
+ const balanceResult = balanceResults[i];
1218
+ if (balanceResult.status !== "fulfilled") {
1198
1219
  acc.errors.push({
1199
- tokenId: error.tokenId,
1200
- address: error.address,
1201
- error
1220
+ tokenId: token.id,
1221
+ address,
1222
+ error: new BalanceFetchError(`Failed to fetch balance for token ${token.id} at address ${address}`, token.id, address, balanceResult.reason)
1202
1223
  });
1224
+ return acc;
1203
1225
  }
1226
+ const {
1227
+ totalSupply,
1228
+ reserve0,
1229
+ reserve1
1230
+ } = pool;
1231
+ const {
1232
+ balance
1233
+ } = balanceResult.value;
1234
+ const extraWithLabel = (label, amount) => ({
1235
+ type: "extra",
1236
+ label,
1237
+ amount
1238
+ });
1239
+ const ratio = BigNumber__default.default(String(balance)).div(totalSupply === 0n ? "1" : String(totalSupply));
1240
+ acc.success.push({
1241
+ address,
1242
+ tokenId: token.id,
1243
+ source: MODULE_TYPE$6,
1244
+ networkId: chaindataProvider.parseTokenId(token.id).networkId,
1245
+ status: "live",
1246
+ values: [{
1247
+ type: "free",
1248
+ label: "free",
1249
+ amount: String(balance)
1250
+ }, extraWithLabel("totalSupply", String(totalSupply)), extraWithLabel("reserve0", String(reserve0)), extraWithLabel("reserve1", String(reserve1)), extraWithLabel("holding0", ratio.times(String(reserve0)).toString(10)), extraWithLabel("holding1", ratio.times(String(reserve1)).toString(10))]
1251
+ });
1204
1252
  return acc;
1205
1253
  }, {
1206
1254
  success: [],
1207
1255
  errors: []
1208
1256
  });
1209
- };
1210
- const fetchWithAggregator = async (client, balanceDefs, erc20BalancesAggregatorAddress) => {
1211
- if (balanceDefs.length === 0) return {
1212
- success: [],
1213
- errors: []
1214
- };
1215
- try {
1216
- const erc20Balances = await client.readContract({
1217
- abi: erc20BalancesAggregatorAbi,
1218
- address: erc20BalancesAggregatorAddress,
1219
- functionName: "balances",
1220
- args: [balanceDefs.map(b => ({
1221
- account: b.address,
1222
- token: b.token.contractAddress
1223
- }))]
1224
- });
1225
- const success = balanceDefs.map((balanceDef, index) => ({
1226
- address: balanceDef.address,
1227
- tokenId: balanceDef.token.id,
1228
- value: erc20Balances[index].toString(),
1229
- source: MODULE_TYPE$6,
1230
- networkId: chaindataProvider.parseTokenId(balanceDef.token.id).networkId,
1231
- status: "live"
1232
- }));
1233
- return {
1234
- success,
1235
- errors: []
1236
- };
1237
- } catch (err) {
1238
- const errors = balanceDefs.map(balanceDef => ({
1239
- tokenId: balanceDef.token.id,
1240
- address: balanceDef.address,
1241
- error: new BalanceFetchNetworkError(`Failed to get balances for evm-erc20 tokens on chain ${client.chain?.id}`, String(client.chain?.id), err)
1242
- }));
1243
- return {
1244
- success: [],
1245
- errors
1246
- };
1247
- }
1257
+ return results;
1248
1258
  };
1249
1259
 
1250
1260
  const getErc20ContractData = async (client, contractAddress) => {
@@ -7,9 +7,9 @@ var lodashEs = require('lodash-es');
7
7
  var z = require('zod/v4');
8
8
  var anylogger = require('anylogger');
9
9
  var rxjs = require('rxjs');
10
+ var BigNumber = require('bignumber.js');
10
11
  var scale = require('@talismn/scale');
11
12
  var tokenRates = require('@talismn/token-rates');
12
- var BigNumber = require('bignumber.js');
13
13
  var utils = require('@polkadot-api/utils');
14
14
  var polkadotApi = require('polkadot-api');
15
15
  var upperFirst = require('lodash-es/upperFirst');
@@ -643,11 +643,11 @@ const fetchBalances$8 = async ({
643
643
  const balanceDefs = getBalanceDefs(tokensWithAddresses);
644
644
  if (client.chain?.contracts?.erc20Aggregator && balanceDefs.length > 1) {
645
645
  const erc20Aggregator = client.chain.contracts.erc20Aggregator;
646
- return fetchWithAggregator$1(client, balanceDefs, erc20Aggregator.address);
646
+ return fetchWithAggregator(client, balanceDefs, erc20Aggregator.address);
647
647
  }
648
- return fetchWithoutAggregator$1(client, balanceDefs);
648
+ return fetchWithoutAggregator(client, balanceDefs);
649
649
  };
650
- const fetchWithoutAggregator$1 = async (client, balanceDefs) => {
650
+ const fetchWithoutAggregator = async (client, balanceDefs) => {
651
651
  if (balanceDefs.length === 0) return {
652
652
  success: [],
653
653
  errors: []
@@ -691,7 +691,7 @@ const fetchWithoutAggregator$1 = async (client, balanceDefs) => {
691
691
  errors: []
692
692
  });
693
693
  };
694
- const fetchWithAggregator$1 = async (client, balanceDefs, erc20BalancesAggregatorAddress) => {
694
+ const fetchWithAggregator = async (client, balanceDefs, erc20BalancesAggregatorAddress) => {
695
695
  if (balanceDefs.length === 0) return {
696
696
  success: [],
697
697
  errors: []
@@ -1157,94 +1157,104 @@ const fetchBalances$6 = async ({
1157
1157
  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}`);
1158
1158
  }
1159
1159
  const balanceDefs = getBalanceDefs(tokensWithAddresses);
1160
- if (client.chain?.contracts?.erc20Aggregator && balanceDefs.length > 1) {
1161
- const erc20Aggregator = client.chain.contracts.erc20Aggregator;
1162
- return fetchWithAggregator(client, balanceDefs, erc20Aggregator.address);
1163
- }
1164
- return fetchWithoutAggregator(client, balanceDefs);
1160
+ return fetchPoolBalances(client, balanceDefs);
1165
1161
  };
1166
- const fetchWithoutAggregator = async (client, balanceDefs) => {
1162
+ const fetchPoolBalances = async (client, balanceDefs) => {
1167
1163
  if (balanceDefs.length === 0) return {
1168
1164
  success: [],
1169
1165
  errors: []
1170
1166
  };
1171
- const results = await Promise.allSettled(balanceDefs.map(async ({
1167
+
1168
+ // fetch pool specific info separately to prevent querying same contract info for multiple account addresses
1169
+ const pools = lodashEs.uniq(balanceDefs.map(def => def.token.contractAddress));
1170
+ const [poolResults, balanceResults] = await Promise.all([
1171
+ // pool supplies and reserves
1172
+ Promise.allSettled(pools.map(async address => {
1173
+ const contract = viem.getContract({
1174
+ address,
1175
+ abi: uniswapV2PairAbi,
1176
+ client
1177
+ });
1178
+ const [totalSupply, [reserve0, reserve1]] = await Promise.all([contract.read.totalSupply(), contract.read.getReserves()]);
1179
+ return {
1180
+ address,
1181
+ totalSupply,
1182
+ reserve0,
1183
+ reserve1
1184
+ };
1185
+ })),
1186
+ // balances for each address
1187
+ Promise.allSettled(balanceDefs.map(async ({
1172
1188
  token,
1173
1189
  address
1174
1190
  }) => {
1175
- try {
1176
- const result = await client.readContract({
1177
- abi: viem.erc20Abi,
1178
- address: token.contractAddress,
1179
- functionName: "balanceOf",
1180
- args: [address]
1181
- });
1182
- const balance = {
1183
- address,
1191
+ const balance = await client.readContract({
1192
+ address: token.contractAddress,
1193
+ abi: uniswapV2PairAbi,
1194
+ functionName: "balanceOf",
1195
+ args: [address]
1196
+ });
1197
+ return {
1198
+ pool: token.contractAddress,
1199
+ address,
1200
+ balance
1201
+ };
1202
+ }))]);
1203
+ const poolInfo = lodashEs.keyBy(poolResults.filter(r => r.status === "fulfilled").map(r => r.value), p => p.address);
1204
+ const results = balanceDefs.reduce((acc, {
1205
+ token,
1206
+ address
1207
+ }, i) => {
1208
+ const pool = poolInfo[token.contractAddress];
1209
+ if (!pool) {
1210
+ acc.errors.push({
1184
1211
  tokenId: token.id,
1185
- value: result.toString(),
1186
- source: MODULE_TYPE$6,
1187
- networkId: chaindataProvider.parseTokenId(token.id).networkId,
1188
- status: "live"
1189
- };
1190
- return balance;
1191
- } catch (err) {
1192
- throw new BalanceFetchError(`Failed to get balance for token ${token.id} and address ${address} on chain ${client.chain?.id}`, token.id, address, err);
1212
+ address,
1213
+ error: new BalanceFetchNetworkError(`Pool data not found for token ${token.id} at address ${token.contractAddress}`, chaindataProvider.parseTokenId(token.id).networkId)
1214
+ });
1215
+ return acc;
1193
1216
  }
1194
- }));
1195
- return results.reduce((acc, result) => {
1196
- if (result.status === "fulfilled") acc.success.push(result.value);else {
1197
- const error = result.reason;
1217
+ const balanceResult = balanceResults[i];
1218
+ if (balanceResult.status !== "fulfilled") {
1198
1219
  acc.errors.push({
1199
- tokenId: error.tokenId,
1200
- address: error.address,
1201
- error
1220
+ tokenId: token.id,
1221
+ address,
1222
+ error: new BalanceFetchError(`Failed to fetch balance for token ${token.id} at address ${address}`, token.id, address, balanceResult.reason)
1202
1223
  });
1224
+ return acc;
1203
1225
  }
1226
+ const {
1227
+ totalSupply,
1228
+ reserve0,
1229
+ reserve1
1230
+ } = pool;
1231
+ const {
1232
+ balance
1233
+ } = balanceResult.value;
1234
+ const extraWithLabel = (label, amount) => ({
1235
+ type: "extra",
1236
+ label,
1237
+ amount
1238
+ });
1239
+ const ratio = BigNumber__default.default(String(balance)).div(totalSupply === 0n ? "1" : String(totalSupply));
1240
+ acc.success.push({
1241
+ address,
1242
+ tokenId: token.id,
1243
+ source: MODULE_TYPE$6,
1244
+ networkId: chaindataProvider.parseTokenId(token.id).networkId,
1245
+ status: "live",
1246
+ values: [{
1247
+ type: "free",
1248
+ label: "free",
1249
+ amount: String(balance)
1250
+ }, extraWithLabel("totalSupply", String(totalSupply)), extraWithLabel("reserve0", String(reserve0)), extraWithLabel("reserve1", String(reserve1)), extraWithLabel("holding0", ratio.times(String(reserve0)).toString(10)), extraWithLabel("holding1", ratio.times(String(reserve1)).toString(10))]
1251
+ });
1204
1252
  return acc;
1205
1253
  }, {
1206
1254
  success: [],
1207
1255
  errors: []
1208
1256
  });
1209
- };
1210
- const fetchWithAggregator = async (client, balanceDefs, erc20BalancesAggregatorAddress) => {
1211
- if (balanceDefs.length === 0) return {
1212
- success: [],
1213
- errors: []
1214
- };
1215
- try {
1216
- const erc20Balances = await client.readContract({
1217
- abi: erc20BalancesAggregatorAbi,
1218
- address: erc20BalancesAggregatorAddress,
1219
- functionName: "balances",
1220
- args: [balanceDefs.map(b => ({
1221
- account: b.address,
1222
- token: b.token.contractAddress
1223
- }))]
1224
- });
1225
- const success = balanceDefs.map((balanceDef, index) => ({
1226
- address: balanceDef.address,
1227
- tokenId: balanceDef.token.id,
1228
- value: erc20Balances[index].toString(),
1229
- source: MODULE_TYPE$6,
1230
- networkId: chaindataProvider.parseTokenId(balanceDef.token.id).networkId,
1231
- status: "live"
1232
- }));
1233
- return {
1234
- success,
1235
- errors: []
1236
- };
1237
- } catch (err) {
1238
- const errors = balanceDefs.map(balanceDef => ({
1239
- tokenId: balanceDef.token.id,
1240
- address: balanceDef.address,
1241
- error: new BalanceFetchNetworkError(`Failed to get balances for evm-erc20 tokens on chain ${client.chain?.id}`, String(client.chain?.id), err)
1242
- }));
1243
- return {
1244
- success: [],
1245
- errors
1246
- };
1247
- }
1257
+ return results;
1248
1258
  };
1249
1259
 
1250
1260
  const getErc20ContractData = async (client, contractAddress) => {
@@ -2,13 +2,13 @@ import { EvmErc20TokenSchema, parseTokenId, parseEvmErc20TokenId, evmErc20TokenI
2
2
  export { MINIMETADATA_VERSION } from '@talismn/chaindata-provider';
3
3
  import { isEthereumAddress, isNotNil, BigMath, isArrayOf, isBigInt, planckToTokens, isAbortError, getSharedObservable, keepAlive, isTruthy } from '@talismn/util';
4
4
  import { parseAbi, erc20Abi, getContract, ContractFunctionExecutionError, hexToString, erc20Abi_bytes32, encodeFunctionData, withRetry } from 'viem';
5
- import { assign, omit, isEqual, keyBy, keys, uniq, fromPairs, values, toPairs } from 'lodash-es';
5
+ import { assign, omit, isEqual, uniq, keyBy, keys, fromPairs, values, toPairs } from 'lodash-es';
6
6
  import z from 'zod/v4';
7
7
  import anylogger from 'anylogger';
8
8
  import { of, Observable, distinctUntilChanged, map, timer, switchMap, from, firstValueFrom, combineLatest, BehaviorSubject, shareReplay, startWith, filter, catchError, EMPTY, tap } from 'rxjs';
9
+ import BigNumber from 'bignumber.js';
9
10
  import { parseMetadataRpc, toHex, unifyMetadata, decAnyMetadata, getDynamicBuilder, getLookupFn, decodeScale, getStorageKeyPrefix, Twox128, compactMetadata, encodeMetadata, papiParse, papiStringify } from '@talismn/scale';
10
11
  import { newTokenRates } from '@talismn/token-rates';
11
- import BigNumber from 'bignumber.js';
12
12
  import { mergeUint8 } from '@polkadot-api/utils';
13
13
  import { Binary, Enum, AccountId } from 'polkadot-api';
14
14
  import upperFirst from 'lodash-es/upperFirst';
@@ -634,11 +634,11 @@ const fetchBalances$8 = async ({
634
634
  const balanceDefs = getBalanceDefs(tokensWithAddresses);
635
635
  if (client.chain?.contracts?.erc20Aggregator && balanceDefs.length > 1) {
636
636
  const erc20Aggregator = client.chain.contracts.erc20Aggregator;
637
- return fetchWithAggregator$1(client, balanceDefs, erc20Aggregator.address);
637
+ return fetchWithAggregator(client, balanceDefs, erc20Aggregator.address);
638
638
  }
639
- return fetchWithoutAggregator$1(client, balanceDefs);
639
+ return fetchWithoutAggregator(client, balanceDefs);
640
640
  };
641
- const fetchWithoutAggregator$1 = async (client, balanceDefs) => {
641
+ const fetchWithoutAggregator = async (client, balanceDefs) => {
642
642
  if (balanceDefs.length === 0) return {
643
643
  success: [],
644
644
  errors: []
@@ -682,7 +682,7 @@ const fetchWithoutAggregator$1 = async (client, balanceDefs) => {
682
682
  errors: []
683
683
  });
684
684
  };
685
- const fetchWithAggregator$1 = async (client, balanceDefs, erc20BalancesAggregatorAddress) => {
685
+ const fetchWithAggregator = async (client, balanceDefs, erc20BalancesAggregatorAddress) => {
686
686
  if (balanceDefs.length === 0) return {
687
687
  success: [],
688
688
  errors: []
@@ -1148,94 +1148,104 @@ const fetchBalances$6 = async ({
1148
1148
  for (const address of addresses) if (!isEthereumAddress(address)) throw new Error(`Invalid ethereum address for EVM ERC20 balance module: ${address} for token ${token.id}`);
1149
1149
  }
1150
1150
  const balanceDefs = getBalanceDefs(tokensWithAddresses);
1151
- if (client.chain?.contracts?.erc20Aggregator && balanceDefs.length > 1) {
1152
- const erc20Aggregator = client.chain.contracts.erc20Aggregator;
1153
- return fetchWithAggregator(client, balanceDefs, erc20Aggregator.address);
1154
- }
1155
- return fetchWithoutAggregator(client, balanceDefs);
1151
+ return fetchPoolBalances(client, balanceDefs);
1156
1152
  };
1157
- const fetchWithoutAggregator = async (client, balanceDefs) => {
1153
+ const fetchPoolBalances = async (client, balanceDefs) => {
1158
1154
  if (balanceDefs.length === 0) return {
1159
1155
  success: [],
1160
1156
  errors: []
1161
1157
  };
1162
- const results = await Promise.allSettled(balanceDefs.map(async ({
1158
+
1159
+ // fetch pool specific info separately to prevent querying same contract info for multiple account addresses
1160
+ const pools = uniq(balanceDefs.map(def => def.token.contractAddress));
1161
+ const [poolResults, balanceResults] = await Promise.all([
1162
+ // pool supplies and reserves
1163
+ Promise.allSettled(pools.map(async address => {
1164
+ const contract = getContract({
1165
+ address,
1166
+ abi: uniswapV2PairAbi,
1167
+ client
1168
+ });
1169
+ const [totalSupply, [reserve0, reserve1]] = await Promise.all([contract.read.totalSupply(), contract.read.getReserves()]);
1170
+ return {
1171
+ address,
1172
+ totalSupply,
1173
+ reserve0,
1174
+ reserve1
1175
+ };
1176
+ })),
1177
+ // balances for each address
1178
+ Promise.allSettled(balanceDefs.map(async ({
1163
1179
  token,
1164
1180
  address
1165
1181
  }) => {
1166
- try {
1167
- const result = await client.readContract({
1168
- abi: erc20Abi,
1169
- address: token.contractAddress,
1170
- functionName: "balanceOf",
1171
- args: [address]
1172
- });
1173
- const balance = {
1174
- address,
1182
+ const balance = await client.readContract({
1183
+ address: token.contractAddress,
1184
+ abi: uniswapV2PairAbi,
1185
+ functionName: "balanceOf",
1186
+ args: [address]
1187
+ });
1188
+ return {
1189
+ pool: token.contractAddress,
1190
+ address,
1191
+ balance
1192
+ };
1193
+ }))]);
1194
+ const poolInfo = keyBy(poolResults.filter(r => r.status === "fulfilled").map(r => r.value), p => p.address);
1195
+ const results = balanceDefs.reduce((acc, {
1196
+ token,
1197
+ address
1198
+ }, i) => {
1199
+ const pool = poolInfo[token.contractAddress];
1200
+ if (!pool) {
1201
+ acc.errors.push({
1175
1202
  tokenId: token.id,
1176
- value: result.toString(),
1177
- source: MODULE_TYPE$6,
1178
- networkId: parseTokenId(token.id).networkId,
1179
- status: "live"
1180
- };
1181
- return balance;
1182
- } catch (err) {
1183
- throw new BalanceFetchError(`Failed to get balance for token ${token.id} and address ${address} on chain ${client.chain?.id}`, token.id, address, err);
1203
+ address,
1204
+ error: new BalanceFetchNetworkError(`Pool data not found for token ${token.id} at address ${token.contractAddress}`, parseTokenId(token.id).networkId)
1205
+ });
1206
+ return acc;
1184
1207
  }
1185
- }));
1186
- return results.reduce((acc, result) => {
1187
- if (result.status === "fulfilled") acc.success.push(result.value);else {
1188
- const error = result.reason;
1208
+ const balanceResult = balanceResults[i];
1209
+ if (balanceResult.status !== "fulfilled") {
1189
1210
  acc.errors.push({
1190
- tokenId: error.tokenId,
1191
- address: error.address,
1192
- error
1211
+ tokenId: token.id,
1212
+ address,
1213
+ error: new BalanceFetchError(`Failed to fetch balance for token ${token.id} at address ${address}`, token.id, address, balanceResult.reason)
1193
1214
  });
1215
+ return acc;
1194
1216
  }
1217
+ const {
1218
+ totalSupply,
1219
+ reserve0,
1220
+ reserve1
1221
+ } = pool;
1222
+ const {
1223
+ balance
1224
+ } = balanceResult.value;
1225
+ const extraWithLabel = (label, amount) => ({
1226
+ type: "extra",
1227
+ label,
1228
+ amount
1229
+ });
1230
+ const ratio = BigNumber(String(balance)).div(totalSupply === 0n ? "1" : String(totalSupply));
1231
+ acc.success.push({
1232
+ address,
1233
+ tokenId: token.id,
1234
+ source: MODULE_TYPE$6,
1235
+ networkId: parseTokenId(token.id).networkId,
1236
+ status: "live",
1237
+ values: [{
1238
+ type: "free",
1239
+ label: "free",
1240
+ amount: String(balance)
1241
+ }, extraWithLabel("totalSupply", String(totalSupply)), extraWithLabel("reserve0", String(reserve0)), extraWithLabel("reserve1", String(reserve1)), extraWithLabel("holding0", ratio.times(String(reserve0)).toString(10)), extraWithLabel("holding1", ratio.times(String(reserve1)).toString(10))]
1242
+ });
1195
1243
  return acc;
1196
1244
  }, {
1197
1245
  success: [],
1198
1246
  errors: []
1199
1247
  });
1200
- };
1201
- const fetchWithAggregator = async (client, balanceDefs, erc20BalancesAggregatorAddress) => {
1202
- if (balanceDefs.length === 0) return {
1203
- success: [],
1204
- errors: []
1205
- };
1206
- try {
1207
- const erc20Balances = await client.readContract({
1208
- abi: erc20BalancesAggregatorAbi,
1209
- address: erc20BalancesAggregatorAddress,
1210
- functionName: "balances",
1211
- args: [balanceDefs.map(b => ({
1212
- account: b.address,
1213
- token: b.token.contractAddress
1214
- }))]
1215
- });
1216
- const success = balanceDefs.map((balanceDef, index) => ({
1217
- address: balanceDef.address,
1218
- tokenId: balanceDef.token.id,
1219
- value: erc20Balances[index].toString(),
1220
- source: MODULE_TYPE$6,
1221
- networkId: parseTokenId(balanceDef.token.id).networkId,
1222
- status: "live"
1223
- }));
1224
- return {
1225
- success,
1226
- errors: []
1227
- };
1228
- } catch (err) {
1229
- const errors = balanceDefs.map(balanceDef => ({
1230
- tokenId: balanceDef.token.id,
1231
- address: balanceDef.address,
1232
- error: new BalanceFetchNetworkError(`Failed to get balances for evm-erc20 tokens on chain ${client.chain?.id}`, String(client.chain?.id), err)
1233
- }));
1234
- return {
1235
- success: [],
1236
- errors
1237
- };
1238
- }
1248
+ return results;
1239
1249
  };
1240
1250
 
1241
1251
  const getErc20ContractData = async (client, contractAddress) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@talismn/balances",
3
- "version": "0.0.0-pr2075-20250711181503",
3
+ "version": "0.0.0-pr2075-20250712112227",
4
4
  "author": "Talisman",
5
5
  "homepage": "https://talisman.xyz",
6
6
  "license": "GPL-3.0-or-later",
@@ -34,13 +34,13 @@
34
34
  "scale-ts": "^1.6.1",
35
35
  "viem": "^2.27.3",
36
36
  "zod": "^3.25.62",
37
- "@talismn/chain-connector-evm": "0.0.0-pr2075-20250711181503",
38
- "@talismn/chaindata-provider": "0.0.0-pr2075-20250711181503",
39
- "@talismn/scale": "0.0.0-pr2075-20250711181503",
40
- "@talismn/token-rates": "0.0.0-pr2075-20250711181503",
41
- "@talismn/sapi": "0.0.0-pr2075-20250711181503",
42
- "@talismn/util": "0.0.0-pr2075-20250711181503",
43
- "@talismn/chain-connector": "0.0.0-pr2075-20250711181503"
37
+ "@talismn/chain-connector": "0.0.0-pr2075-20250712112227",
38
+ "@talismn/chaindata-provider": "0.0.0-pr2075-20250712112227",
39
+ "@talismn/sapi": "0.0.0-pr2075-20250712112227",
40
+ "@talismn/chain-connector-evm": "0.0.0-pr2075-20250712112227",
41
+ "@talismn/scale": "0.0.0-pr2075-20250712112227",
42
+ "@talismn/token-rates": "0.0.0-pr2075-20250712112227",
43
+ "@talismn/util": "0.0.0-pr2075-20250712112227"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@polkadot/api-contract": "16.1.2",