@defisaver/positions-sdk 2.1.109 → 2.1.111-merkl-auth-api-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/aaveV3/merkl.js +3 -2
- package/cjs/aaveV4/index.d.ts +3 -1
- package/cjs/aaveV4/index.js +41 -1
- package/cjs/aaveV4/merkl.js +3 -2
- package/cjs/claiming/aaveV3.js +6 -1
- package/cjs/helpers/aaveHelpers/index.d.ts +17 -0
- package/cjs/helpers/aaveHelpers/index.js +45 -1
- package/cjs/index.d.ts +1 -0
- package/cjs/index.js +4 -1
- package/cjs/markets/aaveV4/index.d.ts +1 -0
- package/cjs/markets/aaveV4/index.js +3 -1
- package/cjs/markets/index.d.ts +1 -1
- package/cjs/markets/index.js +2 -1
- package/cjs/services/merkl.d.ts +2 -0
- package/cjs/services/merkl.js +17 -0
- package/cjs/types/aave.d.ts +3 -0
- package/esm/aaveV3/merkl.js +4 -3
- package/esm/aaveV4/index.d.ts +3 -1
- package/esm/aaveV4/index.js +41 -3
- package/esm/aaveV4/merkl.js +4 -3
- package/esm/claiming/aaveV3.js +7 -2
- package/esm/helpers/aaveHelpers/index.d.ts +17 -0
- package/esm/helpers/aaveHelpers/index.js +43 -0
- package/esm/index.d.ts +1 -0
- package/esm/index.js +1 -0
- package/esm/markets/aaveV4/index.d.ts +1 -0
- package/esm/markets/aaveV4/index.js +1 -0
- package/esm/markets/index.d.ts +1 -1
- package/esm/markets/index.js +1 -1
- package/esm/services/merkl.d.ts +2 -0
- package/esm/services/merkl.js +12 -0
- package/esm/types/aave.d.ts +3 -0
- package/package.json +1 -1
- package/src/aaveV3/merkl.ts +4 -3
- package/src/aaveV4/index.ts +73 -3
- package/src/aaveV4/merkl.ts +4 -3
- package/src/claiming/aaveV3.ts +8 -3
- package/src/helpers/aaveHelpers/index.ts +60 -0
- package/src/index.ts +2 -0
- package/src/markets/aaveV4/index.ts +4 -0
- package/src/markets/index.ts +1 -1
- package/src/services/merkl.ts +14 -0
- package/src/types/aave.ts +4 -0
package/cjs/aaveV3/merkl.js
CHANGED
|
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.getMerkleCampaigns = exports.formatAaveAsset = exports.getAaveUnderlyingSymbol = void 0;
|
|
13
13
|
const moneymarket_1 = require("../moneymarket");
|
|
14
14
|
const utils_1 = require("../services/utils");
|
|
15
|
+
const merkl_1 = require("../services/merkl");
|
|
15
16
|
const types_1 = require("../types");
|
|
16
17
|
const getAaveUnderlyingSymbol = (_symbol = '') => {
|
|
17
18
|
let symbol = _symbol
|
|
@@ -40,8 +41,8 @@ const formatAaveAsset = (_symbol) => {
|
|
|
40
41
|
exports.formatAaveAsset = formatAaveAsset;
|
|
41
42
|
const getMerkleCampaigns = (chainId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
42
43
|
try {
|
|
43
|
-
const res = yield fetch(
|
|
44
|
-
signal: AbortSignal.timeout(utils_1.
|
|
44
|
+
const res = yield fetch(`${(0, merkl_1.getMerklApiUrl)()}/v4/opportunities?mainProtocolId=aave`, {
|
|
45
|
+
signal: AbortSignal.timeout(utils_1.LONGER_TIMEOUT),
|
|
45
46
|
});
|
|
46
47
|
if (!res.ok)
|
|
47
48
|
throw new Error('Failed to fetch Merkle campaigns');
|
package/cjs/aaveV4/index.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Client } from 'viem';
|
|
2
|
-
import { AaveV4AccountData, AaveV4SpokeData, AaveV4SpokeInfo, EthAddress, EthereumProvider, NetworkNumber } from '../types';
|
|
2
|
+
import { AaveV4AccountData, AaveV4SpokeData, AaveV4SpokeInfo, EthAddress, EthereumProvider, NetworkNumber, Blockish, PositionBalances } from '../types';
|
|
3
3
|
export * as lend from './lend';
|
|
4
4
|
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
8
|
export declare function getAaveV4AccountData(provider: EthereumProvider, network: NetworkNumber, marketData: AaveV4SpokeData, address: EthAddress, blockNumber?: 'latest' | number): Promise<any>;
|
|
9
|
+
export declare const _getAaveV4AccountBalances: (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, spokeAddress: EthAddress, spokeData?: AaveV4SpokeData) => Promise<PositionBalances>;
|
|
10
|
+
export declare const getAaveV4AccountBalances: (provider: EthereumProvider, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, spokeAddress: EthAddress, spokeData?: AaveV4SpokeData) => Promise<PositionBalances>;
|
|
9
11
|
export declare function getAaveV4UnderlyingFromReserveId(provider: EthereumProvider, network: NetworkNumber, spoke: EthAddress, reserveId: number): Promise<any>;
|
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.getAaveV4MerkleCampaigns = exports.lend = void 0;
|
|
48
|
+
exports.getAaveV4AccountBalances = exports._getAaveV4AccountBalances = exports.getAaveV4MerkleCampaigns = exports.lend = void 0;
|
|
49
49
|
exports._getAaveV4SpokeData = _getAaveV4SpokeData;
|
|
50
50
|
exports.getAaveV4SpokeData = getAaveV4SpokeData;
|
|
51
51
|
exports._getAaveV4AccountData = _getAaveV4AccountData;
|
|
@@ -285,6 +285,46 @@ function getAaveV4AccountData(provider_1, network_1, marketData_1, address_1) {
|
|
|
285
285
|
return _getAaveV4AccountData((0, viem_1.getViemProvider)(provider, network), network, marketData, address, blockNumber);
|
|
286
286
|
});
|
|
287
287
|
}
|
|
288
|
+
const _getAaveV4AccountBalances = (provider, network, block, addressMapping, address, spokeAddress, spokeData) => __awaiter(void 0, void 0, void 0, function* () {
|
|
289
|
+
const balances = {
|
|
290
|
+
collateral: {},
|
|
291
|
+
debt: {},
|
|
292
|
+
};
|
|
293
|
+
if (!address || !spokeAddress) {
|
|
294
|
+
return balances;
|
|
295
|
+
}
|
|
296
|
+
const blockNumber = block === 'latest' ? 'latest' : Number(block);
|
|
297
|
+
let resolvedSpokeData = spokeData;
|
|
298
|
+
if (!resolvedSpokeData) {
|
|
299
|
+
const spokeInfo = (0, aaveV4_1.findAaveV4SpokeByAddress)(network, spokeAddress);
|
|
300
|
+
if (!spokeInfo) {
|
|
301
|
+
return balances;
|
|
302
|
+
}
|
|
303
|
+
resolvedSpokeData = yield _getAaveV4SpokeData(provider, network, spokeInfo, blockNumber);
|
|
304
|
+
}
|
|
305
|
+
const accountData = yield _getAaveV4AccountData(provider, network, resolvedSpokeData, address, blockNumber);
|
|
306
|
+
const finalSpokeData = resolvedSpokeData;
|
|
307
|
+
Object.entries(accountData.usedAssets).forEach(([key, asset]) => {
|
|
308
|
+
const reserveData = finalSpokeData.assetsData[key];
|
|
309
|
+
if (!reserveData)
|
|
310
|
+
return;
|
|
311
|
+
const balanceKey = addressMapping
|
|
312
|
+
? (0, utils_1.wethToEthByAddress)(reserveData.underlying, network).toLowerCase()
|
|
313
|
+
: (0, utils_1.wethToEth)(asset.symbol);
|
|
314
|
+
if (asset.isSupplied && new decimal_js_1.default(asset.supplied || 0).gt(0)) {
|
|
315
|
+
balances.collateral[balanceKey] = (0, tokens_1.assetAmountInWei)(asset.supplied, asset.symbol);
|
|
316
|
+
}
|
|
317
|
+
if (asset.isBorrowed && new decimal_js_1.default(asset.borrowed || 0).gt(0)) {
|
|
318
|
+
balances.debt[balanceKey] = (0, tokens_1.assetAmountInWei)(asset.borrowed, asset.symbol);
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
return balances;
|
|
322
|
+
});
|
|
323
|
+
exports._getAaveV4AccountBalances = _getAaveV4AccountBalances;
|
|
324
|
+
const getAaveV4AccountBalances = (provider, network, block, addressMapping, address, spokeAddress, spokeData) => __awaiter(void 0, void 0, void 0, function* () {
|
|
325
|
+
return (0, exports._getAaveV4AccountBalances)((0, viem_1.getViemProvider)(provider, network), network, block, addressMapping, address, spokeAddress, spokeData);
|
|
326
|
+
});
|
|
327
|
+
exports.getAaveV4AccountBalances = getAaveV4AccountBalances;
|
|
288
328
|
const _getAaveV4UnderlyingFromReserveId = (provider, network, spoke, reserveId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
289
329
|
const viewContract = (0, contracts_1.AaveV4ViewContractViem)(provider, network);
|
|
290
330
|
const reserveData = yield viewContract.read.getReserveData([spoke, BigInt(reserveId)]);
|
package/cjs/aaveV4/merkl.js
CHANGED
|
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.attachAaveV4MerklIncentives = exports.getAaveV4MerkleCampaigns = void 0;
|
|
13
13
|
const moneymarket_1 = require("../moneymarket");
|
|
14
14
|
const utils_1 = require("../services/utils");
|
|
15
|
+
const merkl_1 = require("../services/merkl");
|
|
15
16
|
const types_1 = require("../types");
|
|
16
17
|
/**
|
|
17
18
|
* Merkl tags Aave V4 reward campaigns by scope via the `type` field:
|
|
@@ -34,8 +35,8 @@ const buildIncentive = (opportunity) => {
|
|
|
34
35
|
const getAaveV4MerkleCampaigns = (chainId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
35
36
|
const result = { hub: {}, spoke: {} };
|
|
36
37
|
try {
|
|
37
|
-
const res = yield fetch(
|
|
38
|
-
signal: AbortSignal.timeout(utils_1.
|
|
38
|
+
const res = yield fetch(`${(0, merkl_1.getMerklApiUrl)()}/v4/opportunities?mainProtocolId=aave`, {
|
|
39
|
+
signal: AbortSignal.timeout(utils_1.LONGER_TIMEOUT),
|
|
39
40
|
});
|
|
40
41
|
if (!res.ok)
|
|
41
42
|
throw new Error('Failed to fetch Aave V4 Merkle campaigns');
|
package/cjs/claiming/aaveV3.js
CHANGED
|
@@ -19,6 +19,7 @@ const claiming_1 = require("../types/claiming");
|
|
|
19
19
|
const contracts_1 = require("../contracts");
|
|
20
20
|
const utils_1 = require("../services/utils");
|
|
21
21
|
const aaveHelpers_1 = require("../helpers/aaveHelpers");
|
|
22
|
+
const merkl_1 = require("../services/merkl");
|
|
22
23
|
const mapAaveRewardsToClaimableTokens = (aaveRewards, marketAddress, walletAddress) => aaveRewards.map(reward => ({
|
|
23
24
|
symbol: reward.symbol,
|
|
24
25
|
amount: reward.amount,
|
|
@@ -99,7 +100,7 @@ function getMeritUnclaimedRewards(account, network) {
|
|
|
99
100
|
return __awaiter(this, void 0, void 0, function* () {
|
|
100
101
|
let data;
|
|
101
102
|
try {
|
|
102
|
-
const res = yield fetch(
|
|
103
|
+
const res = yield fetch(`${(0, merkl_1.getMerklApiUrl)()}/v4/users/${account}/rewards?chainId=${network}`, { signal: AbortSignal.timeout(utils_1.LONGER_TIMEOUT) });
|
|
103
104
|
data = yield res.json();
|
|
104
105
|
}
|
|
105
106
|
catch (error) {
|
|
@@ -107,6 +108,10 @@ function getMeritUnclaimedRewards(account, network) {
|
|
|
107
108
|
data = [];
|
|
108
109
|
}
|
|
109
110
|
const claimableTokens = [];
|
|
111
|
+
// Merkl (or our proxy, on a non-2xx) can return a non-array error body; `fetch` doesn't throw on
|
|
112
|
+
// HTTP errors, so guard before iterating. Mirrors the app-side getMeritUnclaimedRewards.
|
|
113
|
+
if (!Array.isArray(data))
|
|
114
|
+
return claimableTokens;
|
|
110
115
|
data.forEach((item) => {
|
|
111
116
|
item.rewards.forEach(reward => {
|
|
112
117
|
const { token, amount, claimed, proofs, } = reward;
|
|
@@ -30,6 +30,23 @@ export declare const aaveAnyGetEmodeMutableProps: ({ eModeCategory, eModeCategor
|
|
|
30
30
|
liquidationRatio: any;
|
|
31
31
|
collateralFactor: any;
|
|
32
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* @description Per-asset effective LTV and liquidation threshold (LLTV) for the user, eMode-aware.
|
|
35
|
+
* Mirrors AaveV3View._getUserReserveLtvAndLltv: an asset in the active eMode's ltv-zero set has
|
|
36
|
+
* ltv 0 but KEEPS the eMode liquidation threshold (liquidations only consider LLTV). The returned
|
|
37
|
+
* `ltv` is identical to aaveAnyGetEmodeMutableProps().collateralFactor in every branch, so a ratio
|
|
38
|
+
* built on this matches the regular safety ratio whenever no collateral is LTV-0.
|
|
39
|
+
*
|
|
40
|
+
* Intentionally NOT merged with aaveAnyGetEmodeMutableProps (which it otherwise duplicates): the two
|
|
41
|
+
* differ only for an eMode ltv-zero asset — that helper returns liquidationRatio '0', whereas this one
|
|
42
|
+
* keeps the eMode liquidation threshold (to match the contract). aaveAnyGetEmodeMutableProps also feeds
|
|
43
|
+
* liquidationLimitUsd, so unifying them would change healthRatio / liqRatio / liquidationPrice for
|
|
44
|
+
* eMode-ltv-zero positions — to be done as a separate, validated follow-up PR.
|
|
45
|
+
*/
|
|
46
|
+
export declare const aaveAnyGetUserReserveLtvAndLltv: ({ eModeCategory, eModeCategoriesData, assetsData, }: AaveHelperCommon, _asset: string) => {
|
|
47
|
+
ltv: string;
|
|
48
|
+
lltv: string;
|
|
49
|
+
};
|
|
33
50
|
export declare const aaveAnyGetAggregatedPositionData: ({ usedAssets, eModeCategory, assetsData, selectedMarket, network, ...rest }: AaveHelperCommon) => AaveV3AggregatedPositionData;
|
|
34
51
|
export declare const getApyAfterValuesEstimation: (selectedMarket: AaveMarketInfo, actions: [{
|
|
35
52
|
action: string;
|
|
@@ -23,7 +23,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
23
23
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.getAaveUnderlyingSymbol = exports.getApyAfterValuesEstimation = exports.aaveAnyGetAggregatedPositionData = exports.aaveAnyGetEmodeMutableProps = exports.aaveAnyGetSuppliableAsCollAssets = exports.aaveAnyGetSuppliableAssets = exports.aaveAnyGetCollSuppliedAssets = exports.aaveV3IsInSiloedMode = exports.aaveV3IsInIsolationMode = exports.isAaveV3 = exports.isAaveV2 = exports.AAVE_V3_MARKETS = void 0;
|
|
26
|
+
exports.getAaveUnderlyingSymbol = exports.getApyAfterValuesEstimation = exports.aaveAnyGetAggregatedPositionData = exports.aaveAnyGetUserReserveLtvAndLltv = exports.aaveAnyGetEmodeMutableProps = exports.aaveAnyGetSuppliableAsCollAssets = exports.aaveAnyGetSuppliableAssets = exports.aaveAnyGetCollSuppliedAssets = exports.aaveV3IsInSiloedMode = exports.aaveV3IsInIsolationMode = exports.isAaveV3 = exports.isAaveV2 = exports.AAVE_V3_MARKETS = void 0;
|
|
27
27
|
const decimal_js_1 = __importDefault(require("decimal.js"));
|
|
28
28
|
const tokens_1 = require("@defisaver/tokens");
|
|
29
29
|
const types_1 = require("../../types");
|
|
@@ -83,6 +83,39 @@ const aaveAnyGetEmodeMutableProps = ({ eModeCategory, eModeCategoriesData, asset
|
|
|
83
83
|
return ({ liquidationRatio, collateralFactor });
|
|
84
84
|
};
|
|
85
85
|
exports.aaveAnyGetEmodeMutableProps = aaveAnyGetEmodeMutableProps;
|
|
86
|
+
/**
|
|
87
|
+
* @description Offset subtracted from the liquidation threshold (LLTV) when crediting LTV-0 collateral
|
|
88
|
+
* in the safety-ratio fallback. Matches AaveV3View.getSafetyRatioWithLtvZeroFallback ('LLTV - 5%').
|
|
89
|
+
* Values are fractions (e.g. 0.8), so 5% === 0.05.
|
|
90
|
+
*/
|
|
91
|
+
const LTV_ZERO_FALLBACK_LLTV_OFFSET = '0.05';
|
|
92
|
+
/**
|
|
93
|
+
* @description Per-asset effective LTV and liquidation threshold (LLTV) for the user, eMode-aware.
|
|
94
|
+
* Mirrors AaveV3View._getUserReserveLtvAndLltv: an asset in the active eMode's ltv-zero set has
|
|
95
|
+
* ltv 0 but KEEPS the eMode liquidation threshold (liquidations only consider LLTV). The returned
|
|
96
|
+
* `ltv` is identical to aaveAnyGetEmodeMutableProps().collateralFactor in every branch, so a ratio
|
|
97
|
+
* built on this matches the regular safety ratio whenever no collateral is LTV-0.
|
|
98
|
+
*
|
|
99
|
+
* Intentionally NOT merged with aaveAnyGetEmodeMutableProps (which it otherwise duplicates): the two
|
|
100
|
+
* differ only for an eMode ltv-zero asset — that helper returns liquidationRatio '0', whereas this one
|
|
101
|
+
* keeps the eMode liquidation threshold (to match the contract). aaveAnyGetEmodeMutableProps also feeds
|
|
102
|
+
* liquidationLimitUsd, so unifying them would change healthRatio / liqRatio / liquidationPrice for
|
|
103
|
+
* eMode-ltv-zero positions — to be done as a separate, validated follow-up PR.
|
|
104
|
+
*/
|
|
105
|
+
const aaveAnyGetUserReserveLtvAndLltv = ({ eModeCategory, eModeCategoriesData, assetsData, }, _asset) => {
|
|
106
|
+
const asset = (0, utils_1.getNativeAssetFromWrapped)(_asset);
|
|
107
|
+
const assetData = assetsData[asset];
|
|
108
|
+
const eModeCategoryData = eModeCategoriesData === null || eModeCategoriesData === void 0 ? void 0 : eModeCategoriesData[eModeCategory];
|
|
109
|
+
if (eModeCategory === 0
|
|
110
|
+
|| !eModeCategoryData
|
|
111
|
+
|| !eModeCategoryData.collateralAssets.includes(asset)
|
|
112
|
+
|| new decimal_js_1.default(eModeCategoryData.collateralFactor || 0).eq(0)) {
|
|
113
|
+
return { ltv: assetData.collateralFactor, lltv: assetData.liquidationRatio };
|
|
114
|
+
}
|
|
115
|
+
const ltv = eModeCategoryData.ltvZeroAssets.includes(asset) ? '0' : eModeCategoryData.collateralFactor;
|
|
116
|
+
return { ltv, lltv: eModeCategoryData.liquidationRatio };
|
|
117
|
+
};
|
|
118
|
+
exports.aaveAnyGetUserReserveLtvAndLltv = aaveAnyGetUserReserveLtvAndLltv;
|
|
86
119
|
const aaveAnyGetAggregatedPositionData = (_a) => {
|
|
87
120
|
var { usedAssets, eModeCategory, assetsData, selectedMarket, network } = _a, rest = __rest(_a, ["usedAssets", "eModeCategory", "assetsData", "selectedMarket", "network"]);
|
|
88
121
|
const data = Object.assign({ usedAssets, eModeCategory, assetsData, selectedMarket, network }, rest);
|
|
@@ -96,6 +129,17 @@ const aaveAnyGetAggregatedPositionData = (_a) => {
|
|
|
96
129
|
payload.leftToBorrowUsd = leftToBorrowUsd.lte('0') ? '0' : leftToBorrowUsd.toString();
|
|
97
130
|
payload.ratio = +payload.suppliedUsd ? new decimal_js_1.default(payload.borrowLimitUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
|
|
98
131
|
payload.collRatio = +payload.suppliedUsd ? new decimal_js_1.default(payload.suppliedCollateralUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
|
|
132
|
+
// Safety ratio as evaluated by the automation bots: LTV-0 collateral is credited at (LLTV - 5%)
|
|
133
|
+
// instead of 0 (AaveV3View.getSafetyRatioWithLtvZeroFallback). Equals `ratio` when no collateral
|
|
134
|
+
// is LTV-0. Computed off-chain here so it is available for after-value simulations too.
|
|
135
|
+
payload.borrowLimitWithLtvZeroFallbackUsd = (0, moneymarket_1.getAssetsTotal)(usedAssets, ({ isSupplied, collateral }) => isSupplied && collateral, ({ symbol, suppliedUsd }) => {
|
|
136
|
+
const { ltv, lltv } = (0, exports.aaveAnyGetUserReserveLtvAndLltv)(data, symbol);
|
|
137
|
+
const effectiveLtv = new decimal_js_1.default(ltv).eq(0)
|
|
138
|
+
? decimal_js_1.default.max(0, new decimal_js_1.default(lltv).sub(LTV_ZERO_FALLBACK_LLTV_OFFSET))
|
|
139
|
+
: new decimal_js_1.default(ltv);
|
|
140
|
+
return new decimal_js_1.default(suppliedUsd).mul(effectiveLtv);
|
|
141
|
+
});
|
|
142
|
+
payload.safetyRatioWithLtvZeroFallback = +payload.suppliedUsd ? new decimal_js_1.default(payload.borrowLimitWithLtvZeroFallbackUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
|
|
99
143
|
payload.liqRatio = new decimal_js_1.default(payload.borrowLimitUsd).div(payload.liquidationLimitUsd).toString();
|
|
100
144
|
payload.liqPercent = new decimal_js_1.default(payload.borrowLimitUsd).div(payload.liquidationLimitUsd).mul(100).toString();
|
|
101
145
|
const { leveragedType, leveragedAsset } = (0, moneymarket_1.isLeveragedPos)(usedAssets);
|
package/cjs/index.d.ts
CHANGED
|
@@ -22,4 +22,5 @@ import * as portfolio from './portfolio';
|
|
|
22
22
|
import * as claiming from './claiming';
|
|
23
23
|
import * as savings from './savings';
|
|
24
24
|
export * from './types';
|
|
25
|
+
export { getMerklApiUrl, setMerklApiUrl } from './services/merkl';
|
|
25
26
|
export { aaveV2, aaveV3, aaveV4, compoundV2, compoundV3, spark, curveUsd, liquity, liquityV2, maker, exchange, staking, moneymarket, markets, helpers, morphoBlue, llamaLend, eulerV2, fluid, portfolio, claiming, savings, };
|
package/cjs/index.js
CHANGED
|
@@ -36,7 +36,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
36
36
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.savings = exports.claiming = exports.portfolio = exports.fluid = exports.eulerV2 = exports.llamaLend = exports.morphoBlue = exports.helpers = exports.markets = exports.moneymarket = exports.staking = exports.exchange = exports.maker = exports.liquityV2 = exports.liquity = exports.curveUsd = exports.spark = exports.compoundV3 = exports.compoundV2 = exports.aaveV4 = exports.aaveV3 = exports.aaveV2 = void 0;
|
|
39
|
+
exports.savings = exports.claiming = exports.portfolio = exports.fluid = exports.eulerV2 = exports.llamaLend = exports.morphoBlue = exports.helpers = exports.markets = exports.moneymarket = exports.staking = exports.exchange = exports.maker = exports.liquityV2 = exports.liquity = exports.curveUsd = exports.spark = exports.compoundV3 = exports.compoundV2 = exports.aaveV4 = exports.aaveV3 = exports.aaveV2 = exports.setMerklApiUrl = exports.getMerklApiUrl = void 0;
|
|
40
40
|
require("./setup");
|
|
41
41
|
const fluid = __importStar(require("./fluid"));
|
|
42
42
|
exports.fluid = fluid;
|
|
@@ -83,3 +83,6 @@ exports.claiming = claiming;
|
|
|
83
83
|
const savings = __importStar(require("./savings"));
|
|
84
84
|
exports.savings = savings;
|
|
85
85
|
__exportStar(require("./types"), exports);
|
|
86
|
+
var merkl_1 = require("./services/merkl");
|
|
87
|
+
Object.defineProperty(exports, "getMerklApiUrl", { enumerable: true, get: function () { return merkl_1.getMerklApiUrl; } });
|
|
88
|
+
Object.defineProperty(exports, "setMerklApiUrl", { enumerable: true, get: function () { return merkl_1.setMerklApiUrl; } });
|
|
@@ -32,3 +32,4 @@ export declare const AaveV4Spokes: (networkId: NetworkNumber) => {
|
|
|
32
32
|
readonly aave_v4_main_spoke: AaveV4SpokeInfo;
|
|
33
33
|
};
|
|
34
34
|
export declare const getAaveV4SpokeTypeInfo: (type: AaveV4SpokesType, network?: NetworkNumber) => AaveV4SpokeInfo;
|
|
35
|
+
export declare const findAaveV4SpokeByAddress: (networkId: NetworkNumber, address: string) => AaveV4SpokeInfo | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getAaveV4SpokeTypeInfo = exports.AaveV4Spokes = exports.AAVE_V4_MAIN_SPOKE = exports.AAVE_V4_LOMBARD_BTC_SPOKE = exports.AAVE_V4_LIDO_SPOKE = exports.AAVE_V4_KELP_SPOKE = exports.AAVE_V4_GOLD_SPOKE = exports.AAVE_V4_FOREX_SPOKE = exports.AAVE_V4_ETHERFI_SPOKE = exports.AAVE_V4_ETHENA_ECOSYSTEM_SPOKE = exports.AAVE_V4_ETHENA_CORRELATED_SPOKE = exports.AAVE_V4_BLUECHIP_SPOKE = exports.getAaveV4HubByAddress = exports.getAaveV4HubTypeInfo = exports.AaveV4Hubs = exports.AAVE_V4_PRIME_HUB = exports.AAVE_V4_PLUS_HUB = exports.AAVE_V4_CORE_HUB = void 0;
|
|
3
|
+
exports.findAaveV4SpokeByAddress = exports.getAaveV4SpokeTypeInfo = exports.AaveV4Spokes = exports.AAVE_V4_MAIN_SPOKE = exports.AAVE_V4_LOMBARD_BTC_SPOKE = exports.AAVE_V4_LIDO_SPOKE = exports.AAVE_V4_KELP_SPOKE = exports.AAVE_V4_GOLD_SPOKE = exports.AAVE_V4_FOREX_SPOKE = exports.AAVE_V4_ETHERFI_SPOKE = exports.AAVE_V4_ETHENA_ECOSYSTEM_SPOKE = exports.AAVE_V4_ETHENA_CORRELATED_SPOKE = exports.AAVE_V4_BLUECHIP_SPOKE = exports.getAaveV4HubByAddress = exports.getAaveV4HubTypeInfo = exports.AaveV4Hubs = exports.AAVE_V4_PRIME_HUB = exports.AAVE_V4_PLUS_HUB = exports.AAVE_V4_CORE_HUB = void 0;
|
|
4
4
|
const types_1 = require("../../types");
|
|
5
5
|
// HUBS
|
|
6
6
|
const AAVE_V4_CORE_HUB = (networkId) => ({
|
|
@@ -180,3 +180,5 @@ const AaveV4Spokes = (networkId) => ({
|
|
|
180
180
|
exports.AaveV4Spokes = AaveV4Spokes;
|
|
181
181
|
const getAaveV4SpokeTypeInfo = (type, network) => (Object.assign({}, (0, exports.AaveV4Spokes)(network !== null && network !== void 0 ? network : types_1.NetworkNumber.Eth))[type]);
|
|
182
182
|
exports.getAaveV4SpokeTypeInfo = getAaveV4SpokeTypeInfo;
|
|
183
|
+
const findAaveV4SpokeByAddress = (networkId, address) => Object.values((0, exports.AaveV4Spokes)(networkId)).find(spoke => spoke.address.toLowerCase() === address.toLowerCase());
|
|
184
|
+
exports.findAaveV4SpokeByAddress = findAaveV4SpokeByAddress;
|
package/cjs/markets/index.d.ts
CHANGED
|
@@ -7,4 +7,4 @@ export { LlamaLendMarkets } from './llamaLend';
|
|
|
7
7
|
export { LiquityV2Markets, findLiquityV2MarketByAddress } from './liquityV2';
|
|
8
8
|
export { EulerV2Markets } from './euler';
|
|
9
9
|
export { FluidMarkets, getFluidVersionsDataForNetwork, getFluidMarketInfoById, getFTokenAddress, getFluidMarketInfoByAddress, } from './fluid';
|
|
10
|
-
export { AaveV4Spokes } from './aaveV4';
|
|
10
|
+
export { AaveV4Spokes, findAaveV4SpokeByAddress } from './aaveV4';
|
package/cjs/markets/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AaveV4Spokes = exports.getFluidMarketInfoByAddress = exports.getFTokenAddress = exports.getFluidMarketInfoById = exports.getFluidVersionsDataForNetwork = exports.FluidMarkets = exports.EulerV2Markets = exports.findLiquityV2MarketByAddress = exports.LiquityV2Markets = exports.LlamaLendMarkets = exports.findMorphoBlueMarket = exports.MorphoBlueMarkets = exports.CrvUsdMarkets = exports.SparkMarkets = exports.v3USDTCollAssets = exports.v3USDCeCollAssets = exports.v3USDCCollAssets = exports.v3USDbCCollAssets = exports.v3ETHCollAssets = exports.compoundV2CollateralAssets = exports.CompoundMarkets = exports.getAaveV3MarketByMarketAddress = exports.aaveV3AssetsDefaultMarket = exports.aaveV2AssetsDefaultMarket = exports.aaveV1AssetsDefaultMarket = exports.AaveMarkets = void 0;
|
|
3
|
+
exports.findAaveV4SpokeByAddress = exports.AaveV4Spokes = exports.getFluidMarketInfoByAddress = exports.getFTokenAddress = exports.getFluidMarketInfoById = exports.getFluidVersionsDataForNetwork = exports.FluidMarkets = exports.EulerV2Markets = exports.findLiquityV2MarketByAddress = exports.LiquityV2Markets = exports.LlamaLendMarkets = exports.findMorphoBlueMarket = exports.MorphoBlueMarkets = exports.CrvUsdMarkets = exports.SparkMarkets = exports.v3USDTCollAssets = exports.v3USDCeCollAssets = exports.v3USDCCollAssets = exports.v3USDbCCollAssets = exports.v3ETHCollAssets = exports.compoundV2CollateralAssets = exports.CompoundMarkets = exports.getAaveV3MarketByMarketAddress = exports.aaveV3AssetsDefaultMarket = exports.aaveV2AssetsDefaultMarket = exports.aaveV1AssetsDefaultMarket = exports.AaveMarkets = void 0;
|
|
4
4
|
var aave_1 = require("./aave");
|
|
5
5
|
Object.defineProperty(exports, "AaveMarkets", { enumerable: true, get: function () { return aave_1.AaveMarkets; } });
|
|
6
6
|
Object.defineProperty(exports, "aaveV1AssetsDefaultMarket", { enumerable: true, get: function () { return aave_1.aaveV1AssetsDefaultMarket; } });
|
|
@@ -37,3 +37,4 @@ Object.defineProperty(exports, "getFTokenAddress", { enumerable: true, get: func
|
|
|
37
37
|
Object.defineProperty(exports, "getFluidMarketInfoByAddress", { enumerable: true, get: function () { return fluid_1.getFluidMarketInfoByAddress; } });
|
|
38
38
|
var aaveV4_1 = require("./aaveV4");
|
|
39
39
|
Object.defineProperty(exports, "AaveV4Spokes", { enumerable: true, get: function () { return aaveV4_1.AaveV4Spokes; } });
|
|
40
|
+
Object.defineProperty(exports, "findAaveV4SpokeByAddress", { enumerable: true, get: function () { return aaveV4_1.findAaveV4SpokeByAddress; } });
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setMerklApiUrl = exports.getMerklApiUrl = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Configurable base URL for the Merkl API (https://developers.merkl.xyz).
|
|
6
|
+
*
|
|
7
|
+
* Defaults to Merkl's public host. Consumers can override it via `setMerklApiUrl` — e.g. to route
|
|
8
|
+
* requests through their own backend proxy that attaches a Merkl API key (the key must stay
|
|
9
|
+
* server-side, and a proxy also avoids browser CORS limits on the public host).
|
|
10
|
+
*/
|
|
11
|
+
let merklApiUrl = 'https://api.merkl.xyz';
|
|
12
|
+
const getMerklApiUrl = () => merklApiUrl;
|
|
13
|
+
exports.getMerklApiUrl = getMerklApiUrl;
|
|
14
|
+
const setMerklApiUrl = (url) => {
|
|
15
|
+
merklApiUrl = url.replace(/\/+$/, '');
|
|
16
|
+
};
|
|
17
|
+
exports.setMerklApiUrl = setMerklApiUrl;
|
package/cjs/types/aave.d.ts
CHANGED
|
@@ -125,6 +125,7 @@ export interface AavePositionData extends MMPositionData {
|
|
|
125
125
|
ratio: string;
|
|
126
126
|
minRatio: string;
|
|
127
127
|
collRatio: string;
|
|
128
|
+
safetyRatioWithLtvZeroFallback?: string;
|
|
128
129
|
suppliedUsd: string;
|
|
129
130
|
borrowedUsd: string;
|
|
130
131
|
borrowLimitUsd: string;
|
|
@@ -156,6 +157,8 @@ export interface AaveV3AggregatedPositionData {
|
|
|
156
157
|
leftToBorrowUsd: string;
|
|
157
158
|
ratio: string;
|
|
158
159
|
collRatio: string;
|
|
160
|
+
borrowLimitWithLtvZeroFallbackUsd: string;
|
|
161
|
+
safetyRatioWithLtvZeroFallback: string;
|
|
159
162
|
netApy: string;
|
|
160
163
|
incentiveUsd: string;
|
|
161
164
|
totalInterestUsd: string;
|
package/esm/aaveV3/merkl.js
CHANGED
|
@@ -8,7 +8,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { aprToApy } from '../moneymarket';
|
|
11
|
-
import {
|
|
11
|
+
import { LONGER_TIMEOUT, wethToEth } from '../services/utils';
|
|
12
|
+
import { getMerklApiUrl } from '../services/merkl';
|
|
12
13
|
import { OpportunityAction, OpportunityStatus, } from '../types';
|
|
13
14
|
export const getAaveUnderlyingSymbol = (_symbol = '') => {
|
|
14
15
|
let symbol = _symbol
|
|
@@ -35,8 +36,8 @@ export const formatAaveAsset = (_symbol) => {
|
|
|
35
36
|
};
|
|
36
37
|
export const getMerkleCampaigns = (chainId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
37
38
|
try {
|
|
38
|
-
const res = yield fetch(
|
|
39
|
-
signal: AbortSignal.timeout(
|
|
39
|
+
const res = yield fetch(`${getMerklApiUrl()}/v4/opportunities?mainProtocolId=aave`, {
|
|
40
|
+
signal: AbortSignal.timeout(LONGER_TIMEOUT),
|
|
40
41
|
});
|
|
41
42
|
if (!res.ok)
|
|
42
43
|
throw new Error('Failed to fetch Merkle campaigns');
|
package/esm/aaveV4/index.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Client } from 'viem';
|
|
2
|
-
import { AaveV4AccountData, AaveV4SpokeData, AaveV4SpokeInfo, EthAddress, EthereumProvider, NetworkNumber } from '../types';
|
|
2
|
+
import { AaveV4AccountData, AaveV4SpokeData, AaveV4SpokeInfo, EthAddress, EthereumProvider, NetworkNumber, Blockish, PositionBalances } from '../types';
|
|
3
3
|
export * as lend from './lend';
|
|
4
4
|
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
8
|
export declare function getAaveV4AccountData(provider: EthereumProvider, network: NetworkNumber, marketData: AaveV4SpokeData, address: EthAddress, blockNumber?: 'latest' | number): Promise<any>;
|
|
9
|
+
export declare const _getAaveV4AccountBalances: (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, spokeAddress: EthAddress, spokeData?: AaveV4SpokeData) => Promise<PositionBalances>;
|
|
10
|
+
export declare const getAaveV4AccountBalances: (provider: EthereumProvider, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, spokeAddress: EthAddress, spokeData?: AaveV4SpokeData) => Promise<PositionBalances>;
|
|
9
11
|
export declare function getAaveV4UnderlyingFromReserveId(provider: EthereumProvider, network: NetworkNumber, spoke: EthAddress, reserveId: number): Promise<any>;
|
package/esm/aaveV4/index.js
CHANGED
|
@@ -8,14 +8,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import Dec from 'decimal.js';
|
|
11
|
-
import { assetAmountInEth, getAssetInfoByAddress } from '@defisaver/tokens';
|
|
11
|
+
import { assetAmountInEth, assetAmountInWei, getAssetInfoByAddress } from '@defisaver/tokens';
|
|
12
12
|
import { getViemProvider } from '../services/viem';
|
|
13
13
|
import { IncentiveKind, } from '../types';
|
|
14
14
|
import { AaveV4ViewContractViem } from '../contracts';
|
|
15
15
|
import { getStakingApy, STAKING_ASSETS } from '../staking';
|
|
16
|
-
import { isMaxUint, wethToEth } from '../services/utils';
|
|
16
|
+
import { isMaxUint, wethToEth, wethToEthByAddress } from '../services/utils';
|
|
17
17
|
import { aaveV4GetAggregatedPositionData, calcUserRiskPremiumBps } from '../helpers/aaveV4Helpers';
|
|
18
|
-
import { getAaveV4HubByAddress } from '../markets/aaveV4';
|
|
18
|
+
import { findAaveV4SpokeByAddress, getAaveV4HubByAddress } from '../markets/aaveV4';
|
|
19
19
|
import { aprToApy } from '../moneymarket';
|
|
20
20
|
import { attachAaveV4MerklIncentives, getAaveV4MerkleCampaigns } from './merkl';
|
|
21
21
|
export * as lend from './lend';
|
|
@@ -240,6 +240,44 @@ export function getAaveV4AccountData(provider_1, network_1, marketData_1, addres
|
|
|
240
240
|
return _getAaveV4AccountData(getViemProvider(provider, network), network, marketData, address, blockNumber);
|
|
241
241
|
});
|
|
242
242
|
}
|
|
243
|
+
export const _getAaveV4AccountBalances = (provider, network, block, addressMapping, address, spokeAddress, spokeData) => __awaiter(void 0, void 0, void 0, function* () {
|
|
244
|
+
const balances = {
|
|
245
|
+
collateral: {},
|
|
246
|
+
debt: {},
|
|
247
|
+
};
|
|
248
|
+
if (!address || !spokeAddress) {
|
|
249
|
+
return balances;
|
|
250
|
+
}
|
|
251
|
+
const blockNumber = block === 'latest' ? 'latest' : Number(block);
|
|
252
|
+
let resolvedSpokeData = spokeData;
|
|
253
|
+
if (!resolvedSpokeData) {
|
|
254
|
+
const spokeInfo = findAaveV4SpokeByAddress(network, spokeAddress);
|
|
255
|
+
if (!spokeInfo) {
|
|
256
|
+
return balances;
|
|
257
|
+
}
|
|
258
|
+
resolvedSpokeData = yield _getAaveV4SpokeData(provider, network, spokeInfo, blockNumber);
|
|
259
|
+
}
|
|
260
|
+
const accountData = yield _getAaveV4AccountData(provider, network, resolvedSpokeData, address, blockNumber);
|
|
261
|
+
const finalSpokeData = resolvedSpokeData;
|
|
262
|
+
Object.entries(accountData.usedAssets).forEach(([key, asset]) => {
|
|
263
|
+
const reserveData = finalSpokeData.assetsData[key];
|
|
264
|
+
if (!reserveData)
|
|
265
|
+
return;
|
|
266
|
+
const balanceKey = addressMapping
|
|
267
|
+
? wethToEthByAddress(reserveData.underlying, network).toLowerCase()
|
|
268
|
+
: wethToEth(asset.symbol);
|
|
269
|
+
if (asset.isSupplied && new Dec(asset.supplied || 0).gt(0)) {
|
|
270
|
+
balances.collateral[balanceKey] = assetAmountInWei(asset.supplied, asset.symbol);
|
|
271
|
+
}
|
|
272
|
+
if (asset.isBorrowed && new Dec(asset.borrowed || 0).gt(0)) {
|
|
273
|
+
balances.debt[balanceKey] = assetAmountInWei(asset.borrowed, asset.symbol);
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
return balances;
|
|
277
|
+
});
|
|
278
|
+
export const getAaveV4AccountBalances = (provider, network, block, addressMapping, address, spokeAddress, spokeData) => __awaiter(void 0, void 0, void 0, function* () {
|
|
279
|
+
return _getAaveV4AccountBalances(getViemProvider(provider, network), network, block, addressMapping, address, spokeAddress, spokeData);
|
|
280
|
+
});
|
|
243
281
|
const _getAaveV4UnderlyingFromReserveId = (provider, network, spoke, reserveId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
244
282
|
const viewContract = AaveV4ViewContractViem(provider, network);
|
|
245
283
|
const reserveData = yield viewContract.read.getReserveData([spoke, BigInt(reserveId)]);
|
package/esm/aaveV4/merkl.js
CHANGED
|
@@ -8,7 +8,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { aprToApy } from '../moneymarket';
|
|
11
|
-
import {
|
|
11
|
+
import { LONGER_TIMEOUT } from '../services/utils';
|
|
12
|
+
import { getMerklApiUrl } from '../services/merkl';
|
|
12
13
|
import { IncentiveKind, OpportunityAction, OpportunityStatus, } from '../types';
|
|
13
14
|
/**
|
|
14
15
|
* Merkl tags Aave V4 reward campaigns by scope via the `type` field:
|
|
@@ -31,8 +32,8 @@ const buildIncentive = (opportunity) => {
|
|
|
31
32
|
export const getAaveV4MerkleCampaigns = (chainId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
32
33
|
const result = { hub: {}, spoke: {} };
|
|
33
34
|
try {
|
|
34
|
-
const res = yield fetch(
|
|
35
|
-
signal: AbortSignal.timeout(
|
|
35
|
+
const res = yield fetch(`${getMerklApiUrl()}/v4/opportunities?mainProtocolId=aave`, {
|
|
36
|
+
signal: AbortSignal.timeout(LONGER_TIMEOUT),
|
|
36
37
|
});
|
|
37
38
|
if (!res.ok)
|
|
38
39
|
throw new Error('Failed to fetch Aave V4 Merkle campaigns');
|
package/esm/claiming/aaveV3.js
CHANGED
|
@@ -10,8 +10,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
import Dec from 'decimal.js';
|
|
11
11
|
import { ClaimType } from '../types/claiming';
|
|
12
12
|
import { AaveIncentiveDataProviderV3ContractViem, AaveRewardsControllerViem, } from '../contracts';
|
|
13
|
-
import { compareAddresses, getEthAmountForDecimals } from '../services/utils';
|
|
13
|
+
import { compareAddresses, getEthAmountForDecimals, LONGER_TIMEOUT } from '../services/utils';
|
|
14
14
|
import { getAaveUnderlyingSymbol } from '../helpers/aaveHelpers';
|
|
15
|
+
import { getMerklApiUrl } from '../services/merkl';
|
|
15
16
|
const mapAaveRewardsToClaimableTokens = (aaveRewards, marketAddress, walletAddress) => aaveRewards.map(reward => ({
|
|
16
17
|
symbol: reward.symbol,
|
|
17
18
|
amount: reward.amount,
|
|
@@ -92,7 +93,7 @@ export function getMeritUnclaimedRewards(account, network) {
|
|
|
92
93
|
return __awaiter(this, void 0, void 0, function* () {
|
|
93
94
|
let data;
|
|
94
95
|
try {
|
|
95
|
-
const res = yield fetch(
|
|
96
|
+
const res = yield fetch(`${getMerklApiUrl()}/v4/users/${account}/rewards?chainId=${network}`, { signal: AbortSignal.timeout(LONGER_TIMEOUT) });
|
|
96
97
|
data = yield res.json();
|
|
97
98
|
}
|
|
98
99
|
catch (error) {
|
|
@@ -100,6 +101,10 @@ export function getMeritUnclaimedRewards(account, network) {
|
|
|
100
101
|
data = [];
|
|
101
102
|
}
|
|
102
103
|
const claimableTokens = [];
|
|
104
|
+
// Merkl (or our proxy, on a non-2xx) can return a non-array error body; `fetch` doesn't throw on
|
|
105
|
+
// HTTP errors, so guard before iterating. Mirrors the app-side getMeritUnclaimedRewards.
|
|
106
|
+
if (!Array.isArray(data))
|
|
107
|
+
return claimableTokens;
|
|
103
108
|
data.forEach((item) => {
|
|
104
109
|
item.rewards.forEach(reward => {
|
|
105
110
|
const { token, amount, claimed, proofs, } = reward;
|
|
@@ -30,6 +30,23 @@ export declare const aaveAnyGetEmodeMutableProps: ({ eModeCategory, eModeCategor
|
|
|
30
30
|
liquidationRatio: any;
|
|
31
31
|
collateralFactor: any;
|
|
32
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* @description Per-asset effective LTV and liquidation threshold (LLTV) for the user, eMode-aware.
|
|
35
|
+
* Mirrors AaveV3View._getUserReserveLtvAndLltv: an asset in the active eMode's ltv-zero set has
|
|
36
|
+
* ltv 0 but KEEPS the eMode liquidation threshold (liquidations only consider LLTV). The returned
|
|
37
|
+
* `ltv` is identical to aaveAnyGetEmodeMutableProps().collateralFactor in every branch, so a ratio
|
|
38
|
+
* built on this matches the regular safety ratio whenever no collateral is LTV-0.
|
|
39
|
+
*
|
|
40
|
+
* Intentionally NOT merged with aaveAnyGetEmodeMutableProps (which it otherwise duplicates): the two
|
|
41
|
+
* differ only for an eMode ltv-zero asset — that helper returns liquidationRatio '0', whereas this one
|
|
42
|
+
* keeps the eMode liquidation threshold (to match the contract). aaveAnyGetEmodeMutableProps also feeds
|
|
43
|
+
* liquidationLimitUsd, so unifying them would change healthRatio / liqRatio / liquidationPrice for
|
|
44
|
+
* eMode-ltv-zero positions — to be done as a separate, validated follow-up PR.
|
|
45
|
+
*/
|
|
46
|
+
export declare const aaveAnyGetUserReserveLtvAndLltv: ({ eModeCategory, eModeCategoriesData, assetsData, }: AaveHelperCommon, _asset: string) => {
|
|
47
|
+
ltv: string;
|
|
48
|
+
lltv: string;
|
|
49
|
+
};
|
|
33
50
|
export declare const aaveAnyGetAggregatedPositionData: ({ usedAssets, eModeCategory, assetsData, selectedMarket, network, ...rest }: AaveHelperCommon) => AaveV3AggregatedPositionData;
|
|
34
51
|
export declare const getApyAfterValuesEstimation: (selectedMarket: AaveMarketInfo, actions: [{
|
|
35
52
|
action: string;
|
|
@@ -69,6 +69,38 @@ export const aaveAnyGetEmodeMutableProps = ({ eModeCategory, eModeCategoriesData
|
|
|
69
69
|
const { liquidationRatio, collateralFactor } = eModeCategoryData;
|
|
70
70
|
return ({ liquidationRatio, collateralFactor });
|
|
71
71
|
};
|
|
72
|
+
/**
|
|
73
|
+
* @description Offset subtracted from the liquidation threshold (LLTV) when crediting LTV-0 collateral
|
|
74
|
+
* in the safety-ratio fallback. Matches AaveV3View.getSafetyRatioWithLtvZeroFallback ('LLTV - 5%').
|
|
75
|
+
* Values are fractions (e.g. 0.8), so 5% === 0.05.
|
|
76
|
+
*/
|
|
77
|
+
const LTV_ZERO_FALLBACK_LLTV_OFFSET = '0.05';
|
|
78
|
+
/**
|
|
79
|
+
* @description Per-asset effective LTV and liquidation threshold (LLTV) for the user, eMode-aware.
|
|
80
|
+
* Mirrors AaveV3View._getUserReserveLtvAndLltv: an asset in the active eMode's ltv-zero set has
|
|
81
|
+
* ltv 0 but KEEPS the eMode liquidation threshold (liquidations only consider LLTV). The returned
|
|
82
|
+
* `ltv` is identical to aaveAnyGetEmodeMutableProps().collateralFactor in every branch, so a ratio
|
|
83
|
+
* built on this matches the regular safety ratio whenever no collateral is LTV-0.
|
|
84
|
+
*
|
|
85
|
+
* Intentionally NOT merged with aaveAnyGetEmodeMutableProps (which it otherwise duplicates): the two
|
|
86
|
+
* differ only for an eMode ltv-zero asset — that helper returns liquidationRatio '0', whereas this one
|
|
87
|
+
* keeps the eMode liquidation threshold (to match the contract). aaveAnyGetEmodeMutableProps also feeds
|
|
88
|
+
* liquidationLimitUsd, so unifying them would change healthRatio / liqRatio / liquidationPrice for
|
|
89
|
+
* eMode-ltv-zero positions — to be done as a separate, validated follow-up PR.
|
|
90
|
+
*/
|
|
91
|
+
export const aaveAnyGetUserReserveLtvAndLltv = ({ eModeCategory, eModeCategoriesData, assetsData, }, _asset) => {
|
|
92
|
+
const asset = getNativeAssetFromWrapped(_asset);
|
|
93
|
+
const assetData = assetsData[asset];
|
|
94
|
+
const eModeCategoryData = eModeCategoriesData === null || eModeCategoriesData === void 0 ? void 0 : eModeCategoriesData[eModeCategory];
|
|
95
|
+
if (eModeCategory === 0
|
|
96
|
+
|| !eModeCategoryData
|
|
97
|
+
|| !eModeCategoryData.collateralAssets.includes(asset)
|
|
98
|
+
|| new Dec(eModeCategoryData.collateralFactor || 0).eq(0)) {
|
|
99
|
+
return { ltv: assetData.collateralFactor, lltv: assetData.liquidationRatio };
|
|
100
|
+
}
|
|
101
|
+
const ltv = eModeCategoryData.ltvZeroAssets.includes(asset) ? '0' : eModeCategoryData.collateralFactor;
|
|
102
|
+
return { ltv, lltv: eModeCategoryData.liquidationRatio };
|
|
103
|
+
};
|
|
72
104
|
export const aaveAnyGetAggregatedPositionData = (_a) => {
|
|
73
105
|
var { usedAssets, eModeCategory, assetsData, selectedMarket, network } = _a, rest = __rest(_a, ["usedAssets", "eModeCategory", "assetsData", "selectedMarket", "network"]);
|
|
74
106
|
const data = Object.assign({ usedAssets, eModeCategory, assetsData, selectedMarket, network }, rest);
|
|
@@ -82,6 +114,17 @@ export const aaveAnyGetAggregatedPositionData = (_a) => {
|
|
|
82
114
|
payload.leftToBorrowUsd = leftToBorrowUsd.lte('0') ? '0' : leftToBorrowUsd.toString();
|
|
83
115
|
payload.ratio = +payload.suppliedUsd ? new Dec(payload.borrowLimitUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
|
|
84
116
|
payload.collRatio = +payload.suppliedUsd ? new Dec(payload.suppliedCollateralUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
|
|
117
|
+
// Safety ratio as evaluated by the automation bots: LTV-0 collateral is credited at (LLTV - 5%)
|
|
118
|
+
// instead of 0 (AaveV3View.getSafetyRatioWithLtvZeroFallback). Equals `ratio` when no collateral
|
|
119
|
+
// is LTV-0. Computed off-chain here so it is available for after-value simulations too.
|
|
120
|
+
payload.borrowLimitWithLtvZeroFallbackUsd = getAssetsTotal(usedAssets, ({ isSupplied, collateral }) => isSupplied && collateral, ({ symbol, suppliedUsd }) => {
|
|
121
|
+
const { ltv, lltv } = aaveAnyGetUserReserveLtvAndLltv(data, symbol);
|
|
122
|
+
const effectiveLtv = new Dec(ltv).eq(0)
|
|
123
|
+
? Dec.max(0, new Dec(lltv).sub(LTV_ZERO_FALLBACK_LLTV_OFFSET))
|
|
124
|
+
: new Dec(ltv);
|
|
125
|
+
return new Dec(suppliedUsd).mul(effectiveLtv);
|
|
126
|
+
});
|
|
127
|
+
payload.safetyRatioWithLtvZeroFallback = +payload.suppliedUsd ? new Dec(payload.borrowLimitWithLtvZeroFallbackUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
|
|
85
128
|
payload.liqRatio = new Dec(payload.borrowLimitUsd).div(payload.liquidationLimitUsd).toString();
|
|
86
129
|
payload.liqPercent = new Dec(payload.borrowLimitUsd).div(payload.liquidationLimitUsd).mul(100).toString();
|
|
87
130
|
const { leveragedType, leveragedAsset } = isLeveragedPos(usedAssets);
|
package/esm/index.d.ts
CHANGED
|
@@ -22,4 +22,5 @@ import * as portfolio from './portfolio';
|
|
|
22
22
|
import * as claiming from './claiming';
|
|
23
23
|
import * as savings from './savings';
|
|
24
24
|
export * from './types';
|
|
25
|
+
export { getMerklApiUrl, setMerklApiUrl } from './services/merkl';
|
|
25
26
|
export { aaveV2, aaveV3, aaveV4, compoundV2, compoundV3, spark, curveUsd, liquity, liquityV2, maker, exchange, staking, moneymarket, markets, helpers, morphoBlue, llamaLend, eulerV2, fluid, portfolio, claiming, savings, };
|
package/esm/index.js
CHANGED
|
@@ -22,4 +22,5 @@ import * as portfolio from './portfolio';
|
|
|
22
22
|
import * as claiming from './claiming';
|
|
23
23
|
import * as savings from './savings';
|
|
24
24
|
export * from './types';
|
|
25
|
+
export { getMerklApiUrl, setMerklApiUrl } from './services/merkl';
|
|
25
26
|
export { aaveV2, aaveV3, aaveV4, compoundV2, compoundV3, spark, curveUsd, liquity, liquityV2, maker, exchange, staking, moneymarket, markets, helpers, morphoBlue, llamaLend, eulerV2, fluid, portfolio, claiming, savings, };
|
|
@@ -32,3 +32,4 @@ export declare const AaveV4Spokes: (networkId: NetworkNumber) => {
|
|
|
32
32
|
readonly aave_v4_main_spoke: AaveV4SpokeInfo;
|
|
33
33
|
};
|
|
34
34
|
export declare const getAaveV4SpokeTypeInfo: (type: AaveV4SpokesType, network?: NetworkNumber) => AaveV4SpokeInfo;
|
|
35
|
+
export declare const findAaveV4SpokeByAddress: (networkId: NetworkNumber, address: string) => AaveV4SpokeInfo | undefined;
|
|
@@ -159,3 +159,4 @@ export const AaveV4Spokes = (networkId) => ({
|
|
|
159
159
|
[AaveV4SpokesType.AaveV4MainSpoke]: AAVE_V4_MAIN_SPOKE(networkId),
|
|
160
160
|
});
|
|
161
161
|
export const getAaveV4SpokeTypeInfo = (type, network) => (Object.assign({}, AaveV4Spokes(network !== null && network !== void 0 ? network : NetworkNumber.Eth))[type]);
|
|
162
|
+
export const findAaveV4SpokeByAddress = (networkId, address) => Object.values(AaveV4Spokes(networkId)).find(spoke => spoke.address.toLowerCase() === address.toLowerCase());
|
package/esm/markets/index.d.ts
CHANGED
|
@@ -7,4 +7,4 @@ export { LlamaLendMarkets } from './llamaLend';
|
|
|
7
7
|
export { LiquityV2Markets, findLiquityV2MarketByAddress } from './liquityV2';
|
|
8
8
|
export { EulerV2Markets } from './euler';
|
|
9
9
|
export { FluidMarkets, getFluidVersionsDataForNetwork, getFluidMarketInfoById, getFTokenAddress, getFluidMarketInfoByAddress, } from './fluid';
|
|
10
|
-
export { AaveV4Spokes } from './aaveV4';
|
|
10
|
+
export { AaveV4Spokes, findAaveV4SpokeByAddress } from './aaveV4';
|
package/esm/markets/index.js
CHANGED
|
@@ -7,4 +7,4 @@ export { LlamaLendMarkets } from './llamaLend';
|
|
|
7
7
|
export { LiquityV2Markets, findLiquityV2MarketByAddress } from './liquityV2';
|
|
8
8
|
export { EulerV2Markets } from './euler';
|
|
9
9
|
export { FluidMarkets, getFluidVersionsDataForNetwork, getFluidMarketInfoById, getFTokenAddress, getFluidMarketInfoByAddress, } from './fluid';
|
|
10
|
-
export { AaveV4Spokes } from './aaveV4';
|
|
10
|
+
export { AaveV4Spokes, findAaveV4SpokeByAddress } from './aaveV4';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configurable base URL for the Merkl API (https://developers.merkl.xyz).
|
|
3
|
+
*
|
|
4
|
+
* Defaults to Merkl's public host. Consumers can override it via `setMerklApiUrl` — e.g. to route
|
|
5
|
+
* requests through their own backend proxy that attaches a Merkl API key (the key must stay
|
|
6
|
+
* server-side, and a proxy also avoids browser CORS limits on the public host).
|
|
7
|
+
*/
|
|
8
|
+
let merklApiUrl = 'https://api.merkl.xyz';
|
|
9
|
+
export const getMerklApiUrl = () => merklApiUrl;
|
|
10
|
+
export const setMerklApiUrl = (url) => {
|
|
11
|
+
merklApiUrl = url.replace(/\/+$/, '');
|
|
12
|
+
};
|
package/esm/types/aave.d.ts
CHANGED
|
@@ -125,6 +125,7 @@ export interface AavePositionData extends MMPositionData {
|
|
|
125
125
|
ratio: string;
|
|
126
126
|
minRatio: string;
|
|
127
127
|
collRatio: string;
|
|
128
|
+
safetyRatioWithLtvZeroFallback?: string;
|
|
128
129
|
suppliedUsd: string;
|
|
129
130
|
borrowedUsd: string;
|
|
130
131
|
borrowLimitUsd: string;
|
|
@@ -156,6 +157,8 @@ export interface AaveV3AggregatedPositionData {
|
|
|
156
157
|
leftToBorrowUsd: string;
|
|
157
158
|
ratio: string;
|
|
158
159
|
collRatio: string;
|
|
160
|
+
borrowLimitWithLtvZeroFallbackUsd: string;
|
|
161
|
+
safetyRatioWithLtvZeroFallback: string;
|
|
159
162
|
netApy: string;
|
|
160
163
|
incentiveUsd: string;
|
|
161
164
|
totalInterestUsd: string;
|
package/package.json
CHANGED
package/src/aaveV3/merkl.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { aprToApy } from '../moneymarket';
|
|
2
|
-
import {
|
|
2
|
+
import { LONGER_TIMEOUT, wethToEth } from '../services/utils';
|
|
3
|
+
import { getMerklApiUrl } from '../services/merkl';
|
|
3
4
|
import {
|
|
4
5
|
MerkleRewardMap, MerklOpportunity, OpportunityAction, OpportunityStatus,
|
|
5
6
|
} from '../types';
|
|
@@ -31,8 +32,8 @@ export const formatAaveAsset = (_symbol: string) => {
|
|
|
31
32
|
|
|
32
33
|
export const getMerkleCampaigns = async (chainId: NetworkNumber): Promise<MerkleRewardMap> => {
|
|
33
34
|
try {
|
|
34
|
-
const res = await fetch(
|
|
35
|
-
signal: AbortSignal.timeout(
|
|
35
|
+
const res = await fetch(`${getMerklApiUrl()}/v4/opportunities?mainProtocolId=aave`, {
|
|
36
|
+
signal: AbortSignal.timeout(LONGER_TIMEOUT),
|
|
36
37
|
});
|
|
37
38
|
if (!res.ok) throw new Error('Failed to fetch Merkle campaigns');
|
|
38
39
|
const opportunities = await res.json() as MerklOpportunity[];
|
package/src/aaveV4/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Client } from 'viem';
|
|
2
2
|
import Dec from 'decimal.js';
|
|
3
|
-
import { assetAmountInEth, getAssetInfoByAddress } from '@defisaver/tokens';
|
|
3
|
+
import { assetAmountInEth, assetAmountInWei, getAssetInfoByAddress } from '@defisaver/tokens';
|
|
4
4
|
import { getViemProvider } from '../services/viem';
|
|
5
5
|
import {
|
|
6
6
|
AaveV4AccountData,
|
|
@@ -16,12 +16,14 @@ import {
|
|
|
16
16
|
IncentiveData,
|
|
17
17
|
IncentiveKind,
|
|
18
18
|
NetworkNumber,
|
|
19
|
+
Blockish,
|
|
20
|
+
PositionBalances,
|
|
19
21
|
} from '../types';
|
|
20
22
|
import { AaveV4ViewContractViem } from '../contracts';
|
|
21
23
|
import { getStakingApy, STAKING_ASSETS } from '../staking';
|
|
22
|
-
import { isMaxUint, wethToEth } from '../services/utils';
|
|
24
|
+
import { isMaxUint, wethToEth, wethToEthByAddress } from '../services/utils';
|
|
23
25
|
import { aaveV4GetAggregatedPositionData, calcUserRiskPremiumBps } from '../helpers/aaveV4Helpers';
|
|
24
|
-
import { getAaveV4HubByAddress } from '../markets/aaveV4';
|
|
26
|
+
import { findAaveV4SpokeByAddress, getAaveV4HubByAddress } from '../markets/aaveV4';
|
|
25
27
|
import { aprToApy } from '../moneymarket';
|
|
26
28
|
import { attachAaveV4MerklIncentives, getAaveV4MerkleCampaigns } from './merkl';
|
|
27
29
|
|
|
@@ -259,6 +261,74 @@ export async function getAaveV4AccountData(provider: EthereumProvider, network:
|
|
|
259
261
|
return _getAaveV4AccountData(getViemProvider(provider, network), network, marketData, address, blockNumber);
|
|
260
262
|
}
|
|
261
263
|
|
|
264
|
+
export const _getAaveV4AccountBalances = async (
|
|
265
|
+
provider: Client,
|
|
266
|
+
network: NetworkNumber,
|
|
267
|
+
block: Blockish,
|
|
268
|
+
addressMapping: boolean,
|
|
269
|
+
address: EthAddress,
|
|
270
|
+
spokeAddress: EthAddress,
|
|
271
|
+
spokeData?: AaveV4SpokeData,
|
|
272
|
+
): Promise<PositionBalances> => {
|
|
273
|
+
const balances: PositionBalances = {
|
|
274
|
+
collateral: {},
|
|
275
|
+
debt: {},
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
if (!address || !spokeAddress) {
|
|
279
|
+
return balances;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const blockNumber = block === 'latest' ? 'latest' : Number(block);
|
|
283
|
+
let resolvedSpokeData = spokeData;
|
|
284
|
+
if (!resolvedSpokeData) {
|
|
285
|
+
const spokeInfo = findAaveV4SpokeByAddress(network, spokeAddress);
|
|
286
|
+
if (!spokeInfo) {
|
|
287
|
+
return balances;
|
|
288
|
+
}
|
|
289
|
+
resolvedSpokeData = await _getAaveV4SpokeData(provider, network, spokeInfo, blockNumber);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const accountData = await _getAaveV4AccountData(provider, network, resolvedSpokeData, address, blockNumber);
|
|
293
|
+
const finalSpokeData = resolvedSpokeData;
|
|
294
|
+
|
|
295
|
+
Object.entries(accountData.usedAssets).forEach(([key, asset]) => {
|
|
296
|
+
const reserveData = finalSpokeData.assetsData[key];
|
|
297
|
+
if (!reserveData) return;
|
|
298
|
+
|
|
299
|
+
const balanceKey = addressMapping
|
|
300
|
+
? wethToEthByAddress(reserveData.underlying, network).toLowerCase()
|
|
301
|
+
: wethToEth(asset.symbol);
|
|
302
|
+
|
|
303
|
+
if (asset.isSupplied && new Dec(asset.supplied || 0).gt(0)) {
|
|
304
|
+
balances.collateral![balanceKey] = assetAmountInWei(asset.supplied, asset.symbol);
|
|
305
|
+
}
|
|
306
|
+
if (asset.isBorrowed && new Dec(asset.borrowed || 0).gt(0)) {
|
|
307
|
+
balances.debt![balanceKey] = assetAmountInWei(asset.borrowed, asset.symbol);
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
return balances;
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
export const getAaveV4AccountBalances = async (
|
|
315
|
+
provider: EthereumProvider,
|
|
316
|
+
network: NetworkNumber,
|
|
317
|
+
block: Blockish,
|
|
318
|
+
addressMapping: boolean,
|
|
319
|
+
address: EthAddress,
|
|
320
|
+
spokeAddress: EthAddress,
|
|
321
|
+
spokeData?: AaveV4SpokeData,
|
|
322
|
+
): Promise<PositionBalances> => _getAaveV4AccountBalances(
|
|
323
|
+
getViemProvider(provider, network),
|
|
324
|
+
network,
|
|
325
|
+
block,
|
|
326
|
+
addressMapping,
|
|
327
|
+
address,
|
|
328
|
+
spokeAddress,
|
|
329
|
+
spokeData,
|
|
330
|
+
);
|
|
331
|
+
|
|
262
332
|
const _getAaveV4UnderlyingFromReserveId = async (provider: Client, network: NetworkNumber, spoke: EthAddress, reserveId: number): Promise<any> => {
|
|
263
333
|
const viewContract = AaveV4ViewContractViem(provider, network);
|
|
264
334
|
|
package/src/aaveV4/merkl.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { aprToApy } from '../moneymarket';
|
|
2
|
-
import {
|
|
2
|
+
import { LONGER_TIMEOUT } from '../services/utils';
|
|
3
|
+
import { getMerklApiUrl } from '../services/merkl';
|
|
3
4
|
import {
|
|
4
5
|
AaveV4MerklRewardMap,
|
|
5
6
|
AaveV4ReserveAssetData,
|
|
@@ -34,8 +35,8 @@ const buildIncentive = (opportunity: MerklOpportunity): IncentiveData => {
|
|
|
34
35
|
export const getAaveV4MerkleCampaigns = async (chainId: NetworkNumber): Promise<AaveV4MerklRewardMap> => {
|
|
35
36
|
const result: AaveV4MerklRewardMap = { hub: {}, spoke: {} };
|
|
36
37
|
try {
|
|
37
|
-
const res = await fetch(
|
|
38
|
-
signal: AbortSignal.timeout(
|
|
38
|
+
const res = await fetch(`${getMerklApiUrl()}/v4/opportunities?mainProtocolId=aave`, {
|
|
39
|
+
signal: AbortSignal.timeout(LONGER_TIMEOUT),
|
|
39
40
|
});
|
|
40
41
|
if (!res.ok) throw new Error('Failed to fetch Aave V4 Merkle campaigns');
|
|
41
42
|
const opportunities = await res.json() as MerklOpportunity[];
|
package/src/claiming/aaveV3.ts
CHANGED
|
@@ -6,8 +6,9 @@ import {
|
|
|
6
6
|
AaveIncentiveDataProviderV3ContractViem,
|
|
7
7
|
AaveRewardsControllerViem,
|
|
8
8
|
} from '../contracts';
|
|
9
|
-
import { compareAddresses, getEthAmountForDecimals } from '../services/utils';
|
|
9
|
+
import { compareAddresses, getEthAmountForDecimals, LONGER_TIMEOUT } from '../services/utils';
|
|
10
10
|
import { getAaveUnderlyingSymbol } from '../helpers/aaveHelpers';
|
|
11
|
+
import { getMerklApiUrl } from '../services/merkl';
|
|
11
12
|
|
|
12
13
|
type AaveReward = {
|
|
13
14
|
amount: string;
|
|
@@ -106,8 +107,8 @@ export async function getUnclaimedRewardsForAllMarkets(
|
|
|
106
107
|
export async function getMeritUnclaimedRewards(account: EthAddress, network: NetworkNumber): Promise<ClaimableToken[]> {
|
|
107
108
|
let data;
|
|
108
109
|
try {
|
|
109
|
-
const res = await fetch(
|
|
110
|
-
{ signal: AbortSignal.timeout(
|
|
110
|
+
const res = await fetch(`${getMerklApiUrl()}/v4/users/${account}/rewards?chainId=${network}`,
|
|
111
|
+
{ signal: AbortSignal.timeout(LONGER_TIMEOUT) });
|
|
111
112
|
data = await res.json();
|
|
112
113
|
} catch (error) {
|
|
113
114
|
console.error('External API Failure: Aave Merit', error);
|
|
@@ -116,6 +117,10 @@ export async function getMeritUnclaimedRewards(account: EthAddress, network: Net
|
|
|
116
117
|
|
|
117
118
|
const claimableTokens: ClaimableToken[] = [];
|
|
118
119
|
|
|
120
|
+
// Merkl (or our proxy, on a non-2xx) can return a non-array error body; `fetch` doesn't throw on
|
|
121
|
+
// HTTP errors, so guard before iterating. Mirrors the app-side getMeritUnclaimedRewards.
|
|
122
|
+
if (!Array.isArray(data)) return claimableTokens;
|
|
123
|
+
|
|
119
124
|
data.forEach((item: { rewards: any[]; }) => {
|
|
120
125
|
item.rewards.forEach(reward => {
|
|
121
126
|
const {
|
|
@@ -80,6 +80,51 @@ export const aaveAnyGetEmodeMutableProps = (
|
|
|
80
80
|
return ({ liquidationRatio, collateralFactor });
|
|
81
81
|
};
|
|
82
82
|
|
|
83
|
+
/**
|
|
84
|
+
* @description Offset subtracted from the liquidation threshold (LLTV) when crediting LTV-0 collateral
|
|
85
|
+
* in the safety-ratio fallback. Matches AaveV3View.getSafetyRatioWithLtvZeroFallback ('LLTV - 5%').
|
|
86
|
+
* Values are fractions (e.g. 0.8), so 5% === 0.05.
|
|
87
|
+
*/
|
|
88
|
+
const LTV_ZERO_FALLBACK_LLTV_OFFSET = '0.05';
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @description Per-asset effective LTV and liquidation threshold (LLTV) for the user, eMode-aware.
|
|
92
|
+
* Mirrors AaveV3View._getUserReserveLtvAndLltv: an asset in the active eMode's ltv-zero set has
|
|
93
|
+
* ltv 0 but KEEPS the eMode liquidation threshold (liquidations only consider LLTV). The returned
|
|
94
|
+
* `ltv` is identical to aaveAnyGetEmodeMutableProps().collateralFactor in every branch, so a ratio
|
|
95
|
+
* built on this matches the regular safety ratio whenever no collateral is LTV-0.
|
|
96
|
+
*
|
|
97
|
+
* Intentionally NOT merged with aaveAnyGetEmodeMutableProps (which it otherwise duplicates): the two
|
|
98
|
+
* differ only for an eMode ltv-zero asset — that helper returns liquidationRatio '0', whereas this one
|
|
99
|
+
* keeps the eMode liquidation threshold (to match the contract). aaveAnyGetEmodeMutableProps also feeds
|
|
100
|
+
* liquidationLimitUsd, so unifying them would change healthRatio / liqRatio / liquidationPrice for
|
|
101
|
+
* eMode-ltv-zero positions — to be done as a separate, validated follow-up PR.
|
|
102
|
+
*/
|
|
103
|
+
export const aaveAnyGetUserReserveLtvAndLltv = (
|
|
104
|
+
{
|
|
105
|
+
eModeCategory,
|
|
106
|
+
eModeCategoriesData,
|
|
107
|
+
assetsData,
|
|
108
|
+
}: AaveHelperCommon,
|
|
109
|
+
_asset: string,
|
|
110
|
+
): { ltv: string, lltv: string } => {
|
|
111
|
+
const asset = getNativeAssetFromWrapped(_asset);
|
|
112
|
+
const assetData = assetsData[asset];
|
|
113
|
+
const eModeCategoryData = eModeCategoriesData?.[eModeCategory];
|
|
114
|
+
|
|
115
|
+
if (
|
|
116
|
+
eModeCategory === 0
|
|
117
|
+
|| !eModeCategoryData
|
|
118
|
+
|| !eModeCategoryData.collateralAssets.includes(asset)
|
|
119
|
+
|| new Dec(eModeCategoryData.collateralFactor || 0).eq(0)
|
|
120
|
+
) {
|
|
121
|
+
return { ltv: assetData.collateralFactor, lltv: assetData.liquidationRatio };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const ltv = eModeCategoryData.ltvZeroAssets.includes(asset) ? '0' : eModeCategoryData.collateralFactor;
|
|
125
|
+
return { ltv, lltv: eModeCategoryData.liquidationRatio };
|
|
126
|
+
};
|
|
127
|
+
|
|
83
128
|
export const aaveAnyGetAggregatedPositionData = ({
|
|
84
129
|
usedAssets,
|
|
85
130
|
eModeCategory,
|
|
@@ -109,6 +154,21 @@ export const aaveAnyGetAggregatedPositionData = ({
|
|
|
109
154
|
payload.leftToBorrowUsd = leftToBorrowUsd.lte('0') ? '0' : leftToBorrowUsd.toString();
|
|
110
155
|
payload.ratio = +payload.suppliedUsd ? new Dec(payload.borrowLimitUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
|
|
111
156
|
payload.collRatio = +payload.suppliedUsd ? new Dec(payload.suppliedCollateralUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
|
|
157
|
+
// Safety ratio as evaluated by the automation bots: LTV-0 collateral is credited at (LLTV - 5%)
|
|
158
|
+
// instead of 0 (AaveV3View.getSafetyRatioWithLtvZeroFallback). Equals `ratio` when no collateral
|
|
159
|
+
// is LTV-0. Computed off-chain here so it is available for after-value simulations too.
|
|
160
|
+
payload.borrowLimitWithLtvZeroFallbackUsd = getAssetsTotal(
|
|
161
|
+
usedAssets,
|
|
162
|
+
({ isSupplied, collateral }: { isSupplied: boolean, collateral: string }) => isSupplied && collateral,
|
|
163
|
+
({ symbol, suppliedUsd }: { symbol: string, suppliedUsd: string }) => {
|
|
164
|
+
const { ltv, lltv } = aaveAnyGetUserReserveLtvAndLltv(data, symbol);
|
|
165
|
+
const effectiveLtv = new Dec(ltv).eq(0)
|
|
166
|
+
? Dec.max(0, new Dec(lltv).sub(LTV_ZERO_FALLBACK_LLTV_OFFSET))
|
|
167
|
+
: new Dec(ltv);
|
|
168
|
+
return new Dec(suppliedUsd).mul(effectiveLtv);
|
|
169
|
+
},
|
|
170
|
+
);
|
|
171
|
+
payload.safetyRatioWithLtvZeroFallback = +payload.suppliedUsd ? new Dec(payload.borrowLimitWithLtvZeroFallbackUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
|
|
112
172
|
payload.liqRatio = new Dec(payload.borrowLimitUsd).div(payload.liquidationLimitUsd).toString();
|
|
113
173
|
payload.liqPercent = new Dec(payload.borrowLimitUsd).div(payload.liquidationLimitUsd).mul(100).toString();
|
|
114
174
|
const { leveragedType, leveragedAsset } = isLeveragedPos(usedAssets);
|
package/src/index.ts
CHANGED
|
@@ -188,4 +188,8 @@ export const AaveV4Spokes = (networkId: NetworkNumber) => ({
|
|
|
188
188
|
|
|
189
189
|
export const getAaveV4SpokeTypeInfo = (type: AaveV4SpokesType, network?: NetworkNumber) => ({ ...AaveV4Spokes(network ?? NetworkNumber.Eth) }[type]);
|
|
190
190
|
|
|
191
|
+
export const findAaveV4SpokeByAddress = (networkId: NetworkNumber, address: string): AaveV4SpokeInfo | undefined => Object.values(AaveV4Spokes(networkId)).find(
|
|
192
|
+
spoke => spoke.address.toLowerCase() === address.toLowerCase(),
|
|
193
|
+
);
|
|
194
|
+
|
|
191
195
|
|
package/src/markets/index.ts
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configurable base URL for the Merkl API (https://developers.merkl.xyz).
|
|
3
|
+
*
|
|
4
|
+
* Defaults to Merkl's public host. Consumers can override it via `setMerklApiUrl` — e.g. to route
|
|
5
|
+
* requests through their own backend proxy that attaches a Merkl API key (the key must stay
|
|
6
|
+
* server-side, and a proxy also avoids browser CORS limits on the public host).
|
|
7
|
+
*/
|
|
8
|
+
let merklApiUrl = 'https://api.merkl.xyz';
|
|
9
|
+
|
|
10
|
+
export const getMerklApiUrl = (): string => merklApiUrl;
|
|
11
|
+
|
|
12
|
+
export const setMerklApiUrl = (url: string): void => {
|
|
13
|
+
merklApiUrl = url.replace(/\/+$/, '');
|
|
14
|
+
};
|
package/src/types/aave.ts
CHANGED
|
@@ -141,6 +141,8 @@ export interface AavePositionData extends MMPositionData {
|
|
|
141
141
|
ratio: string,
|
|
142
142
|
minRatio: string,
|
|
143
143
|
collRatio: string,
|
|
144
|
+
// Safety ratio as evaluated by automation bots (LTV-0 collateral credited at LLTV - 5%). Aave v3 only.
|
|
145
|
+
safetyRatioWithLtvZeroFallback?: string,
|
|
144
146
|
suppliedUsd: string,
|
|
145
147
|
borrowedUsd: string,
|
|
146
148
|
borrowLimitUsd: string,
|
|
@@ -173,6 +175,8 @@ export interface AaveV3AggregatedPositionData {
|
|
|
173
175
|
leftToBorrowUsd: string,
|
|
174
176
|
ratio: string,
|
|
175
177
|
collRatio: string,
|
|
178
|
+
borrowLimitWithLtvZeroFallbackUsd: string,
|
|
179
|
+
safetyRatioWithLtvZeroFallback: string,
|
|
176
180
|
netApy: string,
|
|
177
181
|
incentiveUsd: string,
|
|
178
182
|
totalInterestUsd: string,
|