@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
|
646
|
+
return fetchWithAggregator(client, balanceDefs, erc20Aggregator.address);
|
647
647
|
}
|
648
|
-
return fetchWithoutAggregator
|
648
|
+
return fetchWithoutAggregator(client, balanceDefs);
|
649
649
|
};
|
650
|
-
const fetchWithoutAggregator
|
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
|
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
|
-
|
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
|
1162
|
+
const fetchPoolBalances = async (client, balanceDefs) => {
|
1167
1163
|
if (balanceDefs.length === 0) return {
|
1168
1164
|
success: [],
|
1169
1165
|
errors: []
|
1170
1166
|
};
|
1171
|
-
|
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
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
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
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
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
|
-
|
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:
|
1200
|
-
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
|
646
|
+
return fetchWithAggregator(client, balanceDefs, erc20Aggregator.address);
|
647
647
|
}
|
648
|
-
return fetchWithoutAggregator
|
648
|
+
return fetchWithoutAggregator(client, balanceDefs);
|
649
649
|
};
|
650
|
-
const fetchWithoutAggregator
|
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
|
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
|
-
|
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
|
1162
|
+
const fetchPoolBalances = async (client, balanceDefs) => {
|
1167
1163
|
if (balanceDefs.length === 0) return {
|
1168
1164
|
success: [],
|
1169
1165
|
errors: []
|
1170
1166
|
};
|
1171
|
-
|
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
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
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
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
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
|
-
|
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:
|
1200
|
-
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,
|
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
|
637
|
+
return fetchWithAggregator(client, balanceDefs, erc20Aggregator.address);
|
638
638
|
}
|
639
|
-
return fetchWithoutAggregator
|
639
|
+
return fetchWithoutAggregator(client, balanceDefs);
|
640
640
|
};
|
641
|
-
const fetchWithoutAggregator
|
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
|
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
|
-
|
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
|
1153
|
+
const fetchPoolBalances = async (client, balanceDefs) => {
|
1158
1154
|
if (balanceDefs.length === 0) return {
|
1159
1155
|
success: [],
|
1160
1156
|
errors: []
|
1161
1157
|
};
|
1162
|
-
|
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
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
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
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
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
|
-
|
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:
|
1191
|
-
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-
|
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
|
38
|
-
"@talismn/chaindata-provider": "0.0.0-pr2075-
|
39
|
-
"@talismn/
|
40
|
-
"@talismn/
|
41
|
-
"@talismn/
|
42
|
-
"@talismn/
|
43
|
-
"@talismn/
|
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",
|