@defisaver/positions-sdk 2.1.167 → 2.1.168
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/aaveV2/index.js +8 -29
- package/cjs/aaveV3/index.js +2 -31
- package/cjs/aaveV4/index.d.ts +25 -0
- package/cjs/aaveV4/index.js +4 -1
- package/cjs/compoundV2/index.d.ts +1 -1
- package/cjs/compoundV2/index.js +2 -2
- package/cjs/curveUsd/index.d.ts +1 -1
- package/cjs/curveUsd/index.js +6 -1
- package/cjs/fluid/index.js +13 -12
- package/cjs/helpers/aaveBalances.d.ts +5 -0
- package/cjs/helpers/aaveBalances.js +51 -0
- package/cjs/helpers/fluidBalances.d.ts +6 -0
- package/cjs/helpers/fluidBalances.js +36 -0
- package/cjs/liquityV2/index.d.ts +8 -0
- package/cjs/liquityV2/index.js +3 -3
- package/cjs/llamaLend/index.d.ts +1 -1
- package/cjs/llamaLend/index.js +6 -1
- package/cjs/morphoMidnight/index.d.ts +1 -1
- package/cjs/morphoMidnight/index.js +6 -1
- package/cjs/portfolio/index.d.ts +1 -0
- package/cjs/portfolio/index.js +3 -0
- package/cjs/portfolio/lendingSummaries.d.ts +7 -0
- package/cjs/portfolio/lendingSummaries.js +262 -0
- package/cjs/portfolio/lendingSummaryTransport.d.ts +8 -0
- package/cjs/portfolio/lendingSummaryTransport.js +109 -0
- package/cjs/spark/index.js +2 -31
- package/cjs/types/index.d.ts +1 -0
- package/cjs/types/index.js +1 -0
- package/cjs/types/lendingSummary.d.ts +34 -0
- package/cjs/types/lendingSummary.js +2 -0
- package/esm/aaveV2/index.js +11 -32
- package/esm/aaveV3/index.js +3 -32
- package/esm/aaveV4/index.d.ts +25 -0
- package/esm/aaveV4/index.js +3 -1
- package/esm/compoundV2/index.d.ts +1 -1
- package/esm/compoundV2/index.js +2 -2
- package/esm/curveUsd/index.d.ts +1 -1
- package/esm/curveUsd/index.js +6 -1
- package/esm/fluid/index.js +13 -12
- package/esm/helpers/aaveBalances.d.ts +5 -0
- package/esm/helpers/aaveBalances.js +45 -0
- package/esm/helpers/fluidBalances.d.ts +6 -0
- package/esm/helpers/fluidBalances.js +28 -0
- package/esm/liquityV2/index.d.ts +8 -0
- package/esm/liquityV2/index.js +1 -1
- package/esm/llamaLend/index.d.ts +1 -1
- package/esm/llamaLend/index.js +6 -1
- package/esm/morphoMidnight/index.d.ts +1 -1
- package/esm/morphoMidnight/index.js +6 -1
- package/esm/portfolio/index.d.ts +1 -0
- package/esm/portfolio/index.js +1 -0
- package/esm/portfolio/lendingSummaries.d.ts +7 -0
- package/esm/portfolio/lendingSummaries.js +256 -0
- package/esm/portfolio/lendingSummaryTransport.d.ts +8 -0
- package/esm/portfolio/lendingSummaryTransport.js +104 -0
- package/esm/spark/index.js +4 -33
- package/esm/types/index.d.ts +1 -0
- package/esm/types/index.js +1 -0
- package/esm/types/lendingSummary.d.ts +34 -0
- package/esm/types/lendingSummary.js +1 -0
- package/package.json +1 -1
- package/src/aaveV2/index.ts +8 -48
- package/src/aaveV3/index.ts +2 -48
- package/src/aaveV4/index.ts +6 -1
- package/src/compoundV2/index.ts +2 -2
- package/src/curveUsd/index.ts +6 -1
- package/src/fluid/index.ts +13 -12
- package/src/helpers/aaveBalances.ts +41 -0
- package/src/helpers/fluidBalances.ts +34 -0
- package/src/liquityV2/index.ts +1 -1
- package/src/llamaLend/index.ts +6 -1
- package/src/morphoMidnight/index.ts +6 -1
- package/src/portfolio/index.ts +2 -0
- package/src/portfolio/lendingSummaries.ts +216 -0
- package/src/portfolio/lendingSummaryTransport.ts +84 -0
- package/src/spark/index.ts +3 -49
- package/src/types/index.ts +2 -1
- package/src/types/lendingSummary.ts +41 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.getWalletLendingSummaries = getWalletLendingSummaries;
|
|
16
|
+
/* global BigInt */
|
|
17
|
+
const decimal_js_1 = __importDefault(require("decimal.js"));
|
|
18
|
+
const tokens_1 = require("@defisaver/tokens");
|
|
19
|
+
const viem_1 = require("viem");
|
|
20
|
+
const markets_1 = require("../markets");
|
|
21
|
+
const types_1 = require("../types");
|
|
22
|
+
const common_1 = require("../types/common");
|
|
23
|
+
const contracts_1 = require("../contracts");
|
|
24
|
+
const viem_2 = require("../services/viem");
|
|
25
|
+
const utils_1 = require("../services/utils");
|
|
26
|
+
const aaveBalances_1 = require("../helpers/aaveBalances");
|
|
27
|
+
const fluidBalances_1 = require("../helpers/fluidBalances");
|
|
28
|
+
const aaveV4_1 = require("../aaveV4");
|
|
29
|
+
const compoundV2_1 = require("../compoundV2");
|
|
30
|
+
const compoundV3_1 = require("../compoundV3");
|
|
31
|
+
const curveUsd_1 = require("../curveUsd");
|
|
32
|
+
const llamaLend_1 = require("../llamaLend");
|
|
33
|
+
const morphoBlue_1 = require("../morphoBlue");
|
|
34
|
+
const morphoMidnight_1 = require("../morphoMidnight");
|
|
35
|
+
const liquity_1 = require("../liquity");
|
|
36
|
+
const maker_1 = require("../maker");
|
|
37
|
+
const liquityV2_1 = require("../liquityV2");
|
|
38
|
+
const lendingSummaryTransport_1 = require("./lendingSummaryTransport");
|
|
39
|
+
const nftAbi = (0, viem_1.parseAbi)([
|
|
40
|
+
'function troveNFT() view returns (address)', 'function balanceOf(address) view returns (uint256)',
|
|
41
|
+
'function ownerOf(uint256) view returns (address)',
|
|
42
|
+
]);
|
|
43
|
+
const transfer = (0, viem_1.parseAbiItem)('event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)');
|
|
44
|
+
const units = (value, decimals = 18) => new decimal_js_1.default(String(value)).div(new decimal_js_1.default(10).pow(decimals)).toString();
|
|
45
|
+
const positive = (value) => new decimal_js_1.default(String(value)).gt(0);
|
|
46
|
+
const supported = (list, network) => Object.values(list).filter(m => m.chainIds.includes(network));
|
|
47
|
+
/** Lending-only balances at one snapshot, valued with caller-supplied market prices.
|
|
48
|
+
* One shared client/limiter covers every wallet. Failed reads remain partial; cancellation
|
|
49
|
+
* discards results. Morpho Blue earn deposits, rewards and savings are excluded.
|
|
50
|
+
*/
|
|
51
|
+
function getWalletLendingSummaries(provider, network, walletAddresses, options) {
|
|
52
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
53
|
+
var _a, _b, _c, _d, _e;
|
|
54
|
+
const addresses = [...new Set(walletAddresses.map(address => {
|
|
55
|
+
if (!/^0x[0-9a-f]{40}$/i.test(address))
|
|
56
|
+
throw new Error('Invalid wallet address');
|
|
57
|
+
return address.toLowerCase();
|
|
58
|
+
}))];
|
|
59
|
+
const summaries = Object.fromEntries(addresses.map(address => [address, {
|
|
60
|
+
status: 'complete', positions: [], protocols: [], suppliedUsd: '0', valuationComplete: true, errors: [],
|
|
61
|
+
}]));
|
|
62
|
+
if (!addresses.length || ((_a = options.signal) === null || _a === void 0 ? void 0 : _a.aborted))
|
|
63
|
+
return { summaries: {}, rateLimited: false };
|
|
64
|
+
const maxCalldataBytes = options.isSim ? 2000 : 32000;
|
|
65
|
+
const transport = (0, lendingSummaryTransport_1.lendingSummaryTransport)(provider, options.signal, options.blockNumber, maxCalldataBytes);
|
|
66
|
+
const client = (0, viem_2.getViemProvider)(transport.provider, network, {
|
|
67
|
+
transport: (0, viem_1.custom)(transport.provider, { retryCount: 0 }), batch: { multicall: { batchSize: maxCalldataBytes } },
|
|
68
|
+
});
|
|
69
|
+
let snapshot;
|
|
70
|
+
try {
|
|
71
|
+
snapshot = (_b = options.blockNumber) !== null && _b !== void 0 ? _b : yield client.getBlockNumber();
|
|
72
|
+
transport.pinBlock(snapshot);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
if ((_c = options.signal) === null || _c === void 0 ? void 0 : _c.aborted)
|
|
76
|
+
return { summaries: {}, rateLimited: transport.isRateLimited() };
|
|
77
|
+
for (const summary of Object.values(summaries)) {
|
|
78
|
+
summary.status = 'failed';
|
|
79
|
+
summary.errors.push(String(error));
|
|
80
|
+
}
|
|
81
|
+
return { summaries, rateLimited: transport.isRateLimited() };
|
|
82
|
+
}
|
|
83
|
+
const block = Number(snapshot);
|
|
84
|
+
// Dynamic ABI boundary for user-scoped CDP/NFT reads; money markets use their existing readers.
|
|
85
|
+
const read = (name, functionName, args = []) => client.readContract({
|
|
86
|
+
address: (0, contracts_1.getConfigContractAddress)(name, network, block), abi: (0, contracts_1.getConfigContractAbi)(name, network, block), functionName, args,
|
|
87
|
+
});
|
|
88
|
+
const nftRead = (address, functionName, args = []) => client.readContract({
|
|
89
|
+
address, abi: nftAbi, functionName, args,
|
|
90
|
+
});
|
|
91
|
+
const cache = new Map();
|
|
92
|
+
const shared = (key, fetch) => {
|
|
93
|
+
if (!cache.has(key))
|
|
94
|
+
cache.set(key, fetch());
|
|
95
|
+
return cache.get(key);
|
|
96
|
+
};
|
|
97
|
+
const tasks = [];
|
|
98
|
+
const tokens = new Set();
|
|
99
|
+
const valuations = [];
|
|
100
|
+
let prices = {};
|
|
101
|
+
const run = (address, protocol, key, work) => __awaiter(this, void 0, void 0, function* () {
|
|
102
|
+
var _a;
|
|
103
|
+
try {
|
|
104
|
+
if (!((_a = options.signal) === null || _a === void 0 ? void 0 : _a.aborted))
|
|
105
|
+
yield work();
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
summaries[address].errors.push(`${protocol}:${key}: ${String(error).split('\n')[0]}`);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
const add = (address_1, protocol_1, key_1, balances_1, ...args_1) => __awaiter(this, [address_1, protocol_1, key_1, balances_1, ...args_1], void 0, function* (address, protocol, key, balances, human = false) {
|
|
112
|
+
const supply = Object.entries(balances.collateral || {}).concat(Object.entries(balances.deposited || {}));
|
|
113
|
+
const debt = Object.entries(balances.debt || {});
|
|
114
|
+
if (![...supply, ...debt].some(([, amount]) => positive(amount)))
|
|
115
|
+
return;
|
|
116
|
+
const entry = {
|
|
117
|
+
id: `${protocol}:${key}`,
|
|
118
|
+
protocol,
|
|
119
|
+
suppliedUsd: (supply.some(([, amount]) => positive(amount)) ? null : '0'),
|
|
120
|
+
debtUsd: (debt.some(([, amount]) => positive(amount)) ? null : '0'),
|
|
121
|
+
};
|
|
122
|
+
summaries[address].positions.push(entry);
|
|
123
|
+
const normalize = (amounts) => {
|
|
124
|
+
const result = {};
|
|
125
|
+
amounts.filter(([, amount]) => positive(amount)).forEach(([symbol, amount]) => {
|
|
126
|
+
const token = symbol.startsWith('0x') ? (0, tokens_1.getAssetInfoByAddress)(symbol, network) : (0, tokens_1.getAssetInfo)((0, utils_1.getWrappedNativeAssetFromUnwrapped)(symbol), network);
|
|
127
|
+
if (!token.address || !Number.isFinite(token.decimals))
|
|
128
|
+
throw new Error(`Token metadata unavailable: ${symbol}`);
|
|
129
|
+
const id = token.address.toLowerCase();
|
|
130
|
+
tokens.add(id);
|
|
131
|
+
result[id] = (result[id] || new decimal_js_1.default(0)).add(human ? amount : units(amount, token.decimals));
|
|
132
|
+
});
|
|
133
|
+
return result;
|
|
134
|
+
};
|
|
135
|
+
const amounts = [normalize(supply), normalize(debt)];
|
|
136
|
+
valuations.push(() => {
|
|
137
|
+
['suppliedUsd', 'debtUsd'].forEach((field, i) => {
|
|
138
|
+
try {
|
|
139
|
+
entry[field] = Object.entries(amounts[i]).reduce((total, [token, amount]) => {
|
|
140
|
+
const price = new decimal_js_1.default(prices[token] || 0);
|
|
141
|
+
if (!price.isFinite() || !price.gt(0))
|
|
142
|
+
throw new Error(`Price unavailable: ${token}`);
|
|
143
|
+
return total.add(amount.mul(price));
|
|
144
|
+
}, new decimal_js_1.default(0)).toString();
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
summaries[address].errors.push(`${entry.id}: ${String(error)}`);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
const balanceTask = (address, protocol, key, fetch, human = false) => tasks.push(run(address, protocol, key, () => __awaiter(this, void 0, void 0, function* () { return add(address, protocol, key, yield fetch(), human); })));
|
|
153
|
+
for (const address of addresses) {
|
|
154
|
+
const aaveMarkets = supported((0, markets_1.AaveMarkets)(network), network).filter(m => [types_1.AaveVersions.AaveV2, types_1.AaveVersions.AaveV3, types_1.AaveVersions.AaveV3Lido, types_1.AaveVersions.AaveV3Etherfi].includes(m.value));
|
|
155
|
+
for (const market of [...aaveMarkets, ...supported((0, markets_1.SparkMarkets)(network), network)]) {
|
|
156
|
+
const v2 = market.value === types_1.AaveVersions.AaveV2;
|
|
157
|
+
const spark = !aaveMarkets.some(m => m.value === market.value);
|
|
158
|
+
balanceTask(address, spark ? 'spark' : v2 ? 'aaveV2' : 'aaveV3', market.value, () => (0, aaveBalances_1.getAaveLikeBalances)(client, network, block, false, address, market, spark ? 'SparkView' : v2 ? 'AaveLoanInfoV2' : 'AaveV3View', market.assets.map(asset => (0, tokens_1.getAssetInfo)((0, utils_1.getWrappedNativeAssetFromUnwrapped)(asset), network).address)));
|
|
159
|
+
}
|
|
160
|
+
for (const spoke of supported((0, markets_1.AaveV4Spokes)(network), network)) {
|
|
161
|
+
balanceTask(address, 'aaveV4', spoke.value, () => __awaiter(this, void 0, void 0, function* () {
|
|
162
|
+
const { reserves } = yield (0, aaveV4_1._getAaveV4LoanBalances)(client, network, block, address, spoke.address);
|
|
163
|
+
const balances = { collateral: {}, debt: {} };
|
|
164
|
+
reserves.forEach(r => {
|
|
165
|
+
balances.collateral[r.underlying] = new decimal_js_1.default(balances.collateral[r.underlying] || 0).add(r.supplied.toString()).toString();
|
|
166
|
+
balances.debt[r.underlying] = new decimal_js_1.default(balances.debt[r.underlying] || 0).add(r.totalDebt.toString()).toString();
|
|
167
|
+
});
|
|
168
|
+
return balances;
|
|
169
|
+
}));
|
|
170
|
+
}
|
|
171
|
+
for (const market of supported((0, markets_1.CompoundMarkets)(network), network)) {
|
|
172
|
+
const v2 = market.value === types_1.CompoundVersions.CompoundV2;
|
|
173
|
+
balanceTask(address, v2 ? 'compoundV2' : 'compoundV3', market.value, () => (v2
|
|
174
|
+
? (0, compoundV2_1._getCompoundV2AccountBalances)(client, network, block, false, address, markets_1.compoundV2CollateralAssets.map(a => a.address))
|
|
175
|
+
: (0, compoundV3_1._getCompoundV3AccountBalances)(client, network, block, false, address, market.baseMarketAddress)));
|
|
176
|
+
}
|
|
177
|
+
for (const market of supported((0, markets_1.MorphoBlueMarkets)(network), network))
|
|
178
|
+
balanceTask(address, 'morphoBlue', market.value, () => (0, morphoBlue_1._getMorphoBlueAccountBalances)(client, network, block, false, address, market), true);
|
|
179
|
+
for (const market of supported((0, markets_1.MorphoMidnightMarkets)(network), network))
|
|
180
|
+
balanceTask(address, 'morphoMidnight', market.value, () => (0, morphoMidnight_1._getMorphoMidnightAccountBalances)(client, network, block, false, address, market, true), true);
|
|
181
|
+
if (network === common_1.NetworkNumber.Eth)
|
|
182
|
+
for (const market of supported((0, markets_1.CrvUsdMarkets)(network), network))
|
|
183
|
+
balanceTask(address, 'crvUsd', market.value, () => (0, curveUsd_1._getCrvUsdAccountBalances)(client, network, block, false, address, market.controllerAddress, true));
|
|
184
|
+
if ([common_1.NetworkNumber.Eth, common_1.NetworkNumber.Arb].includes(network))
|
|
185
|
+
for (const market of supported((0, markets_1.LlamaLendMarkets)(network), network))
|
|
186
|
+
balanceTask(address, 'llamaLend', market.value, () => (0, llamaLend_1._getLlamaLendAccountBalances)(client, network, block, false, address, market.controllerAddress, true));
|
|
187
|
+
if (network === common_1.NetworkNumber.Eth) {
|
|
188
|
+
balanceTask(address, 'liquity', 'trove', () => (0, liquity_1._getLiquityAccountBalances)(client, network, block, false, address));
|
|
189
|
+
tasks.push(run(address, 'maker', 'discovery', () => __awaiter(this, void 0, void 0, function* () {
|
|
190
|
+
const cdps = yield (0, maker_1._getUserCdps)(client, network, address);
|
|
191
|
+
yield Promise.all(cdps.map(cdp => run(address, 'maker', String(cdp.id), () => __awaiter(this, void 0, void 0, function* () {
|
|
192
|
+
const [collateral, debt] = yield read('McdVat', 'urns', [cdp.ilk, cdp.urn]);
|
|
193
|
+
const rate = positive(debt) ? (yield shared(`maker:${cdp.ilk}`, () => read('McdVat', 'ilks', [cdp.ilk])))[1] : 0;
|
|
194
|
+
yield add(address, 'maker', String(cdp.id), { collateral: { [cdp.asset]: units(collateral) }, debt: { DAI: new decimal_js_1.default(units(debt)).mul(units(rate, 27)).toString() } }, true);
|
|
195
|
+
}))));
|
|
196
|
+
})));
|
|
197
|
+
for (const market of supported((0, markets_1.LiquityV2Markets)(network), network)) {
|
|
198
|
+
tasks.push(run(address, 'liquityV2', market.value, () => __awaiter(this, void 0, void 0, function* () {
|
|
199
|
+
const nft = yield shared(`nft:${market.value}`, () => nftRead(market.marketAddress, 'troveNFT'));
|
|
200
|
+
const count = yield nftRead(nft, 'balanceOf', [address]);
|
|
201
|
+
if (count === BigInt(0))
|
|
202
|
+
return;
|
|
203
|
+
const logs = yield client.getLogs({
|
|
204
|
+
address: nft, event: transfer, args: { to: address }, fromBlock: BigInt(liquityV2_1.nftContractCreationBlockMapping[market.value]), toBlock: snapshot,
|
|
205
|
+
});
|
|
206
|
+
const owned = (yield Promise.all([...new Set(logs.map(log => log.args.tokenId))].map((id) => __awaiter(this, void 0, void 0, function* () {
|
|
207
|
+
try {
|
|
208
|
+
return (yield nftRead(nft, 'ownerOf', [id])).toLowerCase() === address ? id : null;
|
|
209
|
+
}
|
|
210
|
+
catch (_a) {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
})))).filter((id) => id !== null);
|
|
214
|
+
if (BigInt(owned.length) !== count)
|
|
215
|
+
summaries[address].errors.push(`liquityV2:${market.value}: Not all owned troves could be discovered`);
|
|
216
|
+
yield Promise.all(owned.map(id => run(address, 'liquityV2', `${market.value}:${id}`, () => __awaiter(this, void 0, void 0, function* () {
|
|
217
|
+
const data = yield read(market.isLegacy ? 'LiquityV2LegacyView' : 'LiquityV2View', 'getTroveInfo', [market.marketAddress, id]);
|
|
218
|
+
if (data.owner.toLowerCase() !== address)
|
|
219
|
+
throw new Error('Trove ownership changed');
|
|
220
|
+
yield add(address, 'liquityV2', `${market.value}:${id}`, { collateral: { [market.collateralToken]: data.collAmount.toString() }, debt: { [market.debtToken]: data.debtAmount.toString() } });
|
|
221
|
+
}))));
|
|
222
|
+
})));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if ([common_1.NetworkNumber.Eth, common_1.NetworkNumber.Arb, common_1.NetworkNumber.Base, common_1.NetworkNumber.Plasma].includes(network)) {
|
|
226
|
+
tasks.push(run(address, 'fluid', 'discovery', () => __awaiter(this, void 0, void 0, function* () {
|
|
227
|
+
const [positions, vaults] = yield read('FluidView', 'getUserPositions', [address]);
|
|
228
|
+
yield Promise.all(positions.map((p, i) => run(address, 'fluid', String(p.nftId), () => __awaiter(this, void 0, void 0, function* () {
|
|
229
|
+
if (positive(p.supply) || positive(p.borrow))
|
|
230
|
+
yield add(address, 'fluid', String(p.nftId), (0, fluidBalances_1.parseFluidBalances)(p, vaults[i], network), true);
|
|
231
|
+
}))));
|
|
232
|
+
})));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
yield Promise.all(tasks);
|
|
236
|
+
if ((_d = options.signal) === null || _d === void 0 ? void 0 : _d.aborted)
|
|
237
|
+
return { summaries: {}, rateLimited: transport.isRateLimited() };
|
|
238
|
+
if (tokens.size) {
|
|
239
|
+
try {
|
|
240
|
+
prices = yield options.resolvePrices(network, [...tokens], options.signal);
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
for (const summary of Object.values(summaries))
|
|
244
|
+
if (summary.positions.length)
|
|
245
|
+
summary.errors.push(`Prices: ${String(error)}`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if ((_e = options.signal) === null || _e === void 0 ? void 0 : _e.aborted)
|
|
249
|
+
return { summaries: {}, rateLimited: transport.isRateLimited() };
|
|
250
|
+
valuations.forEach(value => value());
|
|
251
|
+
for (const summary of Object.values(summaries)) {
|
|
252
|
+
summary.positions.sort((a, b) => a.id.localeCompare(b.id));
|
|
253
|
+
summary.protocols = [...new Set(summary.positions.map(p => p.protocol))];
|
|
254
|
+
summary.suppliedUsd = summary.positions.reduce((total, p) => total.add(p.suppliedUsd || 0), new decimal_js_1.default(0)).toString();
|
|
255
|
+
summary.valuationComplete = summary.positions.every(p => p.suppliedUsd !== null && p.debtUsd !== null);
|
|
256
|
+
summary.errors = [...new Set(summary.errors)];
|
|
257
|
+
if (summary.errors.length)
|
|
258
|
+
summary.status = 'partial';
|
|
259
|
+
}
|
|
260
|
+
return { summaries, rateLimited: transport.isRateLimited() };
|
|
261
|
+
});
|
|
262
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { EthereumProvider } from '../types/common';
|
|
2
|
+
export declare const isLendingSummaryRateLimit: (error: unknown) => boolean;
|
|
3
|
+
/** One limiter for all reads, including split multicalls. No retries after cancellation/429. */
|
|
4
|
+
export declare function lendingSummaryTransport(provider: EthereumProvider, signal?: AbortSignal, blockNumber?: bigint, maxCalldataBytes?: number): {
|
|
5
|
+
provider: EthereumProvider;
|
|
6
|
+
isRateLimited: () => boolean;
|
|
7
|
+
pinBlock: (value: bigint) => void;
|
|
8
|
+
};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.isLendingSummaryRateLimit = void 0;
|
|
13
|
+
exports.lendingSummaryTransport = lendingSummaryTransport;
|
|
14
|
+
const viem_1 = require("viem");
|
|
15
|
+
const errorText = (error) => {
|
|
16
|
+
const detail = error;
|
|
17
|
+
return `${(detail === null || detail === void 0 ? void 0 : detail.message) || String(error)} ${(detail === null || detail === void 0 ? void 0 : detail.code) || ''} ${(detail === null || detail === void 0 ? void 0 : detail.status) || ''}`;
|
|
18
|
+
};
|
|
19
|
+
const logRangeLimit = (error) => /block range|too many (results|logs)|query returned|response.*size|range.*limit/i.test(errorText(error));
|
|
20
|
+
const oversized = (error) => /413|request.*(large|size)|response.*(large|size)|out of gas|gas (required|limit)|exceeds.*gas|execution.*limit/i.test(errorText(error));
|
|
21
|
+
const isLendingSummaryRateLimit = (error) => !oversized(error) && !logRangeLimit(error) && /429|rate.?limit|too many requests|compute units|limit exceeded/i.test(errorText(error));
|
|
22
|
+
exports.isLendingSummaryRateLimit = isLendingSummaryRateLimit;
|
|
23
|
+
/** One limiter for all reads, including split multicalls. No retries after cancellation/429. */
|
|
24
|
+
function lendingSummaryTransport(provider, signal, blockNumber, maxCalldataBytes = 32000) {
|
|
25
|
+
let pinnedBlock = blockNumber;
|
|
26
|
+
let active = 0;
|
|
27
|
+
let rateLimit;
|
|
28
|
+
const waiting = [];
|
|
29
|
+
const check = () => {
|
|
30
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted)
|
|
31
|
+
throw new Error('Lending summary cancelled');
|
|
32
|
+
// Keep the provider's original error code/message, including plain RPC error objects.
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-throw-literal
|
|
34
|
+
if (rateLimit !== undefined)
|
|
35
|
+
throw rateLimit;
|
|
36
|
+
};
|
|
37
|
+
const send = (args) => __awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
if (active >= 4)
|
|
39
|
+
yield new Promise(resolve => { waiting.push(resolve); });
|
|
40
|
+
else
|
|
41
|
+
active++;
|
|
42
|
+
try {
|
|
43
|
+
check();
|
|
44
|
+
return yield provider.request(args);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if ((0, exports.isLendingSummaryRateLimit)(error))
|
|
48
|
+
rateLimit = error;
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
const next = waiting.shift();
|
|
53
|
+
if (next)
|
|
54
|
+
next();
|
|
55
|
+
else
|
|
56
|
+
active--;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
const request = (args) => __awaiter(this, void 0, void 0, function* () {
|
|
60
|
+
var _a;
|
|
61
|
+
check();
|
|
62
|
+
const params = [...(args.params || [])];
|
|
63
|
+
if (pinnedBlock !== undefined) {
|
|
64
|
+
const block = `0x${pinnedBlock.toString(16)}`;
|
|
65
|
+
if (args.method === 'eth_blockNumber')
|
|
66
|
+
return block;
|
|
67
|
+
if (['eth_call', 'eth_getCode'].includes(args.method))
|
|
68
|
+
params[1] = block;
|
|
69
|
+
}
|
|
70
|
+
const call = params[0];
|
|
71
|
+
const isMulticall = args.method === 'eth_call' && ((_a = call === null || call === void 0 ? void 0 : call.data) === null || _a === void 0 ? void 0 : _a.startsWith('0x82ad56cb'));
|
|
72
|
+
const splitMulticall = (error) => __awaiter(this, void 0, void 0, function* () {
|
|
73
|
+
const { args: [calls] } = (0, viem_1.decodeFunctionData)({ abi: viem_1.multicall3Abi, data: call.data });
|
|
74
|
+
if (!calls || calls.length < 2)
|
|
75
|
+
throw error;
|
|
76
|
+
// Sequential halves keep the same concurrency bound and retain per-call failures.
|
|
77
|
+
const results = [];
|
|
78
|
+
for (const half of [calls.slice(0, Math.ceil(calls.length / 2)), calls.slice(Math.ceil(calls.length / 2))]) {
|
|
79
|
+
const data = (0, viem_1.encodeFunctionData)({ abi: viem_1.multicall3Abi, functionName: 'aggregate3', args: [half] });
|
|
80
|
+
const encoded = yield request(Object.assign(Object.assign({}, args), { params: [Object.assign(Object.assign({}, call), { data }), ...params.slice(1)] }));
|
|
81
|
+
results.push(...(0, viem_1.decodeFunctionResult)({ abi: viem_1.multicall3Abi, functionName: 'aggregate3', data: encoded }));
|
|
82
|
+
}
|
|
83
|
+
return (0, viem_1.encodeFunctionResult)({ abi: viem_1.multicall3Abi, functionName: 'aggregate3', result: results });
|
|
84
|
+
});
|
|
85
|
+
// Viem's batch size counts inner calls only. Also bound the fully encoded calldata.
|
|
86
|
+
if (isMulticall && (call.data.length - 2) / 2 > maxCalldataBytes)
|
|
87
|
+
return splitMulticall(new Error('Single call exceeds summary calldata limit'));
|
|
88
|
+
try {
|
|
89
|
+
return yield send(Object.assign(Object.assign({}, args), { params }));
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
check();
|
|
93
|
+
if (args.method === 'eth_getLogs' && logRangeLimit(error)) {
|
|
94
|
+
const from = BigInt(call.fromBlock);
|
|
95
|
+
const to = BigInt(call.toBlock);
|
|
96
|
+
if (from >= to)
|
|
97
|
+
throw error;
|
|
98
|
+
const middle = (from + to) / BigInt(2);
|
|
99
|
+
const first = yield request(Object.assign(Object.assign({}, args), { params: [Object.assign(Object.assign({}, call), { toBlock: `0x${middle.toString(16)}` })] }));
|
|
100
|
+
const last = yield request(Object.assign(Object.assign({}, args), { params: [Object.assign(Object.assign({}, call), { fromBlock: `0x${(middle + BigInt(1)).toString(16)}` })] }));
|
|
101
|
+
return [...first, ...last];
|
|
102
|
+
}
|
|
103
|
+
if (!isMulticall || !oversized(error))
|
|
104
|
+
throw error;
|
|
105
|
+
return splitMulticall(error);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
return { provider: { request }, isRateLimited: () => rateLimit !== undefined, pinBlock: (value) => { pinnedBlock = value; } };
|
|
109
|
+
}
|
package/cjs/spark/index.js
CHANGED
|
@@ -15,6 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
15
|
exports.getSparkFullPositionData = exports.getSparkAccountData = exports._getSparkAccountData = exports.getSparkAccountBalances = exports._getSparkAccountBalances = exports.EMPTY_SPARK_DATA = exports.getSparkMarketsData = exports._getSparkMarketsData = exports.sparkEmodeCategoriesMapping = void 0;
|
|
16
16
|
const decimal_js_1 = __importDefault(require("decimal.js"));
|
|
17
17
|
const tokens_1 = require("@defisaver/tokens");
|
|
18
|
+
const aaveBalances_1 = require("../helpers/aaveBalances");
|
|
18
19
|
const common_1 = require("../types/common");
|
|
19
20
|
const utils_1 = require("../services/utils");
|
|
20
21
|
const staking_1 = require("../staking");
|
|
@@ -237,37 +238,7 @@ exports.EMPTY_SPARK_DATA = {
|
|
|
237
238
|
exposure: 'N/A',
|
|
238
239
|
};
|
|
239
240
|
const _getSparkAccountBalances = (provider, network, block, addressMapping, address) => __awaiter(void 0, void 0, void 0, function* () {
|
|
240
|
-
|
|
241
|
-
collateral: {},
|
|
242
|
-
debt: {},
|
|
243
|
-
};
|
|
244
|
-
if (!address) {
|
|
245
|
-
return balances;
|
|
246
|
-
}
|
|
247
|
-
const loanInfoContract = (0, contracts_1.SparkViewContractViem)(provider, network, block);
|
|
248
|
-
const market = (0, spark_1.SPARK_V1)(network);
|
|
249
|
-
const marketAddress = market.providerAddress;
|
|
250
|
-
// @ts-ignore
|
|
251
|
-
const protocolDataProviderContract = (0, contracts_1.createViemContractFromConfigFunc)(market.protocolData, market.protocolDataAddress)(provider, network);
|
|
252
|
-
// @ts-ignore
|
|
253
|
-
const reserveTokens = yield protocolDataProviderContract.read.getAllReservesTokens((0, viem_1.setViemBlockNumber)(block));
|
|
254
|
-
const symbols = reserveTokens.map(({ symbol }) => symbol);
|
|
255
|
-
const _addresses = reserveTokens.map(({ tokenAddress }) => tokenAddress);
|
|
256
|
-
// split addresses in half to avoid gas limit by multicall
|
|
257
|
-
const middleAddressIndex = Math.floor(_addresses.length / 2);
|
|
258
|
-
const [tokenBalances1, tokenBalances2] = yield Promise.all([
|
|
259
|
-
loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(0, middleAddressIndex)], (0, viem_1.setViemBlockNumber)(block)),
|
|
260
|
-
loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(middleAddressIndex, _addresses.length)], (0, viem_1.setViemBlockNumber)(block)),
|
|
261
|
-
]);
|
|
262
|
-
const loanInfo = [...tokenBalances1, ...tokenBalances2];
|
|
263
|
-
loanInfo.forEach((tokenInfo, i) => {
|
|
264
|
-
const asset = (0, utils_1.wethToEth)(symbols[i]);
|
|
265
|
-
const assetAddr = (0, utils_1.wethToEthByAddress)(_addresses[i], network).toLowerCase();
|
|
266
|
-
balances = {
|
|
267
|
-
collateral: Object.assign(Object.assign({}, balances.collateral), { [addressMapping ? assetAddr : asset]: tokenInfo.balance.toString() }),
|
|
268
|
-
debt: Object.assign(Object.assign({}, balances.debt), { [addressMapping ? assetAddr : asset]: new decimal_js_1.default(tokenInfo.borrowsStable.toString()).add(tokenInfo.borrowsVariable.toString()).toString() }),
|
|
269
|
-
};
|
|
270
|
-
});
|
|
241
|
+
const balances = yield (0, aaveBalances_1.getAaveLikeBalances)(provider, network, block, addressMapping, address, (0, spark_1.SPARK_V1)(network), 'SparkView');
|
|
271
242
|
return balances;
|
|
272
243
|
});
|
|
273
244
|
exports._getSparkAccountBalances = _getSparkAccountBalances;
|
package/cjs/types/index.d.ts
CHANGED
package/cjs/types/index.js
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { EthAddress, NetworkNumber } from './common';
|
|
2
|
+
export type LendingSummaryPosition = {
|
|
3
|
+
id: string;
|
|
4
|
+
protocol: string;
|
|
5
|
+
/** Estimated decimal USD values; null means unavailable, never a verified zero. */
|
|
6
|
+
suppliedUsd: string | null;
|
|
7
|
+
debtUsd: string | null;
|
|
8
|
+
};
|
|
9
|
+
export type WalletLendingSummary = {
|
|
10
|
+
status: 'complete' | 'partial' | 'failed';
|
|
11
|
+
positions: LendingSummaryPosition[];
|
|
12
|
+
protocols: string[];
|
|
13
|
+
/** Sum of known supply values; check valuationComplete before ranking by value. */
|
|
14
|
+
suppliedUsd: string;
|
|
15
|
+
valuationComplete: boolean;
|
|
16
|
+
errors: string[];
|
|
17
|
+
};
|
|
18
|
+
/** Resolve distinct token addresses to USD prices keyed by lowercase address.
|
|
19
|
+
* Native tokens use their wrapped address. Missing/invalid prices remain unavailable.
|
|
20
|
+
* Prices are current market estimates; balances may come from a historical/fork snapshot.
|
|
21
|
+
*/
|
|
22
|
+
export type LendingSummaryPriceResolver = (network: NetworkNumber, tokens: EthAddress[], signal?: AbortSignal) => Promise<Record<string, string>>;
|
|
23
|
+
export type LendingSummaryOptions = {
|
|
24
|
+
resolvePrices: LendingSummaryPriceResolver;
|
|
25
|
+
signal?: AbortSignal;
|
|
26
|
+
/** Defaults to a snapshot of the provider's latest block. */
|
|
27
|
+
blockNumber?: bigint;
|
|
28
|
+
/** Use the smaller 2 KB calldata limit required by simulation providers. */
|
|
29
|
+
isSim?: boolean;
|
|
30
|
+
};
|
|
31
|
+
export type WalletLendingSummaries = {
|
|
32
|
+
summaries: Record<string, WalletLendingSummary>;
|
|
33
|
+
rateLimited: boolean;
|
|
34
|
+
};
|
package/esm/aaveV2/index.js
CHANGED
|
@@ -9,16 +9,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
};
|
|
10
10
|
import Dec from 'decimal.js';
|
|
11
11
|
import { assetAmountInEth, getAssetInfo } from '@defisaver/tokens';
|
|
12
|
+
import { getAaveLikeBalances } from '../helpers/aaveBalances';
|
|
12
13
|
import { IncentiveKind, } from '../types/common';
|
|
13
14
|
import { calculateNetApy, getStakingApy } from '../staking';
|
|
14
|
-
import { ethToWeth
|
|
15
|
-
import { AaveLoanInfoV2ContractViem
|
|
15
|
+
import { ethToWeth } from '../services/utils';
|
|
16
|
+
import { AaveLoanInfoV2ContractViem } from '../contracts';
|
|
16
17
|
import { aprToApy, calculateBorrowingAssetLimit } from '../moneymarket';
|
|
17
18
|
import { EMPTY_AAVE_DATA } from '../aaveV3';
|
|
18
19
|
import { AAVE_V2 } from '../markets/aave';
|
|
19
20
|
import { aaveAnyGetAggregatedPositionData } from '../helpers/aaveHelpers';
|
|
20
21
|
import { getEthPrice } from '../services/priceService';
|
|
21
|
-
import { getViemProvider
|
|
22
|
+
import { getViemProvider } from '../services/viem';
|
|
22
23
|
export const _getAaveV2MarketsData = (provider, network, selectedMarket) => __awaiter(void 0, void 0, void 0, function* () {
|
|
23
24
|
const _addresses = selectedMarket.assets.map(a => getAssetInfo(ethToWeth(a)).address);
|
|
24
25
|
const loanInfoContract = AaveLoanInfoV2ContractViem(provider, network);
|
|
@@ -85,36 +86,14 @@ export const _getAaveV2MarketsData = (provider, network, selectedMarket) => __aw
|
|
|
85
86
|
});
|
|
86
87
|
export const getAaveV2MarketsData = (provider, network, selectedMarket) => __awaiter(void 0, void 0, void 0, function* () { return _getAaveV2MarketsData(getViemProvider(provider, network), network, selectedMarket); });
|
|
87
88
|
export const _getAaveV2AccountBalances = (provider, network, block, addressMapping, address) => __awaiter(void 0, void 0, void 0, function* () {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
};
|
|
92
|
-
if (!address) {
|
|
89
|
+
var _a;
|
|
90
|
+
const balances = yield getAaveLikeBalances(provider, network, block, addressMapping, address, AAVE_V2, 'AaveLoanInfoV2');
|
|
91
|
+
if (!address)
|
|
93
92
|
return balances;
|
|
94
|
-
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// @ts-ignore
|
|
99
|
-
const protocolDataProviderContract = createViemContractFromConfigFunc(market.protocolData, market.protocolDataAddress)(provider, network);
|
|
100
|
-
// @ts-ignore
|
|
101
|
-
const reserveTokens = yield protocolDataProviderContract.read.getAllReservesTokens(setViemBlockNumber(block));
|
|
102
|
-
const symbols = reserveTokens.map(({ symbol }) => symbol);
|
|
103
|
-
const _addresses = reserveTokens.map(({ tokenAddress }) => tokenAddress);
|
|
104
|
-
const loanInfo = yield loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses], setViemBlockNumber(block));
|
|
105
|
-
loanInfo.forEach((_tokenInfo, i) => {
|
|
106
|
-
const asset = wethToEth(symbols[i]);
|
|
107
|
-
const assetAddr = wethToEthByAddress(_addresses[i], network).toLowerCase();
|
|
108
|
-
const tokenInfo = Object.assign({}, _tokenInfo);
|
|
109
|
-
// known bug: stETH leaves 1 wei on every transfer
|
|
110
|
-
if (asset === 'stETH' && tokenInfo.balance.toString() === '1') {
|
|
111
|
-
tokenInfo.balance = '0';
|
|
112
|
-
}
|
|
113
|
-
balances = {
|
|
114
|
-
collateral: Object.assign(Object.assign({}, balances.collateral), { [addressMapping ? assetAddr : asset]: tokenInfo.balance.toString() }),
|
|
115
|
-
debt: Object.assign(Object.assign({}, balances.debt), { [addressMapping ? assetAddr : asset]: new Dec(tokenInfo.borrowsStable.toString()).add(tokenInfo.borrowsVariable.toString()).toString() }),
|
|
116
|
-
};
|
|
117
|
-
});
|
|
93
|
+
// Preserve the legacy getter's stETH transfer-dust convention.
|
|
94
|
+
const key = addressMapping ? getAssetInfo('stETH', network).address.toLowerCase() : 'stETH';
|
|
95
|
+
if (((_a = balances.collateral) === null || _a === void 0 ? void 0 : _a[key]) === '1')
|
|
96
|
+
balances.collateral[key] = '0';
|
|
118
97
|
return balances;
|
|
119
98
|
});
|
|
120
99
|
export const getAaveV2AccountBalances = (provider, network, block, addressMapping, address) => __awaiter(void 0, void 0, void 0, function* () { return _getAaveV2AccountBalances(getViemProvider(provider, network), network, block, addressMapping, address); });
|
package/esm/aaveV3/index.js
CHANGED
|
@@ -9,11 +9,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
};
|
|
10
10
|
import { assetAmountInEth, assetAmountInWei, getAssetInfo } from '@defisaver/tokens';
|
|
11
11
|
import Dec from 'decimal.js';
|
|
12
|
+
import { getAaveLikeBalances } from '../helpers/aaveBalances';
|
|
12
13
|
import { AaveIncentiveDataProviderV3ContractViem, AaveIncentivesControllerViem, AaveV3ViewContractViem, createViemContractFromConfigFunc, getConfigContractAbi, StkAAVEViem, } from '../contracts';
|
|
13
14
|
import { aaveAnyGetAggregatedPositionData, aaveV3IsInIsolationMode, aaveV3IsInSiloedMode } from '../helpers/aaveHelpers';
|
|
14
15
|
import { AAVE_V3 } from '../markets/aave';
|
|
15
16
|
import { aprToApy, calculateBorrowingAssetLimit } from '../moneymarket';
|
|
16
|
-
import { getWrappedNativeAssetFromUnwrapped, isEnabledOnBitmap,
|
|
17
|
+
import { getWrappedNativeAssetFromUnwrapped, isEnabledOnBitmap, } from '../services/utils';
|
|
17
18
|
import { getStakingApy, STAKING_ASSETS } from '../staking';
|
|
18
19
|
import { IncentiveKind, NetworkNumber, } from '../types/common';
|
|
19
20
|
import { getViemProvider, setViemBlockNumber } from '../services/viem';
|
|
@@ -334,37 +335,7 @@ export const EMPTY_AAVE_DATA = {
|
|
|
334
335
|
exposure: 'N/A',
|
|
335
336
|
};
|
|
336
337
|
export const _getAaveV3AccountBalances = (provider, network, block, addressMapping, address) => __awaiter(void 0, void 0, void 0, function* () {
|
|
337
|
-
|
|
338
|
-
collateral: {},
|
|
339
|
-
debt: {},
|
|
340
|
-
};
|
|
341
|
-
if (!address) {
|
|
342
|
-
return balances;
|
|
343
|
-
}
|
|
344
|
-
const loanInfoContract = AaveV3ViewContractViem(provider, network, block);
|
|
345
|
-
const market = AAVE_V3(network);
|
|
346
|
-
const marketAddress = market.providerAddress;
|
|
347
|
-
// @ts-ignore
|
|
348
|
-
const protocolDataProviderContract = createViemContractFromConfigFunc(market.protocolData, market.protocolDataAddress)(provider, network);
|
|
349
|
-
// @ts-ignore
|
|
350
|
-
const reserveTokens = yield protocolDataProviderContract.read.getAllReservesTokens(setViemBlockNumber(block));
|
|
351
|
-
const symbols = reserveTokens.map(({ symbol }) => symbol);
|
|
352
|
-
const _addresses = reserveTokens.map(({ tokenAddress }) => tokenAddress);
|
|
353
|
-
// split addresses in half to avoid gas limit by multicall
|
|
354
|
-
const middleAddressIndex = Math.floor(_addresses.length / 2);
|
|
355
|
-
const [tokenBalances1, tokenBalances2] = yield Promise.all([
|
|
356
|
-
loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(0, middleAddressIndex)], setViemBlockNumber(block)),
|
|
357
|
-
loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(middleAddressIndex, _addresses.length)], setViemBlockNumber(block)),
|
|
358
|
-
]);
|
|
359
|
-
const loanInfo = [...tokenBalances1, ...tokenBalances2];
|
|
360
|
-
loanInfo.forEach((tokenInfo, i) => {
|
|
361
|
-
const asset = wethToEth(symbols[i]);
|
|
362
|
-
const assetAddr = wethToEthByAddress(_addresses[i], network).toLowerCase();
|
|
363
|
-
balances = {
|
|
364
|
-
collateral: Object.assign(Object.assign({}, balances.collateral), { [addressMapping ? assetAddr : asset]: tokenInfo.balance.toString() }),
|
|
365
|
-
debt: Object.assign(Object.assign({}, balances.debt), { [addressMapping ? assetAddr : asset]: new Dec(tokenInfo.borrowsStable.toString()).add(tokenInfo.borrowsVariable.toString()).toString() }),
|
|
366
|
-
};
|
|
367
|
-
});
|
|
338
|
+
const balances = yield getAaveLikeBalances(provider, network, block, addressMapping, address, AAVE_V3(network), 'AaveV3View');
|
|
368
339
|
return balances;
|
|
369
340
|
});
|
|
370
341
|
export const getAaveV3AccountBalances = (provider, network, block, addressMapping, address) => __awaiter(void 0, void 0, void 0, function* () { return _getAaveV3AccountBalances(getViemProvider(provider, network), network, block, addressMapping, address); });
|
package/esm/aaveV4/index.d.ts
CHANGED
|
@@ -5,6 +5,31 @@ export { getAaveV4MerkleCampaigns } from './merkl';
|
|
|
5
5
|
export declare function _getAaveV4SpokeData(provider: Client, network: NetworkNumber, market: AaveV4SpokeInfo, blockNumber?: 'latest' | number): Promise<AaveV4SpokeData>;
|
|
6
6
|
export declare function getAaveV4SpokeData(provider: EthereumProvider, network: NetworkNumber, spoke: AaveV4SpokeInfo, blockNumber?: 'latest' | number): Promise<AaveV4SpokeData>;
|
|
7
7
|
export declare function _getAaveV4AccountData(provider: Client, network: NetworkNumber, spokeData: AaveV4SpokeData, address: EthAddress, blockNumber?: 'latest' | number): Promise<AaveV4AccountData>;
|
|
8
|
+
/** Shared raw read; no spoke metadata or market enrichment. */
|
|
9
|
+
export declare const _getAaveV4LoanBalances: (provider: Client, network: NetworkNumber, block: Blockish, address: EthAddress, spoke: EthAddress) => Promise<{
|
|
10
|
+
user: `0x${string}`;
|
|
11
|
+
riskPremium: bigint;
|
|
12
|
+
avgCollateralFactor: bigint;
|
|
13
|
+
healthFactor: bigint;
|
|
14
|
+
totalCollateralInUsd: bigint;
|
|
15
|
+
totalDebtInUsdRay: bigint;
|
|
16
|
+
activeCollateralCount: bigint;
|
|
17
|
+
borrowCount: bigint;
|
|
18
|
+
reserves: readonly {
|
|
19
|
+
reserveId: bigint;
|
|
20
|
+
assetId: number;
|
|
21
|
+
underlying: `0x${string}`;
|
|
22
|
+
supplied: bigint;
|
|
23
|
+
drawn: bigint;
|
|
24
|
+
premium: bigint;
|
|
25
|
+
totalDebt: bigint;
|
|
26
|
+
collateralFactor: number;
|
|
27
|
+
maxLiquidationBonus: number;
|
|
28
|
+
liquidationFee: number;
|
|
29
|
+
isUsingAsCollateral: boolean;
|
|
30
|
+
isBorrowing: boolean;
|
|
31
|
+
}[];
|
|
32
|
+
}>;
|
|
8
33
|
/**
|
|
9
34
|
* Lightweight existence check for Loan Shifter / UI discovery.
|
|
10
35
|
* Reads only `getLoanData(spoke, user)` and returns whether any reserve has
|