@defisaver/positions-sdk 2.1.121 → 2.1.122-shifter-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/aaveV4/index.d.ts +6 -0
- package/cjs/aaveV4/index.js +21 -1
- package/cjs/portfolio/discovery.d.ts +13 -0
- package/cjs/portfolio/discovery.js +93 -0
- package/cjs/portfolio/index.d.ts +1 -0
- package/cjs/portfolio/index.js +15 -0
- package/esm/aaveV4/index.d.ts +6 -0
- package/esm/aaveV4/index.js +19 -0
- package/esm/portfolio/discovery.d.ts +13 -0
- package/esm/portfolio/discovery.js +87 -0
- package/esm/portfolio/index.d.ts +1 -0
- package/esm/portfolio/index.js +1 -0
- package/package.json +2 -2
- package/src/aaveV4/index.ts +27 -0
- package/src/portfolio/discovery.ts +114 -0
- package/src/portfolio/index.ts +2 -0
package/cjs/aaveV4/index.d.ts
CHANGED
|
@@ -5,6 +5,12 @@ 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
|
+
/**
|
|
9
|
+
* Lightweight existence check for Loan Shifter / UI discovery.
|
|
10
|
+
* Reads only `getLoanData(spoke, user)` and returns whether any reserve has
|
|
11
|
+
* non-zero supplied or debt, avoiding full spoke/market data fetches.
|
|
12
|
+
*/
|
|
13
|
+
export declare const _getAaveV4AccountHasAnyBalance: (provider: Client, network: NetworkNumber, block: Blockish, address: EthAddress, spokeAddress: EthAddress) => Promise<boolean>;
|
|
8
14
|
export declare function getAaveV4AccountData(provider: EthereumProvider, network: NetworkNumber, marketData: AaveV4SpokeData, address: EthAddress, blockNumber?: 'latest' | number): Promise<any>;
|
|
9
15
|
export declare const _getAaveV4AccountBalances: (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, spokeAddress: EthAddress, spokeData?: AaveV4SpokeData) => Promise<PositionBalances>;
|
|
10
16
|
export declare const getAaveV4AccountBalances: (provider: EthereumProvider, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, spokeAddress: EthAddress, spokeData?: AaveV4SpokeData) => Promise<PositionBalances>;
|
package/cjs/aaveV4/index.js
CHANGED
|
@@ -45,7 +45,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
45
45
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
46
|
};
|
|
47
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
-
exports.getAaveV4AccountBalances = exports._getAaveV4AccountBalances = exports.getAaveV4MerkleCampaigns = exports.lend = void 0;
|
|
48
|
+
exports.getAaveV4AccountBalances = exports._getAaveV4AccountBalances = exports._getAaveV4AccountHasAnyBalance = exports.getAaveV4MerkleCampaigns = exports.lend = void 0;
|
|
49
49
|
exports._getAaveV4SpokeData = _getAaveV4SpokeData;
|
|
50
50
|
exports.getAaveV4SpokeData = getAaveV4SpokeData;
|
|
51
51
|
exports._getAaveV4AccountData = _getAaveV4AccountData;
|
|
@@ -280,6 +280,26 @@ function _getAaveV4AccountData(provider_1, network_1, spokeData_1, address_1) {
|
|
|
280
280
|
riskPremiumBps });
|
|
281
281
|
});
|
|
282
282
|
}
|
|
283
|
+
/**
|
|
284
|
+
* Lightweight existence check for Loan Shifter / UI discovery.
|
|
285
|
+
* Reads only `getLoanData(spoke, user)` and returns whether any reserve has
|
|
286
|
+
* non-zero supplied or debt, avoiding full spoke/market data fetches.
|
|
287
|
+
*/
|
|
288
|
+
const _getAaveV4AccountHasAnyBalance = (provider, network, block, address, spokeAddress) => __awaiter(void 0, void 0, void 0, function* () {
|
|
289
|
+
if (!address || !spokeAddress)
|
|
290
|
+
return false;
|
|
291
|
+
const blockNumber = block === 'latest' ? 'latest' : Number(block);
|
|
292
|
+
const viewContract = (0, contracts_1.AaveV4ViewContractViem)(provider, network, blockNumber);
|
|
293
|
+
const loanData = yield viewContract.read.getLoanData([spokeAddress, address]);
|
|
294
|
+
const reserves = (loanData === null || loanData === void 0 ? void 0 : loanData.reserves) || [];
|
|
295
|
+
return reserves.some((reserveAsset) => {
|
|
296
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
297
|
+
const suppliedRaw = (_d = (_c = (_b = (_a = reserveAsset === null || reserveAsset === void 0 ? void 0 : reserveAsset.supplied) === null || _a === void 0 ? void 0 : _a.toString) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : reserveAsset === null || reserveAsset === void 0 ? void 0 : reserveAsset.supplied) !== null && _d !== void 0 ? _d : '0';
|
|
298
|
+
const debtRaw = (_h = (_g = (_f = (_e = reserveAsset === null || reserveAsset === void 0 ? void 0 : reserveAsset.totalDebt) === null || _e === void 0 ? void 0 : _e.toString) === null || _f === void 0 ? void 0 : _f.call(_e)) !== null && _g !== void 0 ? _g : reserveAsset === null || reserveAsset === void 0 ? void 0 : reserveAsset.totalDebt) !== null && _h !== void 0 ? _h : '0';
|
|
299
|
+
return new decimal_js_1.default(suppliedRaw).gt(0) || new decimal_js_1.default(debtRaw).gt(0);
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
exports._getAaveV4AccountHasAnyBalance = _getAaveV4AccountHasAnyBalance;
|
|
283
303
|
function getAaveV4AccountData(provider_1, network_1, marketData_1, address_1) {
|
|
284
304
|
return __awaiter(this, arguments, void 0, function* (provider, network, marketData, address, blockNumber = 'latest') {
|
|
285
305
|
return _getAaveV4AccountData((0, viem_1.getViemProvider)(provider, network), network, marketData, address, blockNumber);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { EthAddress, EthereumProvider, NetworkNumber } from '../types/common';
|
|
2
|
+
/**
|
|
3
|
+
* Cheap "does this address have a position here" check across all money-market protocols,
|
|
4
|
+
* keyed by each market/spoke's `.value`. Built for UI flows (e.g. Loan Shifter) that need to
|
|
5
|
+
* know *which* markets to show, without paying for a full manage-data fetch of every market.
|
|
6
|
+
*
|
|
7
|
+
* Uses one shared, multicall-batched viem client (same pattern as getPortfolioData) so all
|
|
8
|
+
* per-market reads collapse into a handful of RPC round trips.
|
|
9
|
+
*
|
|
10
|
+
* Not covered: Maker, Liquity, Liquity V2, Fluid, Euler V2 — these already expose cheap,
|
|
11
|
+
* user-scoped discovery entry points elsewhere in the SDK (e.g. _getUserCdps, _getUserPositionsPortfolio).
|
|
12
|
+
*/
|
|
13
|
+
export declare function getUserPositionsExistence(provider: EthereumProvider, network: NetworkNumber, address: EthAddress, isSim?: boolean): Promise<Record<string, boolean>>;
|
|
@@ -0,0 +1,93 @@
|
|
|
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.getUserPositionsExistence = getUserPositionsExistence;
|
|
16
|
+
const decimal_js_1 = __importDefault(require("decimal.js"));
|
|
17
|
+
const common_1 = require("../types/common");
|
|
18
|
+
const viem_1 = require("../services/viem");
|
|
19
|
+
const markets_1 = require("../markets");
|
|
20
|
+
const types_1 = require("../types");
|
|
21
|
+
const aaveV4_1 = require("../aaveV4");
|
|
22
|
+
const compoundV2_1 = require("../compoundV2");
|
|
23
|
+
const compoundV3_1 = require("../compoundV3");
|
|
24
|
+
const curveUsd_1 = require("../curveUsd");
|
|
25
|
+
const llamaLend_1 = require("../llamaLend");
|
|
26
|
+
const morphoBlue_1 = require("../morphoBlue");
|
|
27
|
+
const contracts_1 = require("../contracts");
|
|
28
|
+
const hasAnyBalance = (balances) => ([balances.collateral, balances.debt].some((group) => Object.values(group || {}).some((amount) => new decimal_js_1.default(amount || '0').gt(0))));
|
|
29
|
+
/**
|
|
30
|
+
* Cheap "does this address have a position here" check across all money-market protocols,
|
|
31
|
+
* keyed by each market/spoke's `.value`. Built for UI flows (e.g. Loan Shifter) that need to
|
|
32
|
+
* know *which* markets to show, without paying for a full manage-data fetch of every market.
|
|
33
|
+
*
|
|
34
|
+
* Uses one shared, multicall-batched viem client (same pattern as getPortfolioData) so all
|
|
35
|
+
* per-market reads collapse into a handful of RPC round trips.
|
|
36
|
+
*
|
|
37
|
+
* Not covered: Maker, Liquity, Liquity V2, Fluid, Euler V2 — these already expose cheap,
|
|
38
|
+
* user-scoped discovery entry points elsewhere in the SDK (e.g. _getUserCdps, _getUserPositionsPortfolio).
|
|
39
|
+
*/
|
|
40
|
+
function getUserPositionsExistence(provider_1, network_1, address_1) {
|
|
41
|
+
return __awaiter(this, arguments, void 0, function* (provider, network, address, isSim = false) {
|
|
42
|
+
const existence = {};
|
|
43
|
+
if (!address)
|
|
44
|
+
return existence;
|
|
45
|
+
const client = (0, viem_1.getViemProvider)(provider, network, { batch: { multicall: { batchSize: isSim ? 500000 : 2500000 } } });
|
|
46
|
+
const block = 'latest';
|
|
47
|
+
const tasks = [];
|
|
48
|
+
const aaveV3Markets = [types_1.AaveVersions.AaveV2, types_1.AaveVersions.AaveV3, types_1.AaveVersions.AaveV3Lido, types_1.AaveVersions.AaveV3Etherfi]
|
|
49
|
+
.map((version) => (0, markets_1.AaveMarkets)(network)[version])
|
|
50
|
+
.filter((market) => market.chainIds.includes(network) && market.lendingPoolAddress);
|
|
51
|
+
const sparkMarkets = Object.values((0, markets_1.SparkMarkets)(network)).filter((market) => market.chainIds.includes(network));
|
|
52
|
+
[...aaveV3Markets, ...sparkMarkets].forEach((market) => {
|
|
53
|
+
if (!market.lendingPool)
|
|
54
|
+
return;
|
|
55
|
+
const lendingPoolContract = (0, contracts_1.createViemContractFromConfigFunc)(market.lendingPool, market.lendingPoolAddress)(client, network, block);
|
|
56
|
+
tasks.push(lendingPoolContract.read.getUserAccountData([address], (0, viem_1.setViemBlockNumber)(block))
|
|
57
|
+
.then(([totalCollateral, totalDebt]) => {
|
|
58
|
+
existence[market.value] = new decimal_js_1.default(totalCollateral.toString()).gt(0) || new decimal_js_1.default(totalDebt.toString()).gt(0);
|
|
59
|
+
})
|
|
60
|
+
.catch(() => { existence[market.value] = false; }));
|
|
61
|
+
});
|
|
62
|
+
const balanceTask = (key, getBalances) => getBalances()
|
|
63
|
+
.then((balances) => { existence[key] = hasAnyBalance(balances); })
|
|
64
|
+
.catch(() => { existence[key] = false; });
|
|
65
|
+
Object.values((0, markets_1.AaveV4Spokes)(network)).filter((spoke) => spoke.chainIds.includes(network)).forEach((spoke) => {
|
|
66
|
+
tasks.push((0, aaveV4_1._getAaveV4AccountHasAnyBalance)(client, network, block, address, spoke.address)
|
|
67
|
+
.then((hasAny) => { existence[spoke.value] = hasAny; })
|
|
68
|
+
.catch(() => { existence[spoke.value] = false; }));
|
|
69
|
+
});
|
|
70
|
+
const compoundV3Markets = Object.values((0, markets_1.CompoundMarkets)(network)).filter((market) => market.chainIds.includes(network) && market.value !== types_1.CompoundVersions.CompoundV2);
|
|
71
|
+
const compoundV2Markets = [types_1.CompoundVersions.CompoundV2].map((version) => (0, markets_1.CompoundMarkets)(network)[version]).filter((market) => market.chainIds.includes(network));
|
|
72
|
+
compoundV2Markets.forEach((market) => {
|
|
73
|
+
tasks.push(balanceTask(market.value, () => (0, compoundV2_1._getCompoundV2AccountBalances)(client, network, block, false, address)));
|
|
74
|
+
});
|
|
75
|
+
compoundV3Markets.forEach((market) => {
|
|
76
|
+
tasks.push(balanceTask(market.value, () => (0, compoundV3_1._getCompoundV3AccountBalances)(client, network, block, false, address, market.baseMarketAddress)));
|
|
77
|
+
});
|
|
78
|
+
if (network === common_1.NetworkNumber.Eth) {
|
|
79
|
+
Object.values((0, markets_1.CrvUsdMarkets)(network)).filter((market) => market.chainIds.includes(network)).forEach((market) => {
|
|
80
|
+
tasks.push(balanceTask(market.value, () => (0, curveUsd_1._getCrvUsdAccountBalances)(client, network, block, false, address, market.controllerAddress)));
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
const llamaLendMarkets = [common_1.NetworkNumber.Eth, common_1.NetworkNumber.Arb].includes(network) ? Object.values((0, markets_1.LlamaLendMarkets)(network)).filter((market) => market.chainIds.includes(network)) : [];
|
|
84
|
+
llamaLendMarkets.forEach((market) => {
|
|
85
|
+
tasks.push(balanceTask(market.value, () => (0, llamaLend_1._getLlamaLendAccountBalances)(client, network, block, false, address, market.controllerAddress)));
|
|
86
|
+
});
|
|
87
|
+
Object.values((0, markets_1.MorphoBlueMarkets)(network)).filter((market) => market.chainIds.includes(network)).forEach((market) => {
|
|
88
|
+
tasks.push(balanceTask(market.value, () => (0, morphoBlue_1._getMorphoBlueAccountBalances)(client, network, block, false, address, market)));
|
|
89
|
+
});
|
|
90
|
+
yield Promise.all(tasks);
|
|
91
|
+
return existence;
|
|
92
|
+
});
|
|
93
|
+
}
|
package/cjs/portfolio/index.d.ts
CHANGED
package/cjs/portfolio/index.js
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
17
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
18
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -592,3 +606,4 @@ function getPortfolioData(provider_1, network_1, defaultProvider_1, addresses_1)
|
|
|
592
606
|
};
|
|
593
607
|
});
|
|
594
608
|
}
|
|
609
|
+
__exportStar(require("./discovery"), exports);
|
package/esm/aaveV4/index.d.ts
CHANGED
|
@@ -5,6 +5,12 @@ 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
|
+
/**
|
|
9
|
+
* Lightweight existence check for Loan Shifter / UI discovery.
|
|
10
|
+
* Reads only `getLoanData(spoke, user)` and returns whether any reserve has
|
|
11
|
+
* non-zero supplied or debt, avoiding full spoke/market data fetches.
|
|
12
|
+
*/
|
|
13
|
+
export declare const _getAaveV4AccountHasAnyBalance: (provider: Client, network: NetworkNumber, block: Blockish, address: EthAddress, spokeAddress: EthAddress) => Promise<boolean>;
|
|
8
14
|
export declare function getAaveV4AccountData(provider: EthereumProvider, network: NetworkNumber, marketData: AaveV4SpokeData, address: EthAddress, blockNumber?: 'latest' | number): Promise<any>;
|
|
9
15
|
export declare const _getAaveV4AccountBalances: (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, spokeAddress: EthAddress, spokeData?: AaveV4SpokeData) => Promise<PositionBalances>;
|
|
10
16
|
export declare const getAaveV4AccountBalances: (provider: EthereumProvider, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, spokeAddress: EthAddress, spokeData?: AaveV4SpokeData) => Promise<PositionBalances>;
|
package/esm/aaveV4/index.js
CHANGED
|
@@ -235,6 +235,25 @@ export function _getAaveV4AccountData(provider_1, network_1, spokeData_1, addres
|
|
|
235
235
|
riskPremiumBps });
|
|
236
236
|
});
|
|
237
237
|
}
|
|
238
|
+
/**
|
|
239
|
+
* Lightweight existence check for Loan Shifter / UI discovery.
|
|
240
|
+
* Reads only `getLoanData(spoke, user)` and returns whether any reserve has
|
|
241
|
+
* non-zero supplied or debt, avoiding full spoke/market data fetches.
|
|
242
|
+
*/
|
|
243
|
+
export const _getAaveV4AccountHasAnyBalance = (provider, network, block, address, spokeAddress) => __awaiter(void 0, void 0, void 0, function* () {
|
|
244
|
+
if (!address || !spokeAddress)
|
|
245
|
+
return false;
|
|
246
|
+
const blockNumber = block === 'latest' ? 'latest' : Number(block);
|
|
247
|
+
const viewContract = AaveV4ViewContractViem(provider, network, blockNumber);
|
|
248
|
+
const loanData = yield viewContract.read.getLoanData([spokeAddress, address]);
|
|
249
|
+
const reserves = (loanData === null || loanData === void 0 ? void 0 : loanData.reserves) || [];
|
|
250
|
+
return reserves.some((reserveAsset) => {
|
|
251
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
252
|
+
const suppliedRaw = (_d = (_c = (_b = (_a = reserveAsset === null || reserveAsset === void 0 ? void 0 : reserveAsset.supplied) === null || _a === void 0 ? void 0 : _a.toString) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : reserveAsset === null || reserveAsset === void 0 ? void 0 : reserveAsset.supplied) !== null && _d !== void 0 ? _d : '0';
|
|
253
|
+
const debtRaw = (_h = (_g = (_f = (_e = reserveAsset === null || reserveAsset === void 0 ? void 0 : reserveAsset.totalDebt) === null || _e === void 0 ? void 0 : _e.toString) === null || _f === void 0 ? void 0 : _f.call(_e)) !== null && _g !== void 0 ? _g : reserveAsset === null || reserveAsset === void 0 ? void 0 : reserveAsset.totalDebt) !== null && _h !== void 0 ? _h : '0';
|
|
254
|
+
return new Dec(suppliedRaw).gt(0) || new Dec(debtRaw).gt(0);
|
|
255
|
+
});
|
|
256
|
+
});
|
|
238
257
|
export function getAaveV4AccountData(provider_1, network_1, marketData_1, address_1) {
|
|
239
258
|
return __awaiter(this, arguments, void 0, function* (provider, network, marketData, address, blockNumber = 'latest') {
|
|
240
259
|
return _getAaveV4AccountData(getViemProvider(provider, network), network, marketData, address, blockNumber);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { EthAddress, EthereumProvider, NetworkNumber } from '../types/common';
|
|
2
|
+
/**
|
|
3
|
+
* Cheap "does this address have a position here" check across all money-market protocols,
|
|
4
|
+
* keyed by each market/spoke's `.value`. Built for UI flows (e.g. Loan Shifter) that need to
|
|
5
|
+
* know *which* markets to show, without paying for a full manage-data fetch of every market.
|
|
6
|
+
*
|
|
7
|
+
* Uses one shared, multicall-batched viem client (same pattern as getPortfolioData) so all
|
|
8
|
+
* per-market reads collapse into a handful of RPC round trips.
|
|
9
|
+
*
|
|
10
|
+
* Not covered: Maker, Liquity, Liquity V2, Fluid, Euler V2 — these already expose cheap,
|
|
11
|
+
* user-scoped discovery entry points elsewhere in the SDK (e.g. _getUserCdps, _getUserPositionsPortfolio).
|
|
12
|
+
*/
|
|
13
|
+
export declare function getUserPositionsExistence(provider: EthereumProvider, network: NetworkNumber, address: EthAddress, isSim?: boolean): Promise<Record<string, boolean>>;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import Dec from 'decimal.js';
|
|
11
|
+
import { NetworkNumber, } from '../types/common';
|
|
12
|
+
import { getViemProvider, setViemBlockNumber } from '../services/viem';
|
|
13
|
+
import { AaveMarkets, AaveV4Spokes, CompoundMarkets, CrvUsdMarkets, LlamaLendMarkets, MorphoBlueMarkets, SparkMarkets, } from '../markets';
|
|
14
|
+
import { AaveVersions, CompoundVersions } from '../types';
|
|
15
|
+
import { _getAaveV4AccountHasAnyBalance } from '../aaveV4';
|
|
16
|
+
import { _getCompoundV2AccountBalances } from '../compoundV2';
|
|
17
|
+
import { _getCompoundV3AccountBalances } from '../compoundV3';
|
|
18
|
+
import { _getCrvUsdAccountBalances } from '../curveUsd';
|
|
19
|
+
import { _getLlamaLendAccountBalances } from '../llamaLend';
|
|
20
|
+
import { _getMorphoBlueAccountBalances } from '../morphoBlue';
|
|
21
|
+
import { createViemContractFromConfigFunc } from '../contracts';
|
|
22
|
+
const hasAnyBalance = (balances) => ([balances.collateral, balances.debt].some((group) => Object.values(group || {}).some((amount) => new Dec(amount || '0').gt(0))));
|
|
23
|
+
/**
|
|
24
|
+
* Cheap "does this address have a position here" check across all money-market protocols,
|
|
25
|
+
* keyed by each market/spoke's `.value`. Built for UI flows (e.g. Loan Shifter) that need to
|
|
26
|
+
* know *which* markets to show, without paying for a full manage-data fetch of every market.
|
|
27
|
+
*
|
|
28
|
+
* Uses one shared, multicall-batched viem client (same pattern as getPortfolioData) so all
|
|
29
|
+
* per-market reads collapse into a handful of RPC round trips.
|
|
30
|
+
*
|
|
31
|
+
* Not covered: Maker, Liquity, Liquity V2, Fluid, Euler V2 — these already expose cheap,
|
|
32
|
+
* user-scoped discovery entry points elsewhere in the SDK (e.g. _getUserCdps, _getUserPositionsPortfolio).
|
|
33
|
+
*/
|
|
34
|
+
export function getUserPositionsExistence(provider_1, network_1, address_1) {
|
|
35
|
+
return __awaiter(this, arguments, void 0, function* (provider, network, address, isSim = false) {
|
|
36
|
+
const existence = {};
|
|
37
|
+
if (!address)
|
|
38
|
+
return existence;
|
|
39
|
+
const client = getViemProvider(provider, network, { batch: { multicall: { batchSize: isSim ? 500000 : 2500000 } } });
|
|
40
|
+
const block = 'latest';
|
|
41
|
+
const tasks = [];
|
|
42
|
+
const aaveV3Markets = [AaveVersions.AaveV2, AaveVersions.AaveV3, AaveVersions.AaveV3Lido, AaveVersions.AaveV3Etherfi]
|
|
43
|
+
.map((version) => AaveMarkets(network)[version])
|
|
44
|
+
.filter((market) => market.chainIds.includes(network) && market.lendingPoolAddress);
|
|
45
|
+
const sparkMarkets = Object.values(SparkMarkets(network)).filter((market) => market.chainIds.includes(network));
|
|
46
|
+
[...aaveV3Markets, ...sparkMarkets].forEach((market) => {
|
|
47
|
+
if (!market.lendingPool)
|
|
48
|
+
return;
|
|
49
|
+
const lendingPoolContract = createViemContractFromConfigFunc(market.lendingPool, market.lendingPoolAddress)(client, network, block);
|
|
50
|
+
tasks.push(lendingPoolContract.read.getUserAccountData([address], setViemBlockNumber(block))
|
|
51
|
+
.then(([totalCollateral, totalDebt]) => {
|
|
52
|
+
existence[market.value] = new Dec(totalCollateral.toString()).gt(0) || new Dec(totalDebt.toString()).gt(0);
|
|
53
|
+
})
|
|
54
|
+
.catch(() => { existence[market.value] = false; }));
|
|
55
|
+
});
|
|
56
|
+
const balanceTask = (key, getBalances) => getBalances()
|
|
57
|
+
.then((balances) => { existence[key] = hasAnyBalance(balances); })
|
|
58
|
+
.catch(() => { existence[key] = false; });
|
|
59
|
+
Object.values(AaveV4Spokes(network)).filter((spoke) => spoke.chainIds.includes(network)).forEach((spoke) => {
|
|
60
|
+
tasks.push(_getAaveV4AccountHasAnyBalance(client, network, block, address, spoke.address)
|
|
61
|
+
.then((hasAny) => { existence[spoke.value] = hasAny; })
|
|
62
|
+
.catch(() => { existence[spoke.value] = false; }));
|
|
63
|
+
});
|
|
64
|
+
const compoundV3Markets = Object.values(CompoundMarkets(network)).filter((market) => market.chainIds.includes(network) && market.value !== CompoundVersions.CompoundV2);
|
|
65
|
+
const compoundV2Markets = [CompoundVersions.CompoundV2].map((version) => CompoundMarkets(network)[version]).filter((market) => market.chainIds.includes(network));
|
|
66
|
+
compoundV2Markets.forEach((market) => {
|
|
67
|
+
tasks.push(balanceTask(market.value, () => _getCompoundV2AccountBalances(client, network, block, false, address)));
|
|
68
|
+
});
|
|
69
|
+
compoundV3Markets.forEach((market) => {
|
|
70
|
+
tasks.push(balanceTask(market.value, () => _getCompoundV3AccountBalances(client, network, block, false, address, market.baseMarketAddress)));
|
|
71
|
+
});
|
|
72
|
+
if (network === NetworkNumber.Eth) {
|
|
73
|
+
Object.values(CrvUsdMarkets(network)).filter((market) => market.chainIds.includes(network)).forEach((market) => {
|
|
74
|
+
tasks.push(balanceTask(market.value, () => _getCrvUsdAccountBalances(client, network, block, false, address, market.controllerAddress)));
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
const llamaLendMarkets = [NetworkNumber.Eth, NetworkNumber.Arb].includes(network) ? Object.values(LlamaLendMarkets(network)).filter((market) => market.chainIds.includes(network)) : [];
|
|
78
|
+
llamaLendMarkets.forEach((market) => {
|
|
79
|
+
tasks.push(balanceTask(market.value, () => _getLlamaLendAccountBalances(client, network, block, false, address, market.controllerAddress)));
|
|
80
|
+
});
|
|
81
|
+
Object.values(MorphoBlueMarkets(network)).filter((market) => market.chainIds.includes(network)).forEach((market) => {
|
|
82
|
+
tasks.push(balanceTask(market.value, () => _getMorphoBlueAccountBalances(client, network, block, false, address, market)));
|
|
83
|
+
});
|
|
84
|
+
yield Promise.all(tasks);
|
|
85
|
+
return existence;
|
|
86
|
+
});
|
|
87
|
+
}
|
package/esm/portfolio/index.d.ts
CHANGED
package/esm/portfolio/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defisaver/positions-sdk",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.122-shifter-dev",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./cjs/index.js",
|
|
6
6
|
"module": "./esm/index.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"author": "",
|
|
22
22
|
"license": "ISC",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@defisaver/tokens": "^1.7.
|
|
24
|
+
"@defisaver/tokens": "^1.7.40",
|
|
25
25
|
"@types/lodash": "^4.17.15",
|
|
26
26
|
"@types/memoizee": "^0.4.12",
|
|
27
27
|
"decimal.js": "^10.6.0",
|
package/src/aaveV4/index.ts
CHANGED
|
@@ -257,6 +257,33 @@ export async function _getAaveV4AccountData(provider: Client, network: NetworkNu
|
|
|
257
257
|
};
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Lightweight existence check for Loan Shifter / UI discovery.
|
|
262
|
+
* Reads only `getLoanData(spoke, user)` and returns whether any reserve has
|
|
263
|
+
* non-zero supplied or debt, avoiding full spoke/market data fetches.
|
|
264
|
+
*/
|
|
265
|
+
export const _getAaveV4AccountHasAnyBalance = async (
|
|
266
|
+
provider: Client,
|
|
267
|
+
network: NetworkNumber,
|
|
268
|
+
block: Blockish,
|
|
269
|
+
address: EthAddress,
|
|
270
|
+
spokeAddress: EthAddress,
|
|
271
|
+
): Promise<boolean> => {
|
|
272
|
+
if (!address || !spokeAddress) return false;
|
|
273
|
+
|
|
274
|
+
const blockNumber = block === 'latest' ? 'latest' : Number(block);
|
|
275
|
+
const viewContract = AaveV4ViewContractViem(provider, network, blockNumber);
|
|
276
|
+
|
|
277
|
+
const loanData = await viewContract.read.getLoanData([spokeAddress, address]);
|
|
278
|
+
const reserves = loanData?.reserves || [];
|
|
279
|
+
|
|
280
|
+
return reserves.some((reserveAsset) => {
|
|
281
|
+
const suppliedRaw = reserveAsset?.supplied?.toString?.() ?? reserveAsset?.supplied ?? '0';
|
|
282
|
+
const debtRaw = reserveAsset?.totalDebt?.toString?.() ?? reserveAsset?.totalDebt ?? '0';
|
|
283
|
+
return new Dec(suppliedRaw).gt(0) || new Dec(debtRaw).gt(0);
|
|
284
|
+
});
|
|
285
|
+
};
|
|
286
|
+
|
|
260
287
|
export async function getAaveV4AccountData(provider: EthereumProvider, network: NetworkNumber, marketData: AaveV4SpokeData, address: EthAddress, blockNumber: 'latest' | number = 'latest'): Promise<any> {
|
|
261
288
|
return _getAaveV4AccountData(getViemProvider(provider, network), network, marketData, address, blockNumber);
|
|
262
289
|
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import Dec from 'decimal.js';
|
|
2
|
+
import {
|
|
3
|
+
Blockish, EthAddress, EthereumProvider, NetworkNumber, PositionBalances,
|
|
4
|
+
} from '../types/common';
|
|
5
|
+
import { getViemProvider, setViemBlockNumber } from '../services/viem';
|
|
6
|
+
import {
|
|
7
|
+
AaveMarkets,
|
|
8
|
+
AaveV4Spokes,
|
|
9
|
+
CompoundMarkets,
|
|
10
|
+
CrvUsdMarkets,
|
|
11
|
+
LlamaLendMarkets,
|
|
12
|
+
MorphoBlueMarkets,
|
|
13
|
+
SparkMarkets,
|
|
14
|
+
} from '../markets';
|
|
15
|
+
import { AaveVersions, CompoundVersions } from '../types';
|
|
16
|
+
import { _getAaveV4AccountHasAnyBalance } from '../aaveV4';
|
|
17
|
+
import { _getCompoundV2AccountBalances } from '../compoundV2';
|
|
18
|
+
import { _getCompoundV3AccountBalances } from '../compoundV3';
|
|
19
|
+
import { _getCrvUsdAccountBalances } from '../curveUsd';
|
|
20
|
+
import { _getLlamaLendAccountBalances } from '../llamaLend';
|
|
21
|
+
import { _getMorphoBlueAccountBalances } from '../morphoBlue';
|
|
22
|
+
import { createViemContractFromConfigFunc } from '../contracts';
|
|
23
|
+
|
|
24
|
+
const hasAnyBalance = (balances: PositionBalances): boolean => (
|
|
25
|
+
[balances.collateral, balances.debt].some(
|
|
26
|
+
(group) => Object.values(group || {}).some((amount) => new Dec((amount as string) || '0').gt(0)),
|
|
27
|
+
)
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Cheap "does this address have a position here" check across all money-market protocols,
|
|
32
|
+
* keyed by each market/spoke's `.value`. Built for UI flows (e.g. Loan Shifter) that need to
|
|
33
|
+
* know *which* markets to show, without paying for a full manage-data fetch of every market.
|
|
34
|
+
*
|
|
35
|
+
* Uses one shared, multicall-batched viem client (same pattern as getPortfolioData) so all
|
|
36
|
+
* per-market reads collapse into a handful of RPC round trips.
|
|
37
|
+
*
|
|
38
|
+
* Not covered: Maker, Liquity, Liquity V2, Fluid, Euler V2 — these already expose cheap,
|
|
39
|
+
* user-scoped discovery entry points elsewhere in the SDK (e.g. _getUserCdps, _getUserPositionsPortfolio).
|
|
40
|
+
*/
|
|
41
|
+
export async function getUserPositionsExistence(
|
|
42
|
+
provider: EthereumProvider,
|
|
43
|
+
network: NetworkNumber,
|
|
44
|
+
address: EthAddress,
|
|
45
|
+
isSim = false,
|
|
46
|
+
): Promise<Record<string, boolean>> {
|
|
47
|
+
const existence: Record<string, boolean> = {};
|
|
48
|
+
if (!address) return existence;
|
|
49
|
+
|
|
50
|
+
const client = getViemProvider(provider, network, { batch: { multicall: { batchSize: isSim ? 500_000 : 2_500_000 } } });
|
|
51
|
+
const block: Blockish = 'latest';
|
|
52
|
+
|
|
53
|
+
const tasks: Promise<void>[] = [];
|
|
54
|
+
|
|
55
|
+
const aaveV3Markets = [AaveVersions.AaveV2, AaveVersions.AaveV3, AaveVersions.AaveV3Lido, AaveVersions.AaveV3Etherfi]
|
|
56
|
+
.map((version) => AaveMarkets(network)[version])
|
|
57
|
+
.filter((market) => market.chainIds.includes(network) && market.lendingPoolAddress);
|
|
58
|
+
const sparkMarkets = Object.values(SparkMarkets(network)).filter((market) => market.chainIds.includes(network));
|
|
59
|
+
|
|
60
|
+
[...aaveV3Markets, ...sparkMarkets].forEach((market) => {
|
|
61
|
+
if (!market.lendingPool) return;
|
|
62
|
+
const lendingPoolContract = createViemContractFromConfigFunc(
|
|
63
|
+
market.lendingPool,
|
|
64
|
+
market.lendingPoolAddress as EthAddress,
|
|
65
|
+
)(client, network, block);
|
|
66
|
+
tasks.push(
|
|
67
|
+
lendingPoolContract.read.getUserAccountData([address], setViemBlockNumber(block))
|
|
68
|
+
.then(([totalCollateral, totalDebt]) => {
|
|
69
|
+
existence[market.value] = new Dec(totalCollateral.toString()).gt(0) || new Dec(totalDebt.toString()).gt(0);
|
|
70
|
+
})
|
|
71
|
+
.catch(() => { existence[market.value] = false; }),
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const balanceTask = (key: string, getBalances: () => Promise<PositionBalances>) => getBalances()
|
|
76
|
+
.then((balances) => { existence[key] = hasAnyBalance(balances); })
|
|
77
|
+
.catch(() => { existence[key] = false; });
|
|
78
|
+
|
|
79
|
+
Object.values(AaveV4Spokes(network)).filter((spoke) => spoke.chainIds.includes(network)).forEach((spoke) => {
|
|
80
|
+
tasks.push(
|
|
81
|
+
_getAaveV4AccountHasAnyBalance(client, network, block, address, spoke.address)
|
|
82
|
+
.then((hasAny) => { existence[spoke.value] = hasAny; })
|
|
83
|
+
.catch(() => { existence[spoke.value] = false; }),
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const compoundV3Markets = Object.values(CompoundMarkets(network)).filter((market) => market.chainIds.includes(network) && market.value !== CompoundVersions.CompoundV2);
|
|
88
|
+
const compoundV2Markets = [CompoundVersions.CompoundV2].map((version) => CompoundMarkets(network)[version]).filter((market) => market.chainIds.includes(network));
|
|
89
|
+
|
|
90
|
+
compoundV2Markets.forEach((market) => {
|
|
91
|
+
tasks.push(balanceTask(market.value, () => _getCompoundV2AccountBalances(client, network, block, false, address)));
|
|
92
|
+
});
|
|
93
|
+
compoundV3Markets.forEach((market) => {
|
|
94
|
+
tasks.push(balanceTask(market.value, () => _getCompoundV3AccountBalances(client, network, block, false, address, market.baseMarketAddress)));
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
if (network === NetworkNumber.Eth) {
|
|
98
|
+
Object.values(CrvUsdMarkets(network)).filter((market) => market.chainIds.includes(network)).forEach((market) => {
|
|
99
|
+
tasks.push(balanceTask(market.value, () => _getCrvUsdAccountBalances(client, network, block, false, address, market.controllerAddress)));
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const llamaLendMarkets = [NetworkNumber.Eth, NetworkNumber.Arb].includes(network) ? Object.values(LlamaLendMarkets(network)).filter((market) => market.chainIds.includes(network)) : [];
|
|
104
|
+
llamaLendMarkets.forEach((market) => {
|
|
105
|
+
tasks.push(balanceTask(market.value, () => _getLlamaLendAccountBalances(client, network, block, false, address, market.controllerAddress)));
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
Object.values(MorphoBlueMarkets(network)).filter((market) => market.chainIds.includes(network)).forEach((market) => {
|
|
109
|
+
tasks.push(balanceTask(market.value, () => _getMorphoBlueAccountBalances(client, network, block, false, address, market)));
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
await Promise.all(tasks);
|
|
113
|
+
return existence;
|
|
114
|
+
}
|