@defisaver/positions-sdk 2.0.13 → 2.0.15-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/index.js +38 -31
- package/cjs/aaveV3/rewards.d.ts +14 -0
- package/cjs/aaveV3/rewards.js +82 -0
- package/cjs/markets/aave/marketAssets.js +1 -1
- package/cjs/staking/staking.js +3 -1
- package/cjs/types/aave.d.ts +3 -2
- package/esm/aaveV3/index.js +38 -31
- package/esm/aaveV3/rewards.d.ts +14 -0
- package/esm/aaveV3/rewards.js +77 -0
- package/esm/markets/aave/marketAssets.js +1 -1
- package/esm/staking/staking.js +3 -1
- package/esm/types/aave.d.ts +3 -2
- package/package.json +2 -2
- package/src/aaveV3/index.ts +41 -36
- package/src/aaveV3/rewards.ts +125 -0
- package/src/markets/aave/marketAssets.ts +1 -1
- package/src/staking/staking.ts +2 -1
- package/src/types/aave.ts +3 -2
package/cjs/aaveV3/index.js
CHANGED
|
@@ -25,6 +25,7 @@ const utils_1 = require("../services/utils");
|
|
|
25
25
|
const staking_1 = require("../staking");
|
|
26
26
|
const common_1 = require("../types/common");
|
|
27
27
|
const viem_1 = require("../services/viem");
|
|
28
|
+
const rewards_1 = require("./rewards");
|
|
28
29
|
const aaveV3EmodeCategoriesMapping = (extractedState, usedAssets) => {
|
|
29
30
|
const { eModeCategoriesData } = extractedState;
|
|
30
31
|
const usedAssetsValues = Object.values(usedAssets);
|
|
@@ -60,11 +61,12 @@ function _getAaveV3MarketData(provider_1, network_1, market_1) {
|
|
|
60
61
|
const marketAddress = market.providerAddress;
|
|
61
62
|
const networksWithIncentives = [common_1.NetworkNumber.Eth, common_1.NetworkNumber.Arb, common_1.NetworkNumber.Opt, common_1.NetworkNumber.Linea];
|
|
62
63
|
// eslint-disable-next-line prefer-const
|
|
63
|
-
let [loanInfo, eModesInfo, isBorrowAllowed, rewardInfo] = yield Promise.all([
|
|
64
|
+
let [loanInfo, eModesInfo, isBorrowAllowed, rewardInfo, merkleRewardsMap] = yield Promise.all([
|
|
64
65
|
loanInfoContract.read.getFullTokensInfo([marketAddress, _addresses], (0, viem_1.setViemBlockNumber)(blockNumber)),
|
|
65
66
|
loanInfoContract.read.getAllEmodes([marketAddress], (0, viem_1.setViemBlockNumber)(blockNumber)),
|
|
66
67
|
loanInfoContract.read.isBorrowAllowed([marketAddress], (0, viem_1.setViemBlockNumber)(blockNumber)), // Used on L2s check for PriceOracleSentinel (mainnet will always return true)
|
|
67
68
|
networksWithIncentives.includes(network) ? aaveIncentivesContract.read.getReservesIncentivesData([marketAddress], (0, viem_1.setViemBlockNumber)(blockNumber)) : null,
|
|
69
|
+
(0, rewards_1.getMerkleCampaigns)(network),
|
|
68
70
|
]);
|
|
69
71
|
isBorrowAllowed = (0, utils_1.isLayer2Network)(network) ? isBorrowAllowed : true;
|
|
70
72
|
const eModeCategoriesData = {};
|
|
@@ -146,10 +148,13 @@ function _getAaveV3MarketData(provider_1, network_1, market_1) {
|
|
|
146
148
|
isolationModeBorrowingEnabled: tokenMarket.isolationModeBorrowingEnabled,
|
|
147
149
|
isFlashLoanEnabled: tokenMarket.isFlashLoanEnabled,
|
|
148
150
|
aTokenAddress: tokenMarket.aTokenAddress,
|
|
151
|
+
supplyIncentives: [],
|
|
152
|
+
borrowIncentives: [],
|
|
149
153
|
});
|
|
150
154
|
})));
|
|
151
155
|
// Get incentives data
|
|
152
|
-
yield Promise.all(assetsData.map((_market) => __awaiter(this, void 0, void 0, function* () {
|
|
156
|
+
yield Promise.all(assetsData.map((_market, index) => __awaiter(this, void 0, void 0, function* () {
|
|
157
|
+
var _a;
|
|
153
158
|
/* eslint-disable no-param-reassign */
|
|
154
159
|
// @ts-ignore
|
|
155
160
|
const rewardForMarket = rewardInfo === null || rewardInfo === void 0 ? void 0 : rewardInfo[_market.underlyingTokenAddress];
|
|
@@ -157,38 +162,44 @@ function _getAaveV3MarketData(provider_1, network_1, market_1) {
|
|
|
157
162
|
if (isStakingAsset) {
|
|
158
163
|
_market.incentiveSupplyApy = yield (0, staking_1.getStakingApy)(_market.symbol);
|
|
159
164
|
_market.incentiveSupplyToken = _market.symbol;
|
|
160
|
-
if (!_market.supplyIncentives) {
|
|
161
|
-
_market.supplyIncentives = [];
|
|
162
|
-
}
|
|
163
165
|
_market.supplyIncentives.push({
|
|
164
166
|
apy: _market.incentiveSupplyApy || '0',
|
|
165
167
|
token: _market.symbol,
|
|
166
168
|
incentiveKind: 'staking',
|
|
169
|
+
description: `Native ${_market.symbol} yield.`,
|
|
167
170
|
});
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
171
|
+
if (_market.canBeBorrowed) {
|
|
172
|
+
// when borrowing assets whose value increases over time
|
|
173
|
+
_market.incentiveBorrowApy = new decimal_js_1.default(_market.incentiveSupplyApy).mul(-1).toString();
|
|
174
|
+
_market.incentiveBorrowToken = _market.symbol;
|
|
175
|
+
_market.borrowIncentives.push({
|
|
176
|
+
apy: _market.incentiveBorrowApy,
|
|
177
|
+
token: _market.incentiveBorrowToken,
|
|
178
|
+
incentiveKind: 'reward',
|
|
179
|
+
description: `Due to the native yield of ${_market.symbol}, the value of the debt would increase over time.`,
|
|
180
|
+
});
|
|
174
181
|
}
|
|
175
|
-
_market.borrowIncentives.push({
|
|
176
|
-
apy: _market.incentiveBorrowApy,
|
|
177
|
-
token: _market.incentiveBorrowToken,
|
|
178
|
-
incentiveKind: 'reward',
|
|
179
|
-
});
|
|
180
182
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
_market.supplyIncentives = [];
|
|
185
|
-
}
|
|
183
|
+
const aTokenAddress = _market.aTokenAddress.toLowerCase(); // DEV: Should aTokenAddress be in AaveV3AssetData type?
|
|
184
|
+
if ((_a = merkleRewardsMap[aTokenAddress]) === null || _a === void 0 ? void 0 : _a.supply) {
|
|
185
|
+
const { apr, rewardTokenSymbol, description } = merkleRewardsMap[aTokenAddress].supply;
|
|
186
186
|
_market.supplyIncentives.push({
|
|
187
|
-
apy:
|
|
188
|
-
token:
|
|
187
|
+
apy: (0, moneymarket_1.aprToApy)(apr),
|
|
188
|
+
token: rewardTokenSymbol,
|
|
189
189
|
incentiveKind: 'reward',
|
|
190
|
+
description,
|
|
190
191
|
});
|
|
191
192
|
}
|
|
193
|
+
// const aTokenDebtAddress = '0xTODO';
|
|
194
|
+
// if (merkleRewardsMap[aTokenDebtAddress]?.supply) {
|
|
195
|
+
// const { apr, rewardTokenSymbol, description } = merkleRewardsMap[aTokenDebtAddress].supply;
|
|
196
|
+
// _market.borrowIncentives.push({
|
|
197
|
+
// apy: aprToApy(apr),
|
|
198
|
+
// token: rewardTokenSymbol,
|
|
199
|
+
// incentiveKind: 'reward',
|
|
200
|
+
// description,
|
|
201
|
+
// });
|
|
202
|
+
// }
|
|
192
203
|
if (!rewardForMarket)
|
|
193
204
|
return;
|
|
194
205
|
// @ts-ignore
|
|
@@ -211,13 +222,11 @@ function _getAaveV3MarketData(provider_1, network_1, market_1) {
|
|
|
211
222
|
.toString();
|
|
212
223
|
_market.incentiveSupplyApy = new decimal_js_1.default(_market.incentiveSupplyApy || '0').add(rewardApy)
|
|
213
224
|
.toString();
|
|
214
|
-
if (!_market.supplyIncentives) {
|
|
215
|
-
_market.supplyIncentives = [];
|
|
216
|
-
}
|
|
217
225
|
_market.supplyIncentives.push({
|
|
218
|
-
token: supplyRewardData.rewardTokenSymbol,
|
|
226
|
+
token: (0, rewards_1.getAaveUnderlyingSymbol)(supplyRewardData.rewardTokenSymbol),
|
|
219
227
|
apy: rewardApy,
|
|
220
228
|
incentiveKind: 'reward',
|
|
229
|
+
description: 'Eligible for protocol-level incentives.',
|
|
221
230
|
});
|
|
222
231
|
}
|
|
223
232
|
});
|
|
@@ -240,13 +249,11 @@ function _getAaveV3MarketData(provider_1, network_1, market_1) {
|
|
|
240
249
|
.toString();
|
|
241
250
|
_market.incentiveBorrowApy = new decimal_js_1.default(_market.incentiveBorrowApy || '0').add(rewardApy)
|
|
242
251
|
.toString();
|
|
243
|
-
if (!_market.borrowIncentives) {
|
|
244
|
-
_market.borrowIncentives = [];
|
|
245
|
-
}
|
|
246
252
|
_market.borrowIncentives.push({
|
|
247
|
-
token: borrowRewardData.rewardTokenSymbol,
|
|
253
|
+
token: (0, rewards_1.getAaveUnderlyingSymbol)(borrowRewardData.rewardTokenSymbol),
|
|
248
254
|
apy: rewardApy,
|
|
249
255
|
incentiveKind: 'reward',
|
|
256
|
+
description: 'Eligible for protocol-level incentives.',
|
|
250
257
|
});
|
|
251
258
|
}
|
|
252
259
|
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { EthAddress, NetworkNumber } from '../types/common';
|
|
2
|
+
type RewardInfo = {
|
|
3
|
+
apr: number;
|
|
4
|
+
rewardToken: EthAddress;
|
|
5
|
+
rewardTokenSymbol: string;
|
|
6
|
+
description: string;
|
|
7
|
+
};
|
|
8
|
+
type MerkleRewardMap = Record<EthAddress, {
|
|
9
|
+
supply?: RewardInfo;
|
|
10
|
+
borrow?: RewardInfo;
|
|
11
|
+
}>;
|
|
12
|
+
export declare const getAaveUnderlyingSymbol: (_symbol?: string) => any;
|
|
13
|
+
export declare const getMerkleCampaigns: (chainId: NetworkNumber) => Promise<MerkleRewardMap>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.getMerkleCampaigns = exports.getAaveUnderlyingSymbol = void 0;
|
|
13
|
+
const utils_1 = require("../services/utils");
|
|
14
|
+
var OpportunityAction;
|
|
15
|
+
(function (OpportunityAction) {
|
|
16
|
+
OpportunityAction["LEND"] = "LEND";
|
|
17
|
+
OpportunityAction["BORROW"] = "BORROW";
|
|
18
|
+
})(OpportunityAction || (OpportunityAction = {}));
|
|
19
|
+
var OpportunityStatus;
|
|
20
|
+
(function (OpportunityStatus) {
|
|
21
|
+
OpportunityStatus["LIVE"] = "LIVE";
|
|
22
|
+
OpportunityStatus["PAST"] = "PAST";
|
|
23
|
+
OpportunityStatus["UPCOMING"] = "UPCOMING";
|
|
24
|
+
})(OpportunityStatus || (OpportunityStatus = {}));
|
|
25
|
+
const getAaveUnderlyingSymbol = (_symbol = '') => {
|
|
26
|
+
let symbol = _symbol
|
|
27
|
+
.replace(/^aEthLido/, '')
|
|
28
|
+
.replace(/^aEthEtherFi/, '')
|
|
29
|
+
.replace(/^aEth/, '')
|
|
30
|
+
.replace(/^aArb/, '')
|
|
31
|
+
.replace(/^aOpt/, '')
|
|
32
|
+
.replace(/^aBas/, '')
|
|
33
|
+
.replace(/^aLin/, '');
|
|
34
|
+
if (symbol.startsWith('a'))
|
|
35
|
+
symbol = symbol.slice(1);
|
|
36
|
+
return (0, utils_1.wethToEth)(symbol);
|
|
37
|
+
};
|
|
38
|
+
exports.getAaveUnderlyingSymbol = getAaveUnderlyingSymbol;
|
|
39
|
+
const getMerkleCampaigns = (chainId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
40
|
+
try {
|
|
41
|
+
const res = yield fetch('https://api.merkl.xyz/v4/opportunities?mainProtocolId=aave', {
|
|
42
|
+
signal: AbortSignal.timeout(utils_1.DEFAULT_TIMEOUT),
|
|
43
|
+
});
|
|
44
|
+
if (!res.ok)
|
|
45
|
+
throw new Error('Failed to fetch Merkle campaigns');
|
|
46
|
+
const opportunities = yield res.json();
|
|
47
|
+
const relevantOpportunities = opportunities
|
|
48
|
+
.filter((o) => o.chainId === chainId)
|
|
49
|
+
.filter((o) => o.liveCampaigns > 0);
|
|
50
|
+
return relevantOpportunities.reduce((acc, opportunity) => {
|
|
51
|
+
const rewardToken = opportunity.rewardsRecord.breakdowns[0].token;
|
|
52
|
+
if (opportunity.action === OpportunityAction.LEND) {
|
|
53
|
+
const supplyAToken = opportunity.explorerAddress.toLowerCase();
|
|
54
|
+
if (!acc[supplyAToken])
|
|
55
|
+
acc[supplyAToken] = {};
|
|
56
|
+
acc[supplyAToken].supply = {
|
|
57
|
+
apr: opportunity.apr,
|
|
58
|
+
rewardToken: rewardToken.address,
|
|
59
|
+
rewardTokenSymbol: (0, exports.getAaveUnderlyingSymbol)(rewardToken.symbol),
|
|
60
|
+
description: `Eligible for incentives through Merkl. \n${opportunity.description}`,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (opportunity.action === OpportunityAction.BORROW) {
|
|
64
|
+
const borrowAToken = opportunity.explorerAddress.toLowerCase();
|
|
65
|
+
if (!acc[borrowAToken])
|
|
66
|
+
acc[borrowAToken] = {};
|
|
67
|
+
acc[borrowAToken].borrow = {
|
|
68
|
+
apr: opportunity.apr,
|
|
69
|
+
rewardToken: rewardToken.address,
|
|
70
|
+
rewardTokenSymbol: (0, exports.getAaveUnderlyingSymbol)(rewardToken.symbol),
|
|
71
|
+
description: `Eligible for incentives through Merkl. \n${opportunity.description}`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return acc;
|
|
75
|
+
}, {});
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
console.error('Failed to fetch Merkle campaigns', e);
|
|
79
|
+
return {};
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
exports.getMerkleCampaigns = getMerkleCampaigns;
|
|
@@ -10,7 +10,7 @@ exports.aaveV1AssetsDefaultMarket = [
|
|
|
10
10
|
exports.aaveV2AssetsDefaultMarket = ['USDT', 'WBTC', 'ETH', 'YFI', 'ZRX', 'UNI', 'AAVE', 'BAT', 'BUSD', 'DAI', 'ENJ', 'KNCL', 'LINK', 'MANA', 'MKR', 'REN', 'SNX', 'SUSD', 'TUSD', 'USDC', 'CRV', 'GUSD', 'BAL', 'xSUSHI', 'RENFIL', 'RAI', 'AMPL', 'USDP', 'DPI', 'FRAX', 'FEI', 'stETH', 'ENS', 'UST', 'CVX', '1INCH', 'LUSD'];
|
|
11
11
|
exports.aaveV3AssetsDefaultMarketEth = [
|
|
12
12
|
'ETH', 'wstETH', 'WBTC', 'USDC', 'DAI', 'LINK', 'AAVE', 'cbETH', 'USDT', 'rETH', 'LUSD', 'CRV', 'MKR', 'SNX', 'BAL', 'UNI', 'LDO', 'ENS', '1INCH', 'FRAX', 'GHO', 'RPL', 'sDAI', 'STG', 'KNC', 'FXS', 'crvUSD', 'PYUSD', 'weETH', 'osETH', 'USDe', 'ETHx', 'sUSDe', 'tBTC', 'cbBTC', 'USDS', 'rsETH', 'LBTC', 'eBTC', 'RLUSD', 'PT eUSDe May', 'PT sUSDe July', 'USDtb',
|
|
13
|
-
'eUSDe', 'PT USDe July', 'PT eUSDe Aug', 'EURC', 'FBTC', 'PT sUSDe Sep', 'PT USDe Sep', 'tETH', 'ezETH', 'XAUt', 'PT sUSDe Nov',
|
|
13
|
+
'eUSDe', 'PT USDe July', 'PT eUSDe Aug', 'EURC', 'FBTC', 'PT sUSDe Sep', 'PT USDe Sep', 'tETH', 'ezETH', 'XAUt', 'PT sUSDe Nov', 'PT USDe Nov',
|
|
14
14
|
];
|
|
15
15
|
exports.aaveV3AssetsDefaultMarketOpt = [
|
|
16
16
|
'DAI', 'USDC.e', 'USDT', 'SUSD', 'AAVE', 'LINK', 'WBTC', 'ETH', 'OP', 'wstETH', 'LUSD', 'MAI', 'rETH', 'USDC',
|
package/cjs/staking/staking.js
CHANGED
|
@@ -65,7 +65,7 @@ const getApyFromDfsApi = (asset) => __awaiter(void 0, void 0, void 0, function*
|
|
|
65
65
|
return '0';
|
|
66
66
|
}
|
|
67
67
|
});
|
|
68
|
-
exports.STAKING_ASSETS = ['cbETH', 'wstETH', 'cbETH', 'rETH', 'sDAI', 'weETH', 'sUSDe', 'osETH', 'ezETH', 'ETHx', 'rsETH', 'pufETH', 'wrsETH', 'wsuperOETHb', 'sUSDS', 'tETH', 'PT sUSDe Sep', 'PT USDe Sep', 'PT sUSDe Nov'];
|
|
68
|
+
exports.STAKING_ASSETS = ['cbETH', 'wstETH', 'cbETH', 'rETH', 'sDAI', 'weETH', 'sUSDe', 'osETH', 'ezETH', 'ETHx', 'rsETH', 'pufETH', 'wrsETH', 'wsuperOETHb', 'sUSDS', 'tETH', 'PT sUSDe Sep', 'PT USDe Sep', 'PT sUSDe Nov', 'PT USDe Nov'];
|
|
69
69
|
exports.getStakingApy = (0, memoizee_1.default)((asset) => __awaiter(void 0, void 0, void 0, function* () {
|
|
70
70
|
try {
|
|
71
71
|
if (asset === 'stETH' || asset === 'wstETH')
|
|
@@ -112,6 +112,8 @@ exports.getStakingApy = (0, memoizee_1.default)((asset) => __awaiter(void 0, voi
|
|
|
112
112
|
return yield getApyFromDfsApi('USDe');
|
|
113
113
|
if (asset === 'PT sUSDe Nov')
|
|
114
114
|
return yield getApyFromDfsApi('PT sUSDe Nov');
|
|
115
|
+
if (asset === 'PT USDe Nov')
|
|
116
|
+
return yield getApyFromDfsApi('PT USDe Nov');
|
|
115
117
|
}
|
|
116
118
|
catch (e) {
|
|
117
119
|
console.error(`Failed to fetch APY for ${asset}`);
|
package/cjs/types/aave.d.ts
CHANGED
|
@@ -66,6 +66,7 @@ export interface IncentiveData {
|
|
|
66
66
|
token: string;
|
|
67
67
|
apy: string;
|
|
68
68
|
incentiveKind?: 'staking' | 'reward';
|
|
69
|
+
description?: string;
|
|
69
70
|
}
|
|
70
71
|
export interface AaveV3AssetData extends AaveAssetData {
|
|
71
72
|
isIsolated: boolean;
|
|
@@ -80,8 +81,8 @@ export interface AaveV3AssetData extends AaveAssetData {
|
|
|
80
81
|
isFlashLoanEnabled: boolean;
|
|
81
82
|
assetId: string | number | null;
|
|
82
83
|
liquidationBonus: string;
|
|
83
|
-
supplyIncentives
|
|
84
|
-
borrowIncentives
|
|
84
|
+
supplyIncentives: IncentiveData[];
|
|
85
|
+
borrowIncentives: IncentiveData[];
|
|
85
86
|
}
|
|
86
87
|
export type EModeCategoriesData = Record<number, EModeCategoryData>;
|
|
87
88
|
export type AaveAssetsData<T> = {
|
package/esm/aaveV3/index.js
CHANGED
|
@@ -17,6 +17,7 @@ import { ethToWeth, isEnabledOnBitmap, isLayer2Network, wethToEth, wethToEthByAd
|
|
|
17
17
|
import { getStakingApy, STAKING_ASSETS } from '../staking';
|
|
18
18
|
import { NetworkNumber, } from '../types/common';
|
|
19
19
|
import { getViemProvider, setViemBlockNumber } from '../services/viem';
|
|
20
|
+
import { getAaveUnderlyingSymbol, getMerkleCampaigns } from './rewards';
|
|
20
21
|
export const aaveV3EmodeCategoriesMapping = (extractedState, usedAssets) => {
|
|
21
22
|
const { eModeCategoriesData } = extractedState;
|
|
22
23
|
const usedAssetsValues = Object.values(usedAssets);
|
|
@@ -51,11 +52,12 @@ export function _getAaveV3MarketData(provider_1, network_1, market_1) {
|
|
|
51
52
|
const marketAddress = market.providerAddress;
|
|
52
53
|
const networksWithIncentives = [NetworkNumber.Eth, NetworkNumber.Arb, NetworkNumber.Opt, NetworkNumber.Linea];
|
|
53
54
|
// eslint-disable-next-line prefer-const
|
|
54
|
-
let [loanInfo, eModesInfo, isBorrowAllowed, rewardInfo] = yield Promise.all([
|
|
55
|
+
let [loanInfo, eModesInfo, isBorrowAllowed, rewardInfo, merkleRewardsMap] = yield Promise.all([
|
|
55
56
|
loanInfoContract.read.getFullTokensInfo([marketAddress, _addresses], setViemBlockNumber(blockNumber)),
|
|
56
57
|
loanInfoContract.read.getAllEmodes([marketAddress], setViemBlockNumber(blockNumber)),
|
|
57
58
|
loanInfoContract.read.isBorrowAllowed([marketAddress], setViemBlockNumber(blockNumber)), // Used on L2s check for PriceOracleSentinel (mainnet will always return true)
|
|
58
59
|
networksWithIncentives.includes(network) ? aaveIncentivesContract.read.getReservesIncentivesData([marketAddress], setViemBlockNumber(blockNumber)) : null,
|
|
60
|
+
getMerkleCampaigns(network),
|
|
59
61
|
]);
|
|
60
62
|
isBorrowAllowed = isLayer2Network(network) ? isBorrowAllowed : true;
|
|
61
63
|
const eModeCategoriesData = {};
|
|
@@ -137,10 +139,13 @@ export function _getAaveV3MarketData(provider_1, network_1, market_1) {
|
|
|
137
139
|
isolationModeBorrowingEnabled: tokenMarket.isolationModeBorrowingEnabled,
|
|
138
140
|
isFlashLoanEnabled: tokenMarket.isFlashLoanEnabled,
|
|
139
141
|
aTokenAddress: tokenMarket.aTokenAddress,
|
|
142
|
+
supplyIncentives: [],
|
|
143
|
+
borrowIncentives: [],
|
|
140
144
|
});
|
|
141
145
|
})));
|
|
142
146
|
// Get incentives data
|
|
143
|
-
yield Promise.all(assetsData.map((_market) => __awaiter(this, void 0, void 0, function* () {
|
|
147
|
+
yield Promise.all(assetsData.map((_market, index) => __awaiter(this, void 0, void 0, function* () {
|
|
148
|
+
var _a;
|
|
144
149
|
/* eslint-disable no-param-reassign */
|
|
145
150
|
// @ts-ignore
|
|
146
151
|
const rewardForMarket = rewardInfo === null || rewardInfo === void 0 ? void 0 : rewardInfo[_market.underlyingTokenAddress];
|
|
@@ -148,38 +153,44 @@ export function _getAaveV3MarketData(provider_1, network_1, market_1) {
|
|
|
148
153
|
if (isStakingAsset) {
|
|
149
154
|
_market.incentiveSupplyApy = yield getStakingApy(_market.symbol);
|
|
150
155
|
_market.incentiveSupplyToken = _market.symbol;
|
|
151
|
-
if (!_market.supplyIncentives) {
|
|
152
|
-
_market.supplyIncentives = [];
|
|
153
|
-
}
|
|
154
156
|
_market.supplyIncentives.push({
|
|
155
157
|
apy: _market.incentiveSupplyApy || '0',
|
|
156
158
|
token: _market.symbol,
|
|
157
159
|
incentiveKind: 'staking',
|
|
160
|
+
description: `Native ${_market.symbol} yield.`,
|
|
158
161
|
});
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
162
|
+
if (_market.canBeBorrowed) {
|
|
163
|
+
// when borrowing assets whose value increases over time
|
|
164
|
+
_market.incentiveBorrowApy = new Dec(_market.incentiveSupplyApy).mul(-1).toString();
|
|
165
|
+
_market.incentiveBorrowToken = _market.symbol;
|
|
166
|
+
_market.borrowIncentives.push({
|
|
167
|
+
apy: _market.incentiveBorrowApy,
|
|
168
|
+
token: _market.incentiveBorrowToken,
|
|
169
|
+
incentiveKind: 'reward',
|
|
170
|
+
description: `Due to the native yield of ${_market.symbol}, the value of the debt would increase over time.`,
|
|
171
|
+
});
|
|
165
172
|
}
|
|
166
|
-
_market.borrowIncentives.push({
|
|
167
|
-
apy: _market.incentiveBorrowApy,
|
|
168
|
-
token: _market.incentiveBorrowToken,
|
|
169
|
-
incentiveKind: 'reward',
|
|
170
|
-
});
|
|
171
173
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
_market.supplyIncentives = [];
|
|
176
|
-
}
|
|
174
|
+
const aTokenAddress = _market.aTokenAddress.toLowerCase(); // DEV: Should aTokenAddress be in AaveV3AssetData type?
|
|
175
|
+
if ((_a = merkleRewardsMap[aTokenAddress]) === null || _a === void 0 ? void 0 : _a.supply) {
|
|
176
|
+
const { apr, rewardTokenSymbol, description } = merkleRewardsMap[aTokenAddress].supply;
|
|
177
177
|
_market.supplyIncentives.push({
|
|
178
|
-
apy:
|
|
179
|
-
token:
|
|
178
|
+
apy: aprToApy(apr),
|
|
179
|
+
token: rewardTokenSymbol,
|
|
180
180
|
incentiveKind: 'reward',
|
|
181
|
+
description,
|
|
181
182
|
});
|
|
182
183
|
}
|
|
184
|
+
// const aTokenDebtAddress = '0xTODO';
|
|
185
|
+
// if (merkleRewardsMap[aTokenDebtAddress]?.supply) {
|
|
186
|
+
// const { apr, rewardTokenSymbol, description } = merkleRewardsMap[aTokenDebtAddress].supply;
|
|
187
|
+
// _market.borrowIncentives.push({
|
|
188
|
+
// apy: aprToApy(apr),
|
|
189
|
+
// token: rewardTokenSymbol,
|
|
190
|
+
// incentiveKind: 'reward',
|
|
191
|
+
// description,
|
|
192
|
+
// });
|
|
193
|
+
// }
|
|
183
194
|
if (!rewardForMarket)
|
|
184
195
|
return;
|
|
185
196
|
// @ts-ignore
|
|
@@ -202,13 +213,11 @@ export function _getAaveV3MarketData(provider_1, network_1, market_1) {
|
|
|
202
213
|
.toString();
|
|
203
214
|
_market.incentiveSupplyApy = new Dec(_market.incentiveSupplyApy || '0').add(rewardApy)
|
|
204
215
|
.toString();
|
|
205
|
-
if (!_market.supplyIncentives) {
|
|
206
|
-
_market.supplyIncentives = [];
|
|
207
|
-
}
|
|
208
216
|
_market.supplyIncentives.push({
|
|
209
|
-
token: supplyRewardData.rewardTokenSymbol,
|
|
217
|
+
token: getAaveUnderlyingSymbol(supplyRewardData.rewardTokenSymbol),
|
|
210
218
|
apy: rewardApy,
|
|
211
219
|
incentiveKind: 'reward',
|
|
220
|
+
description: 'Eligible for protocol-level incentives.',
|
|
212
221
|
});
|
|
213
222
|
}
|
|
214
223
|
});
|
|
@@ -231,13 +240,11 @@ export function _getAaveV3MarketData(provider_1, network_1, market_1) {
|
|
|
231
240
|
.toString();
|
|
232
241
|
_market.incentiveBorrowApy = new Dec(_market.incentiveBorrowApy || '0').add(rewardApy)
|
|
233
242
|
.toString();
|
|
234
|
-
if (!_market.borrowIncentives) {
|
|
235
|
-
_market.borrowIncentives = [];
|
|
236
|
-
}
|
|
237
243
|
_market.borrowIncentives.push({
|
|
238
|
-
token: borrowRewardData.rewardTokenSymbol,
|
|
244
|
+
token: getAaveUnderlyingSymbol(borrowRewardData.rewardTokenSymbol),
|
|
239
245
|
apy: rewardApy,
|
|
240
246
|
incentiveKind: 'reward',
|
|
247
|
+
description: 'Eligible for protocol-level incentives.',
|
|
241
248
|
});
|
|
242
249
|
}
|
|
243
250
|
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { EthAddress, NetworkNumber } from '../types/common';
|
|
2
|
+
type RewardInfo = {
|
|
3
|
+
apr: number;
|
|
4
|
+
rewardToken: EthAddress;
|
|
5
|
+
rewardTokenSymbol: string;
|
|
6
|
+
description: string;
|
|
7
|
+
};
|
|
8
|
+
type MerkleRewardMap = Record<EthAddress, {
|
|
9
|
+
supply?: RewardInfo;
|
|
10
|
+
borrow?: RewardInfo;
|
|
11
|
+
}>;
|
|
12
|
+
export declare const getAaveUnderlyingSymbol: (_symbol?: string) => any;
|
|
13
|
+
export declare const getMerkleCampaigns: (chainId: NetworkNumber) => Promise<MerkleRewardMap>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
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 { DEFAULT_TIMEOUT, wethToEth } from '../services/utils';
|
|
11
|
+
var OpportunityAction;
|
|
12
|
+
(function (OpportunityAction) {
|
|
13
|
+
OpportunityAction["LEND"] = "LEND";
|
|
14
|
+
OpportunityAction["BORROW"] = "BORROW";
|
|
15
|
+
})(OpportunityAction || (OpportunityAction = {}));
|
|
16
|
+
var OpportunityStatus;
|
|
17
|
+
(function (OpportunityStatus) {
|
|
18
|
+
OpportunityStatus["LIVE"] = "LIVE";
|
|
19
|
+
OpportunityStatus["PAST"] = "PAST";
|
|
20
|
+
OpportunityStatus["UPCOMING"] = "UPCOMING";
|
|
21
|
+
})(OpportunityStatus || (OpportunityStatus = {}));
|
|
22
|
+
export const getAaveUnderlyingSymbol = (_symbol = '') => {
|
|
23
|
+
let symbol = _symbol
|
|
24
|
+
.replace(/^aEthLido/, '')
|
|
25
|
+
.replace(/^aEthEtherFi/, '')
|
|
26
|
+
.replace(/^aEth/, '')
|
|
27
|
+
.replace(/^aArb/, '')
|
|
28
|
+
.replace(/^aOpt/, '')
|
|
29
|
+
.replace(/^aBas/, '')
|
|
30
|
+
.replace(/^aLin/, '');
|
|
31
|
+
if (symbol.startsWith('a'))
|
|
32
|
+
symbol = symbol.slice(1);
|
|
33
|
+
return wethToEth(symbol);
|
|
34
|
+
};
|
|
35
|
+
export const getMerkleCampaigns = (chainId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
36
|
+
try {
|
|
37
|
+
const res = yield fetch('https://api.merkl.xyz/v4/opportunities?mainProtocolId=aave', {
|
|
38
|
+
signal: AbortSignal.timeout(DEFAULT_TIMEOUT),
|
|
39
|
+
});
|
|
40
|
+
if (!res.ok)
|
|
41
|
+
throw new Error('Failed to fetch Merkle campaigns');
|
|
42
|
+
const opportunities = yield res.json();
|
|
43
|
+
const relevantOpportunities = opportunities
|
|
44
|
+
.filter((o) => o.chainId === chainId)
|
|
45
|
+
.filter((o) => o.liveCampaigns > 0);
|
|
46
|
+
return relevantOpportunities.reduce((acc, opportunity) => {
|
|
47
|
+
const rewardToken = opportunity.rewardsRecord.breakdowns[0].token;
|
|
48
|
+
if (opportunity.action === OpportunityAction.LEND) {
|
|
49
|
+
const supplyAToken = opportunity.explorerAddress.toLowerCase();
|
|
50
|
+
if (!acc[supplyAToken])
|
|
51
|
+
acc[supplyAToken] = {};
|
|
52
|
+
acc[supplyAToken].supply = {
|
|
53
|
+
apr: opportunity.apr,
|
|
54
|
+
rewardToken: rewardToken.address,
|
|
55
|
+
rewardTokenSymbol: getAaveUnderlyingSymbol(rewardToken.symbol),
|
|
56
|
+
description: `Eligible for incentives through Merkl. \n${opportunity.description}`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (opportunity.action === OpportunityAction.BORROW) {
|
|
60
|
+
const borrowAToken = opportunity.explorerAddress.toLowerCase();
|
|
61
|
+
if (!acc[borrowAToken])
|
|
62
|
+
acc[borrowAToken] = {};
|
|
63
|
+
acc[borrowAToken].borrow = {
|
|
64
|
+
apr: opportunity.apr,
|
|
65
|
+
rewardToken: rewardToken.address,
|
|
66
|
+
rewardTokenSymbol: getAaveUnderlyingSymbol(rewardToken.symbol),
|
|
67
|
+
description: `Eligible for incentives through Merkl. \n${opportunity.description}`,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return acc;
|
|
71
|
+
}, {});
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
console.error('Failed to fetch Merkle campaigns', e);
|
|
75
|
+
return {};
|
|
76
|
+
}
|
|
77
|
+
});
|
|
@@ -7,7 +7,7 @@ export const aaveV1AssetsDefaultMarket = [
|
|
|
7
7
|
export const aaveV2AssetsDefaultMarket = ['USDT', 'WBTC', 'ETH', 'YFI', 'ZRX', 'UNI', 'AAVE', 'BAT', 'BUSD', 'DAI', 'ENJ', 'KNCL', 'LINK', 'MANA', 'MKR', 'REN', 'SNX', 'SUSD', 'TUSD', 'USDC', 'CRV', 'GUSD', 'BAL', 'xSUSHI', 'RENFIL', 'RAI', 'AMPL', 'USDP', 'DPI', 'FRAX', 'FEI', 'stETH', 'ENS', 'UST', 'CVX', '1INCH', 'LUSD'];
|
|
8
8
|
export const aaveV3AssetsDefaultMarketEth = [
|
|
9
9
|
'ETH', 'wstETH', 'WBTC', 'USDC', 'DAI', 'LINK', 'AAVE', 'cbETH', 'USDT', 'rETH', 'LUSD', 'CRV', 'MKR', 'SNX', 'BAL', 'UNI', 'LDO', 'ENS', '1INCH', 'FRAX', 'GHO', 'RPL', 'sDAI', 'STG', 'KNC', 'FXS', 'crvUSD', 'PYUSD', 'weETH', 'osETH', 'USDe', 'ETHx', 'sUSDe', 'tBTC', 'cbBTC', 'USDS', 'rsETH', 'LBTC', 'eBTC', 'RLUSD', 'PT eUSDe May', 'PT sUSDe July', 'USDtb',
|
|
10
|
-
'eUSDe', 'PT USDe July', 'PT eUSDe Aug', 'EURC', 'FBTC', 'PT sUSDe Sep', 'PT USDe Sep', 'tETH', 'ezETH', 'XAUt', 'PT sUSDe Nov',
|
|
10
|
+
'eUSDe', 'PT USDe July', 'PT eUSDe Aug', 'EURC', 'FBTC', 'PT sUSDe Sep', 'PT USDe Sep', 'tETH', 'ezETH', 'XAUt', 'PT sUSDe Nov', 'PT USDe Nov',
|
|
11
11
|
];
|
|
12
12
|
export const aaveV3AssetsDefaultMarketOpt = [
|
|
13
13
|
'DAI', 'USDC.e', 'USDT', 'SUSD', 'AAVE', 'LINK', 'WBTC', 'ETH', 'OP', 'wstETH', 'LUSD', 'MAI', 'rETH', 'USDC',
|
package/esm/staking/staking.js
CHANGED
|
@@ -59,7 +59,7 @@ const getApyFromDfsApi = (asset) => __awaiter(void 0, void 0, void 0, function*
|
|
|
59
59
|
return '0';
|
|
60
60
|
}
|
|
61
61
|
});
|
|
62
|
-
export const STAKING_ASSETS = ['cbETH', 'wstETH', 'cbETH', 'rETH', 'sDAI', 'weETH', 'sUSDe', 'osETH', 'ezETH', 'ETHx', 'rsETH', 'pufETH', 'wrsETH', 'wsuperOETHb', 'sUSDS', 'tETH', 'PT sUSDe Sep', 'PT USDe Sep', 'PT sUSDe Nov'];
|
|
62
|
+
export const STAKING_ASSETS = ['cbETH', 'wstETH', 'cbETH', 'rETH', 'sDAI', 'weETH', 'sUSDe', 'osETH', 'ezETH', 'ETHx', 'rsETH', 'pufETH', 'wrsETH', 'wsuperOETHb', 'sUSDS', 'tETH', 'PT sUSDe Sep', 'PT USDe Sep', 'PT sUSDe Nov', 'PT USDe Nov'];
|
|
63
63
|
export const getStakingApy = memoize((asset) => __awaiter(void 0, void 0, void 0, function* () {
|
|
64
64
|
try {
|
|
65
65
|
if (asset === 'stETH' || asset === 'wstETH')
|
|
@@ -106,6 +106,8 @@ export const getStakingApy = memoize((asset) => __awaiter(void 0, void 0, void 0
|
|
|
106
106
|
return yield getApyFromDfsApi('USDe');
|
|
107
107
|
if (asset === 'PT sUSDe Nov')
|
|
108
108
|
return yield getApyFromDfsApi('PT sUSDe Nov');
|
|
109
|
+
if (asset === 'PT USDe Nov')
|
|
110
|
+
return yield getApyFromDfsApi('PT USDe Nov');
|
|
109
111
|
}
|
|
110
112
|
catch (e) {
|
|
111
113
|
console.error(`Failed to fetch APY for ${asset}`);
|
package/esm/types/aave.d.ts
CHANGED
|
@@ -66,6 +66,7 @@ export interface IncentiveData {
|
|
|
66
66
|
token: string;
|
|
67
67
|
apy: string;
|
|
68
68
|
incentiveKind?: 'staking' | 'reward';
|
|
69
|
+
description?: string;
|
|
69
70
|
}
|
|
70
71
|
export interface AaveV3AssetData extends AaveAssetData {
|
|
71
72
|
isIsolated: boolean;
|
|
@@ -80,8 +81,8 @@ export interface AaveV3AssetData extends AaveAssetData {
|
|
|
80
81
|
isFlashLoanEnabled: boolean;
|
|
81
82
|
assetId: string | number | null;
|
|
82
83
|
liquidationBonus: string;
|
|
83
|
-
supplyIncentives
|
|
84
|
-
borrowIncentives
|
|
84
|
+
supplyIncentives: IncentiveData[];
|
|
85
|
+
borrowIncentives: IncentiveData[];
|
|
85
86
|
}
|
|
86
87
|
export type EModeCategoriesData = Record<number, EModeCategoryData>;
|
|
87
88
|
export type AaveAssetsData<T> = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defisaver/positions-sdk",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.15-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.1",
|
|
25
25
|
"@types/lodash": "^4.17.15",
|
|
26
26
|
"@types/memoizee": "^0.4.12",
|
|
27
27
|
"decimal.js": "^10.6.0",
|
package/src/aaveV3/index.ts
CHANGED
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
Blockish, EthAddress, EthereumProvider, NetworkNumber, PositionBalances,
|
|
30
30
|
} from '../types/common';
|
|
31
31
|
import { getViemProvider, setViemBlockNumber } from '../services/viem';
|
|
32
|
+
import { getAaveUnderlyingSymbol, getMerkleCampaigns } from './rewards';
|
|
32
33
|
|
|
33
34
|
export const aaveV3EmodeCategoriesMapping = (extractedState: any, usedAssets: AaveV3UsedAssets) => {
|
|
34
35
|
const { eModeCategoriesData }: { assetsData: AaveV3AssetsData, eModeCategoriesData: EModeCategoriesData } = extractedState;
|
|
@@ -70,11 +71,12 @@ export async function _getAaveV3MarketData(provider: Client, network: NetworkNum
|
|
|
70
71
|
const networksWithIncentives = [NetworkNumber.Eth, NetworkNumber.Arb, NetworkNumber.Opt, NetworkNumber.Linea];
|
|
71
72
|
|
|
72
73
|
// eslint-disable-next-line prefer-const
|
|
73
|
-
let [loanInfo, eModesInfo, isBorrowAllowed, rewardInfo] = await Promise.all([
|
|
74
|
+
let [loanInfo, eModesInfo, isBorrowAllowed, rewardInfo, merkleRewardsMap] = await Promise.all([
|
|
74
75
|
loanInfoContract.read.getFullTokensInfo([marketAddress, _addresses as EthAddress[]], setViemBlockNumber(blockNumber)),
|
|
75
76
|
loanInfoContract.read.getAllEmodes([marketAddress], setViemBlockNumber(blockNumber)),
|
|
76
77
|
loanInfoContract.read.isBorrowAllowed([marketAddress], setViemBlockNumber(blockNumber)), // Used on L2s check for PriceOracleSentinel (mainnet will always return true)
|
|
77
78
|
networksWithIncentives.includes(network) ? aaveIncentivesContract.read.getReservesIncentivesData([marketAddress], setViemBlockNumber(blockNumber)) : null,
|
|
79
|
+
getMerkleCampaigns(network),
|
|
78
80
|
]);
|
|
79
81
|
isBorrowAllowed = isLayer2Network(network) ? isBorrowAllowed : true;
|
|
80
82
|
|
|
@@ -160,54 +162,63 @@ export async function _getAaveV3MarketData(provider: Client, network: NetworkNum
|
|
|
160
162
|
isolationModeBorrowingEnabled: tokenMarket.isolationModeBorrowingEnabled,
|
|
161
163
|
isFlashLoanEnabled: tokenMarket.isFlashLoanEnabled,
|
|
162
164
|
aTokenAddress: tokenMarket.aTokenAddress,
|
|
165
|
+
supplyIncentives: [],
|
|
166
|
+
borrowIncentives: [],
|
|
163
167
|
});
|
|
164
|
-
})
|
|
165
|
-
|
|
168
|
+
}),
|
|
169
|
+
);
|
|
166
170
|
|
|
167
171
|
// Get incentives data
|
|
168
|
-
await Promise.all(assetsData.map(async (_market: AaveV3AssetData) => {
|
|
172
|
+
await Promise.all(assetsData.map(async (_market: AaveV3AssetData, index) => {
|
|
169
173
|
/* eslint-disable no-param-reassign */
|
|
170
174
|
// @ts-ignore
|
|
171
175
|
const rewardForMarket = rewardInfo?.[_market.underlyingTokenAddress];
|
|
172
176
|
const isStakingAsset = STAKING_ASSETS.includes(_market.symbol);
|
|
177
|
+
|
|
173
178
|
if (isStakingAsset) {
|
|
174
179
|
_market.incentiveSupplyApy = await getStakingApy(_market.symbol);
|
|
175
180
|
_market.incentiveSupplyToken = _market.symbol;
|
|
176
|
-
if (!_market.supplyIncentives) {
|
|
177
|
-
_market.supplyIncentives = [];
|
|
178
|
-
}
|
|
179
181
|
_market.supplyIncentives.push({
|
|
180
182
|
apy: _market.incentiveSupplyApy || '0',
|
|
181
183
|
token: _market.symbol,
|
|
182
184
|
incentiveKind: 'staking',
|
|
185
|
+
description: `Native ${_market.symbol} yield.`,
|
|
183
186
|
});
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
187
|
+
if (_market.canBeBorrowed) {
|
|
188
|
+
// when borrowing assets whose value increases over time
|
|
189
|
+
_market.incentiveBorrowApy = new Dec(_market.incentiveSupplyApy).mul(-1).toString();
|
|
190
|
+
_market.incentiveBorrowToken = _market.symbol;
|
|
191
|
+
_market.borrowIncentives.push({
|
|
192
|
+
apy: _market.incentiveBorrowApy,
|
|
193
|
+
token: _market.incentiveBorrowToken,
|
|
194
|
+
incentiveKind: 'reward',
|
|
195
|
+
description: `Due to the native yield of ${_market.symbol}, the value of the debt would increase over time.`,
|
|
196
|
+
});
|
|
191
197
|
}
|
|
192
|
-
_market.borrowIncentives.push({
|
|
193
|
-
apy: _market.incentiveBorrowApy,
|
|
194
|
-
token: _market.incentiveBorrowToken!!,
|
|
195
|
-
incentiveKind: 'reward',
|
|
196
|
-
});
|
|
197
198
|
}
|
|
198
199
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
_market.supplyIncentives = [];
|
|
203
|
-
}
|
|
200
|
+
const aTokenAddress = (_market as any).aTokenAddress.toLowerCase(); // DEV: Should aTokenAddress be in AaveV3AssetData type?
|
|
201
|
+
if (merkleRewardsMap[aTokenAddress]?.supply) {
|
|
202
|
+
const { apr, rewardTokenSymbol, description } = merkleRewardsMap[aTokenAddress].supply;
|
|
204
203
|
_market.supplyIncentives.push({
|
|
205
|
-
apy:
|
|
206
|
-
token:
|
|
204
|
+
apy: aprToApy(apr),
|
|
205
|
+
token: rewardTokenSymbol,
|
|
207
206
|
incentiveKind: 'reward',
|
|
207
|
+
description,
|
|
208
208
|
});
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
// const aTokenDebtAddress = '0xTODO'; // variableDebtTokenAddress is not in loanInfo ATM
|
|
212
|
+
// if (merkleRewardsMap[aTokenDebtAddress]?.supply) {
|
|
213
|
+
// const { apr, rewardTokenSymbol, description } = merkleRewardsMap[aTokenDebtAddress].supply;
|
|
214
|
+
// _market.borrowIncentives.push({
|
|
215
|
+
// apy: aprToApy(apr),
|
|
216
|
+
// token: rewardTokenSymbol,
|
|
217
|
+
// incentiveKind: 'reward',
|
|
218
|
+
// description,
|
|
219
|
+
// });
|
|
220
|
+
// }
|
|
221
|
+
|
|
211
222
|
if (!rewardForMarket) return;
|
|
212
223
|
// @ts-ignore
|
|
213
224
|
rewardForMarket.aIncentiveData.rewardsTokenInformation.forEach(supplyRewardData => {
|
|
@@ -227,14 +238,11 @@ export async function _getAaveV3MarketData(provider: Client, network: NetworkNum
|
|
|
227
238
|
.toString();
|
|
228
239
|
_market.incentiveSupplyApy = new Dec(_market.incentiveSupplyApy || '0').add(rewardApy)
|
|
229
240
|
.toString();
|
|
230
|
-
|
|
231
|
-
if (!_market.supplyIncentives) {
|
|
232
|
-
_market.supplyIncentives = [];
|
|
233
|
-
}
|
|
234
241
|
_market.supplyIncentives.push({
|
|
235
|
-
token: supplyRewardData.rewardTokenSymbol,
|
|
242
|
+
token: getAaveUnderlyingSymbol(supplyRewardData.rewardTokenSymbol),
|
|
236
243
|
apy: rewardApy,
|
|
237
244
|
incentiveKind: 'reward',
|
|
245
|
+
description: 'Eligible for protocol-level incentives.',
|
|
238
246
|
});
|
|
239
247
|
}
|
|
240
248
|
});
|
|
@@ -255,14 +263,11 @@ export async function _getAaveV3MarketData(provider: Client, network: NetworkNum
|
|
|
255
263
|
.toString();
|
|
256
264
|
_market.incentiveBorrowApy = new Dec(_market.incentiveBorrowApy || '0').add(rewardApy)
|
|
257
265
|
.toString();
|
|
258
|
-
|
|
259
|
-
if (!_market.borrowIncentives) {
|
|
260
|
-
_market.borrowIncentives = [];
|
|
261
|
-
}
|
|
262
266
|
_market.borrowIncentives.push({
|
|
263
|
-
token: borrowRewardData.rewardTokenSymbol,
|
|
267
|
+
token: getAaveUnderlyingSymbol(borrowRewardData.rewardTokenSymbol),
|
|
264
268
|
apy: rewardApy,
|
|
265
269
|
incentiveKind: 'reward',
|
|
270
|
+
description: 'Eligible for protocol-level incentives.',
|
|
266
271
|
});
|
|
267
272
|
}
|
|
268
273
|
});
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { DEFAULT_TIMEOUT, wethToEth } from '../services/utils';
|
|
2
|
+
import { EthAddress, NetworkNumber } from '../types/common';
|
|
3
|
+
|
|
4
|
+
enum OpportunityAction {
|
|
5
|
+
LEND = 'LEND',
|
|
6
|
+
BORROW = 'BORROW',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
enum OpportunityStatus {
|
|
10
|
+
LIVE = 'LIVE',
|
|
11
|
+
PAST = 'PAST',
|
|
12
|
+
UPCOMING = 'UPCOMING',
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type MerklOpportunity = {
|
|
16
|
+
chainId: number;
|
|
17
|
+
type: string;
|
|
18
|
+
identifier: EthAddress;
|
|
19
|
+
name: string;
|
|
20
|
+
status: OpportunityStatus;
|
|
21
|
+
action: OpportunityAction;
|
|
22
|
+
tvl: number;
|
|
23
|
+
apr: number;
|
|
24
|
+
dailyRewards: number;
|
|
25
|
+
tags: [];
|
|
26
|
+
id: string;
|
|
27
|
+
explorerAddress?: EthAddress;
|
|
28
|
+
tokens: {
|
|
29
|
+
id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
chainId: number;
|
|
32
|
+
address: EthAddress;
|
|
33
|
+
decimals: number;
|
|
34
|
+
icon: string;
|
|
35
|
+
verified: boolean;
|
|
36
|
+
isTest: boolean;
|
|
37
|
+
price: number;
|
|
38
|
+
symbol: string;
|
|
39
|
+
}[];
|
|
40
|
+
rewardsRecord: {
|
|
41
|
+
id: string;
|
|
42
|
+
total: number;
|
|
43
|
+
timestamp: string;
|
|
44
|
+
breakdowns: {
|
|
45
|
+
token: {
|
|
46
|
+
id: string;
|
|
47
|
+
name: string;
|
|
48
|
+
chainId: number;
|
|
49
|
+
address: string;
|
|
50
|
+
decimals: number;
|
|
51
|
+
symbol: string;
|
|
52
|
+
displaySymbol: string;
|
|
53
|
+
icon: string;
|
|
54
|
+
verified: boolean;
|
|
55
|
+
isTest: boolean;
|
|
56
|
+
type: string;
|
|
57
|
+
isNative: boolean;
|
|
58
|
+
price: number;
|
|
59
|
+
};
|
|
60
|
+
amount: string;
|
|
61
|
+
value: number;
|
|
62
|
+
distributionType: string;
|
|
63
|
+
id: string;
|
|
64
|
+
campaignId: string;
|
|
65
|
+
dailyRewardsRecordId: string;
|
|
66
|
+
}[];
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
type RewardInfo = { apr: number; rewardToken: EthAddress; rewardTokenSymbol: string, description: string };
|
|
71
|
+
type MerkleRewardMap = Record<EthAddress, { supply?: RewardInfo; borrow?: RewardInfo }>;
|
|
72
|
+
|
|
73
|
+
export const getAaveUnderlyingSymbol = (_symbol = '') => {
|
|
74
|
+
let symbol = _symbol
|
|
75
|
+
.replace(/^aEthLido/, '')
|
|
76
|
+
.replace(/^aEthEtherFi/, '')
|
|
77
|
+
.replace(/^aEth/, '')
|
|
78
|
+
.replace(/^aArb/, '')
|
|
79
|
+
.replace(/^aOpt/, '')
|
|
80
|
+
.replace(/^aBas/, '')
|
|
81
|
+
.replace(/^aLin/, '');
|
|
82
|
+
if (symbol.startsWith('a')) symbol = symbol.slice(1);
|
|
83
|
+
return wethToEth(symbol);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const getMerkleCampaigns = async (chainId: NetworkNumber): Promise<MerkleRewardMap> => {
|
|
87
|
+
try {
|
|
88
|
+
const res = await fetch('https://api.merkl.xyz/v4/opportunities?mainProtocolId=aave', {
|
|
89
|
+
signal: AbortSignal.timeout(DEFAULT_TIMEOUT),
|
|
90
|
+
});
|
|
91
|
+
if (!res.ok) throw new Error('Failed to fetch Merkle campaigns');
|
|
92
|
+
const opportunities = await res.json() as MerklOpportunity[];
|
|
93
|
+
const relevantOpportunities = opportunities
|
|
94
|
+
.filter((o: any) => o.chainId === chainId)
|
|
95
|
+
.filter((o: any) => o.liveCampaigns > 0);
|
|
96
|
+
return relevantOpportunities.reduce((acc: any, opportunity: any) => {
|
|
97
|
+
const rewardToken = opportunity.rewardsRecord.breakdowns[0].token;
|
|
98
|
+
if (opportunity.action === OpportunityAction.LEND) {
|
|
99
|
+
const supplyAToken = opportunity.explorerAddress.toLowerCase() as EthAddress;
|
|
100
|
+
if (!acc[supplyAToken]) acc[supplyAToken] = {};
|
|
101
|
+
acc[supplyAToken].supply = {
|
|
102
|
+
apr: opportunity.apr,
|
|
103
|
+
rewardToken: rewardToken.address,
|
|
104
|
+
rewardTokenSymbol: getAaveUnderlyingSymbol(rewardToken.symbol),
|
|
105
|
+
description: `Eligible for incentives through Merkl. \n${opportunity.description}`,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
if (opportunity.action === OpportunityAction.BORROW) {
|
|
109
|
+
const borrowAToken = opportunity.explorerAddress.toLowerCase() as EthAddress;
|
|
110
|
+
if (!acc[borrowAToken]) acc[borrowAToken] = {};
|
|
111
|
+
acc[borrowAToken].borrow = {
|
|
112
|
+
apr: opportunity.apr,
|
|
113
|
+
rewardToken: rewardToken.address,
|
|
114
|
+
rewardTokenSymbol: getAaveUnderlyingSymbol(rewardToken.symbol),
|
|
115
|
+
description: `Eligible for incentives through Merkl. \n${opportunity.description}`,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
return acc;
|
|
119
|
+
}, {} as MerkleRewardMap);
|
|
120
|
+
} catch (e) {
|
|
121
|
+
console.error('Failed to fetch Merkle campaigns', e);
|
|
122
|
+
return {};
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
@@ -10,7 +10,7 @@ export const aaveV2AssetsDefaultMarket = ['USDT', 'WBTC', 'ETH', 'YFI', 'ZRX', '
|
|
|
10
10
|
|
|
11
11
|
export const aaveV3AssetsDefaultMarketEth = [
|
|
12
12
|
'ETH', 'wstETH', 'WBTC', 'USDC', 'DAI', 'LINK', 'AAVE', 'cbETH', 'USDT', 'rETH', 'LUSD', 'CRV', 'MKR', 'SNX', 'BAL', 'UNI', 'LDO', 'ENS', '1INCH', 'FRAX', 'GHO', 'RPL', 'sDAI', 'STG', 'KNC', 'FXS', 'crvUSD', 'PYUSD', 'weETH', 'osETH', 'USDe', 'ETHx', 'sUSDe', 'tBTC', 'cbBTC', 'USDS', 'rsETH', 'LBTC', 'eBTC', 'RLUSD', 'PT eUSDe May', 'PT sUSDe July', 'USDtb',
|
|
13
|
-
'eUSDe', 'PT USDe July', 'PT eUSDe Aug', 'EURC', 'FBTC', 'PT sUSDe Sep', 'PT USDe Sep', 'tETH', 'ezETH', 'XAUt', 'PT sUSDe Nov',
|
|
13
|
+
'eUSDe', 'PT USDe July', 'PT eUSDe Aug', 'EURC', 'FBTC', 'PT sUSDe Sep', 'PT USDe Sep', 'tETH', 'ezETH', 'XAUt', 'PT sUSDe Nov', 'PT USDe Nov',
|
|
14
14
|
];
|
|
15
15
|
export const aaveV3AssetsDefaultMarketOpt = [
|
|
16
16
|
'DAI', 'USDC.e', 'USDT', 'SUSD', 'AAVE', 'LINK', 'WBTC', 'ETH', 'OP', 'wstETH', 'LUSD', 'MAI', 'rETH', 'USDC',
|
package/src/staking/staking.ts
CHANGED
|
@@ -54,7 +54,7 @@ const getApyFromDfsApi = async (asset: string) => {
|
|
|
54
54
|
}
|
|
55
55
|
};
|
|
56
56
|
|
|
57
|
-
export const STAKING_ASSETS = ['cbETH', 'wstETH', 'cbETH', 'rETH', 'sDAI', 'weETH', 'sUSDe', 'osETH', 'ezETH', 'ETHx', 'rsETH', 'pufETH', 'wrsETH', 'wsuperOETHb', 'sUSDS', 'tETH', 'PT sUSDe Sep', 'PT USDe Sep', 'PT sUSDe Nov'];
|
|
57
|
+
export const STAKING_ASSETS = ['cbETH', 'wstETH', 'cbETH', 'rETH', 'sDAI', 'weETH', 'sUSDe', 'osETH', 'ezETH', 'ETHx', 'rsETH', 'pufETH', 'wrsETH', 'wsuperOETHb', 'sUSDS', 'tETH', 'PT sUSDe Sep', 'PT USDe Sep', 'PT sUSDe Nov', 'PT USDe Nov'];
|
|
58
58
|
|
|
59
59
|
export const getStakingApy = memoize(async (asset: string) => {
|
|
60
60
|
try {
|
|
@@ -80,6 +80,7 @@ export const getStakingApy = memoize(async (asset: string) => {
|
|
|
80
80
|
if (asset === 'tETH') return await getApyFromDfsApi('tETH');
|
|
81
81
|
if (asset === 'USDe') return await getApyFromDfsApi('USDe');
|
|
82
82
|
if (asset === 'PT sUSDe Nov') return await getApyFromDfsApi('PT sUSDe Nov');
|
|
83
|
+
if (asset === 'PT USDe Nov') return await getApyFromDfsApi('PT USDe Nov');
|
|
83
84
|
} catch (e) {
|
|
84
85
|
console.error(`Failed to fetch APY for ${asset}`);
|
|
85
86
|
}
|
package/src/types/aave.ts
CHANGED
|
@@ -74,6 +74,7 @@ export interface IncentiveData {
|
|
|
74
74
|
token: string,
|
|
75
75
|
apy: string,
|
|
76
76
|
incentiveKind?: 'staking' | 'reward';
|
|
77
|
+
description?: string;
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
export interface AaveV3AssetData extends AaveAssetData {
|
|
@@ -89,8 +90,8 @@ export interface AaveV3AssetData extends AaveAssetData {
|
|
|
89
90
|
isFlashLoanEnabled: boolean,
|
|
90
91
|
assetId: string | number | null,
|
|
91
92
|
liquidationBonus: string,
|
|
92
|
-
supplyIncentives
|
|
93
|
-
borrowIncentives
|
|
93
|
+
supplyIncentives: IncentiveData[];
|
|
94
|
+
borrowIncentives: IncentiveData[];
|
|
94
95
|
}
|
|
95
96
|
|
|
96
97
|
export type EModeCategoriesData = Record<number, EModeCategoryData>;
|