@defisaver/positions-sdk 2.1.167 → 2.1.168-stable-pair-dev
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/aaveV4Helpers/index.js +11 -1
- 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/moneymarket/moneymarketCommonService.js +12 -2
- 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/common.d.ts +1 -0
- package/cjs/types/common.js +1 -0
- 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/aaveV4Helpers/index.js +11 -1
- 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/moneymarket/moneymarketCommonService.js +12 -2
- 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/common.d.ts +1 -0
- package/esm/types/common.js +1 -0
- 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/aaveV4Helpers/index.ts +12 -1
- package/src/helpers/fluidBalances.ts +34 -0
- package/src/liquityV2/index.ts +1 -1
- package/src/llamaLend/index.ts +6 -1
- package/src/moneymarket/moneymarketCommonService.ts +13 -2
- 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/common.ts +1 -0
- package/src/types/index.ts +2 -1
- package/src/types/lendingSummary.ts +41 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import {
|
|
2
|
+
decodeFunctionData, decodeFunctionResult, encodeFunctionData, encodeFunctionResult, multicall3Abi,
|
|
3
|
+
} from 'viem';
|
|
4
|
+
import { EthereumProvider } from '../types/common';
|
|
5
|
+
|
|
6
|
+
const errorText = (error: unknown) => {
|
|
7
|
+
const detail = error as { message?: string; code?: number; status?: number };
|
|
8
|
+
return `${detail?.message || String(error)} ${detail?.code || ''} ${detail?.status || ''}`;
|
|
9
|
+
};
|
|
10
|
+
const logRangeLimit = (error: unknown) => /block range|too many (results|logs)|query returned|response.*size|range.*limit/i.test(errorText(error));
|
|
11
|
+
const oversized = (error: unknown) => /413|request.*(large|size)|response.*(large|size)|out of gas|gas (required|limit)|exceeds.*gas|execution.*limit/i.test(errorText(error));
|
|
12
|
+
|
|
13
|
+
export const isLendingSummaryRateLimit = (error: unknown): boolean => !oversized(error) && !logRangeLimit(error) && /429|rate.?limit|too many requests|compute units|limit exceeded/i.test(errorText(error));
|
|
14
|
+
|
|
15
|
+
/** One limiter for all reads, including split multicalls. No retries after cancellation/429. */
|
|
16
|
+
export function lendingSummaryTransport(provider: EthereumProvider, signal?: AbortSignal, blockNumber?: bigint, maxCalldataBytes = 32_000) {
|
|
17
|
+
let pinnedBlock = blockNumber;
|
|
18
|
+
let active = 0;
|
|
19
|
+
let rateLimit: unknown;
|
|
20
|
+
const waiting: (() => void)[] = [];
|
|
21
|
+
const check = () => {
|
|
22
|
+
if (signal?.aborted) throw new Error('Lending summary cancelled');
|
|
23
|
+
// Keep the provider's original error code/message, including plain RPC error objects.
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-throw-literal
|
|
25
|
+
if (rateLimit !== undefined) throw rateLimit;
|
|
26
|
+
};
|
|
27
|
+
const send = async (args: Parameters<EthereumProvider['request']>[0]) => {
|
|
28
|
+
if (active >= 4) await new Promise<void>(resolve => { waiting.push(resolve); });
|
|
29
|
+
else active++;
|
|
30
|
+
try {
|
|
31
|
+
check();
|
|
32
|
+
return await provider.request(args);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
if (isLendingSummaryRateLimit(error)) rateLimit = error;
|
|
35
|
+
throw error;
|
|
36
|
+
} finally {
|
|
37
|
+
const next = waiting.shift();
|
|
38
|
+
if (next) next();
|
|
39
|
+
else active--;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const request: EthereumProvider['request'] = async (args) => {
|
|
43
|
+
check();
|
|
44
|
+
const params = [...(args.params || [])] as any[];
|
|
45
|
+
if (pinnedBlock !== undefined) {
|
|
46
|
+
const block = `0x${pinnedBlock.toString(16)}`;
|
|
47
|
+
if (args.method === 'eth_blockNumber') return block;
|
|
48
|
+
if (['eth_call', 'eth_getCode'].includes(args.method)) params[1] = block;
|
|
49
|
+
}
|
|
50
|
+
const call = params[0];
|
|
51
|
+
const isMulticall = args.method === 'eth_call' && call?.data?.startsWith('0x82ad56cb');
|
|
52
|
+
const splitMulticall = async (error: unknown) => {
|
|
53
|
+
const { args: [calls] } = decodeFunctionData({ abi: multicall3Abi, data: call.data });
|
|
54
|
+
if (!calls || calls.length < 2) throw error;
|
|
55
|
+
// Sequential halves keep the same concurrency bound and retain per-call failures.
|
|
56
|
+
const results = [];
|
|
57
|
+
for (const half of [calls.slice(0, Math.ceil(calls.length / 2)), calls.slice(Math.ceil(calls.length / 2))]) {
|
|
58
|
+
const data = encodeFunctionData({ abi: multicall3Abi, functionName: 'aggregate3', args: [half] });
|
|
59
|
+
const encoded = await request({ ...args, params: [{ ...call, data }, ...params.slice(1)] });
|
|
60
|
+
results.push(...decodeFunctionResult({ abi: multicall3Abi, functionName: 'aggregate3', data: encoded }));
|
|
61
|
+
}
|
|
62
|
+
return encodeFunctionResult({ abi: multicall3Abi, functionName: 'aggregate3', result: results });
|
|
63
|
+
};
|
|
64
|
+
// Viem's batch size counts inner calls only. Also bound the fully encoded calldata.
|
|
65
|
+
if (isMulticall && (call.data.length - 2) / 2 > maxCalldataBytes) return splitMulticall(new Error('Single call exceeds summary calldata limit'));
|
|
66
|
+
try {
|
|
67
|
+
return await send({ ...args, params });
|
|
68
|
+
} catch (error) {
|
|
69
|
+
check();
|
|
70
|
+
if (args.method === 'eth_getLogs' && logRangeLimit(error)) {
|
|
71
|
+
const from = BigInt(call.fromBlock);
|
|
72
|
+
const to = BigInt(call.toBlock);
|
|
73
|
+
if (from >= to) throw error;
|
|
74
|
+
const middle = (from + to) / BigInt(2);
|
|
75
|
+
const first = await request({ ...args, params: [{ ...call, toBlock: `0x${middle.toString(16)}` }] });
|
|
76
|
+
const last = await request({ ...args, params: [{ ...call, fromBlock: `0x${(middle + BigInt(1)).toString(16)}` }] });
|
|
77
|
+
return [...first, ...last];
|
|
78
|
+
}
|
|
79
|
+
if (!isMulticall || !oversized(error)) throw error;
|
|
80
|
+
return splitMulticall(error);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
return { provider: { request } as EthereumProvider, isRateLimited: () => rateLimit !== undefined, pinBlock: (value: bigint) => { pinnedBlock = value; } };
|
|
84
|
+
}
|
package/src/spark/index.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import Dec from 'decimal.js';
|
|
2
2
|
import { assetAmountInEth, assetAmountInWei, getAssetInfo } from '@defisaver/tokens';
|
|
3
3
|
import { Client } from 'viem';
|
|
4
|
+
import { getAaveLikeBalances } from '../helpers/aaveBalances';
|
|
4
5
|
import {
|
|
5
6
|
Blockish, EthAddress, EthereumProvider, IncentiveKind, NetworkNumber, PositionBalances,
|
|
6
7
|
} from '../types/common';
|
|
7
8
|
import {
|
|
8
|
-
ethToWeth, wethToEth,
|
|
9
|
+
ethToWeth, wethToEth,
|
|
9
10
|
} from '../services/utils';
|
|
10
11
|
import {
|
|
11
12
|
calculateNetApy, getStakingApy, STAKING_ASSETS,
|
|
@@ -269,54 +270,7 @@ export const EMPTY_SPARK_DATA = {
|
|
|
269
270
|
};
|
|
270
271
|
|
|
271
272
|
export const _getSparkAccountBalances = async (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress): Promise<PositionBalances> => {
|
|
272
|
-
|
|
273
|
-
collateral: {},
|
|
274
|
-
debt: {},
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
if (!address) {
|
|
278
|
-
return balances;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
const loanInfoContract = SparkViewContractViem(provider, network, block);
|
|
282
|
-
|
|
283
|
-
const market = SPARK_V1(network);
|
|
284
|
-
const marketAddress = market.providerAddress;
|
|
285
|
-
// @ts-ignore
|
|
286
|
-
const protocolDataProviderContract = createViemContractFromConfigFunc(market.protocolData, market.protocolDataAddress)(provider, network);
|
|
287
|
-
|
|
288
|
-
// @ts-ignore
|
|
289
|
-
const reserveTokens = await protocolDataProviderContract.read.getAllReservesTokens(setViemBlockNumber(block)) as { symbol: string, tokenAddress: EthAddress }[];
|
|
290
|
-
const symbols = reserveTokens.map(({ symbol }: { symbol: string }) => symbol);
|
|
291
|
-
const _addresses = reserveTokens.map(({ tokenAddress }: { tokenAddress: EthAddress }) => tokenAddress);
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
// split addresses in half to avoid gas limit by multicall
|
|
295
|
-
const middleAddressIndex = Math.floor(_addresses.length / 2);
|
|
296
|
-
|
|
297
|
-
const [tokenBalances1, tokenBalances2] = await Promise.all([
|
|
298
|
-
loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(0, middleAddressIndex)], setViemBlockNumber(block)),
|
|
299
|
-
loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(middleAddressIndex, _addresses.length)], setViemBlockNumber(block)),
|
|
300
|
-
]);
|
|
301
|
-
|
|
302
|
-
const loanInfo = [...tokenBalances1, ...tokenBalances2];
|
|
303
|
-
|
|
304
|
-
loanInfo.forEach((tokenInfo: any, i: number) => {
|
|
305
|
-
const asset = wethToEth(symbols[i]);
|
|
306
|
-
const assetAddr = wethToEthByAddress(_addresses[i], network).toLowerCase();
|
|
307
|
-
|
|
308
|
-
balances = {
|
|
309
|
-
collateral: {
|
|
310
|
-
...balances.collateral,
|
|
311
|
-
[addressMapping ? assetAddr : asset]: tokenInfo.balance.toString(),
|
|
312
|
-
},
|
|
313
|
-
debt: {
|
|
314
|
-
...balances.debt,
|
|
315
|
-
[addressMapping ? assetAddr : asset]: new Dec(tokenInfo.borrowsStable.toString()).add(tokenInfo.borrowsVariable.toString()).toString(),
|
|
316
|
-
},
|
|
317
|
-
};
|
|
318
|
-
});
|
|
319
|
-
|
|
273
|
+
const balances = await getAaveLikeBalances(provider, network, block, addressMapping, address, SPARK_V1(network), 'SparkView');
|
|
320
274
|
return balances;
|
|
321
275
|
};
|
|
322
276
|
|
package/src/types/common.ts
CHANGED
package/src/types/index.ts
CHANGED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { EthAddress, NetworkNumber } from './common';
|
|
2
|
+
|
|
3
|
+
export type LendingSummaryPosition = {
|
|
4
|
+
id: string;
|
|
5
|
+
protocol: string;
|
|
6
|
+
/** Estimated decimal USD values; null means unavailable, never a verified zero. */
|
|
7
|
+
suppliedUsd: string | null;
|
|
8
|
+
debtUsd: string | null;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type WalletLendingSummary = {
|
|
12
|
+
status: 'complete' | 'partial' | 'failed';
|
|
13
|
+
positions: LendingSummaryPosition[];
|
|
14
|
+
protocols: string[];
|
|
15
|
+
/** Sum of known supply values; check valuationComplete before ranking by value. */
|
|
16
|
+
suppliedUsd: string;
|
|
17
|
+
valuationComplete: boolean;
|
|
18
|
+
errors: string[];
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/** Resolve distinct token addresses to USD prices keyed by lowercase address.
|
|
22
|
+
* Native tokens use their wrapped address. Missing/invalid prices remain unavailable.
|
|
23
|
+
* Prices are current market estimates; balances may come from a historical/fork snapshot.
|
|
24
|
+
*/
|
|
25
|
+
export type LendingSummaryPriceResolver = (
|
|
26
|
+
network: NetworkNumber, tokens: EthAddress[], signal?: AbortSignal,
|
|
27
|
+
) => Promise<Record<string, string>>;
|
|
28
|
+
|
|
29
|
+
export type LendingSummaryOptions = {
|
|
30
|
+
resolvePrices: LendingSummaryPriceResolver;
|
|
31
|
+
signal?: AbortSignal;
|
|
32
|
+
/** Defaults to a snapshot of the provider's latest block. */
|
|
33
|
+
blockNumber?: bigint;
|
|
34
|
+
/** Use the smaller 2 KB calldata limit required by simulation providers. */
|
|
35
|
+
isSim?: boolean;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type WalletLendingSummaries = {
|
|
39
|
+
summaries: Record<string, WalletLendingSummary>;
|
|
40
|
+
rateLimited: boolean;
|
|
41
|
+
};
|