@defisaver/positions-sdk 1.0.21-dev-2 → 1.0.21-dev-3

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.
Files changed (42) hide show
  1. package/cjs/aaveV3/index.js +4 -4
  2. package/cjs/index.d.ts +2 -1
  3. package/cjs/index.js +3 -1
  4. package/cjs/markets/morphoBlue/index.js +1 -1
  5. package/cjs/morphoBlue/index.js +35 -15
  6. package/cjs/rewards/index.d.ts +1 -0
  7. package/cjs/rewards/index.js +17 -0
  8. package/cjs/rewards/rewards.d.ts +12 -0
  9. package/cjs/rewards/rewards.js +46 -0
  10. package/cjs/staking/staking.js +45 -3
  11. package/cjs/types/aave.d.ts +1 -6
  12. package/cjs/types/common.d.ts +11 -0
  13. package/cjs/types/common.js +6 -1
  14. package/cjs/types/morphoBlue.d.ts +3 -5
  15. package/cjs/types/spark.d.ts +1 -2
  16. package/esm/aaveV3/index.js +5 -5
  17. package/esm/index.d.ts +2 -1
  18. package/esm/index.js +2 -1
  19. package/esm/markets/morphoBlue/index.js +1 -1
  20. package/esm/morphoBlue/index.js +36 -16
  21. package/esm/rewards/index.d.ts +1 -0
  22. package/esm/rewards/index.js +1 -0
  23. package/esm/rewards/rewards.d.ts +12 -0
  24. package/esm/rewards/rewards.js +40 -0
  25. package/esm/staking/staking.js +45 -3
  26. package/esm/types/aave.d.ts +1 -6
  27. package/esm/types/common.d.ts +11 -0
  28. package/esm/types/common.js +5 -0
  29. package/esm/types/morphoBlue.d.ts +3 -5
  30. package/esm/types/spark.d.ts +1 -2
  31. package/package.json +2 -2
  32. package/src/aaveV3/index.ts +5 -5
  33. package/src/index.ts +2 -0
  34. package/src/markets/morphoBlue/index.ts +1 -1
  35. package/src/morphoBlue/index.ts +35 -15
  36. package/src/rewards/index.ts +1 -0
  37. package/src/rewards/rewards.ts +32 -0
  38. package/src/staking/staking.ts +41 -3
  39. package/src/types/aave.ts +1 -6
  40. package/src/types/common.ts +14 -1
  41. package/src/types/morphoBlue.ts +3 -5
  42. package/src/types/spark.ts +1 -1
@@ -198,7 +198,7 @@ function getAaveV3MarketData(web3, network, market, defaultWeb3) {
198
198
  _market.supplyIncentives.push({
199
199
  apy: _market.incentiveSupplyApy || '0',
200
200
  token: _market.symbol,
201
- incentiveKind: 'staking',
201
+ incentiveKind: common_1.IncentiveKind.Staking,
202
202
  });
203
203
  }
204
204
  if (_market.canBeBorrowed && _market.incentiveSupplyApy) {
@@ -210,7 +210,7 @@ function getAaveV3MarketData(web3, network, market, defaultWeb3) {
210
210
  _market.borrowIncentives.push({
211
211
  apy: _market.incentiveBorrowApy,
212
212
  token: _market.incentiveBorrowToken,
213
- incentiveKind: 'reward',
213
+ incentiveKind: common_1.IncentiveKind.Reward,
214
214
  });
215
215
  }
216
216
  if (!rewardForMarket)
@@ -240,7 +240,7 @@ function getAaveV3MarketData(web3, network, market, defaultWeb3) {
240
240
  _market.supplyIncentives.push({
241
241
  token: supplyRewardData.rewardTokenSymbol,
242
242
  apy: rewardApy,
243
- incentiveKind: 'reward',
243
+ incentiveKind: common_1.IncentiveKind.Reward,
244
244
  });
245
245
  }
246
246
  });
@@ -268,7 +268,7 @@ function getAaveV3MarketData(web3, network, market, defaultWeb3) {
268
268
  _market.borrowIncentives.push({
269
269
  token: borrowRewardData.rewardTokenSymbol,
270
270
  apy: rewardApy,
271
- incentiveKind: 'reward',
271
+ incentiveKind: common_1.IncentiveKind.Reward,
272
272
  });
273
273
  }
274
274
  });
package/cjs/index.d.ts CHANGED
@@ -21,5 +21,6 @@ import * as exchange from './exchange';
21
21
  import * as morphoBlue from './morphoBlue';
22
22
  import * as llamaLend from './llamaLend';
23
23
  import * as eulerV2 from './eulerV2';
24
+ import * as rewards from './rewards';
24
25
  export * from './types';
25
- export { aaveV2, aaveV3, morphoAaveV2, morphoAaveV3, compoundV2, compoundV3, spark, curveUsd, liquity, liquityV2, maker, chickenBonds, exchange, staking, multicall, moneymarket, markets, helpers, morphoBlue, llamaLend, eulerV2, fluid, };
26
+ export { aaveV2, aaveV3, morphoAaveV2, morphoAaveV3, compoundV2, compoundV3, spark, curveUsd, liquity, liquityV2, maker, chickenBonds, exchange, staking, multicall, moneymarket, markets, helpers, morphoBlue, llamaLend, eulerV2, fluid, rewards, };
package/cjs/index.js CHANGED
@@ -26,7 +26,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
26
26
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.fluid = exports.eulerV2 = exports.llamaLend = exports.morphoBlue = exports.helpers = exports.markets = exports.moneymarket = exports.multicall = exports.staking = exports.exchange = exports.chickenBonds = exports.maker = exports.liquityV2 = exports.liquity = exports.curveUsd = exports.spark = exports.compoundV3 = exports.compoundV2 = exports.morphoAaveV3 = exports.morphoAaveV2 = exports.aaveV3 = exports.aaveV2 = void 0;
29
+ exports.rewards = exports.fluid = exports.eulerV2 = exports.llamaLend = exports.morphoBlue = exports.helpers = exports.markets = exports.moneymarket = exports.multicall = exports.staking = exports.exchange = exports.chickenBonds = exports.maker = exports.liquityV2 = exports.liquity = exports.curveUsd = exports.spark = exports.compoundV3 = exports.compoundV2 = exports.morphoAaveV3 = exports.morphoAaveV2 = exports.aaveV3 = exports.aaveV2 = void 0;
30
30
  require("./setup");
31
31
  const fluid = __importStar(require("./fluid"));
32
32
  exports.fluid = fluid;
@@ -72,4 +72,6 @@ const llamaLend = __importStar(require("./llamaLend"));
72
72
  exports.llamaLend = llamaLend;
73
73
  const eulerV2 = __importStar(require("./eulerV2"));
74
74
  exports.eulerV2 = eulerV2;
75
+ const rewards = __importStar(require("./rewards"));
76
+ exports.rewards = rewards;
75
77
  __exportStar(require("./types"), exports);
@@ -590,7 +590,7 @@ exports.MORPHO_BLUE_USR_USDC_915 = MORPHO_BLUE_USR_USDC_915;
590
590
  const MORPHO_BLUE_PTSYRUPUSDCAUG_USDC_860 = (networkId = common_1.NetworkNumber.Eth) => ({
591
591
  chainIds: [1],
592
592
  label: 'Morpho',
593
- shortLabel: 'Pt syrupUSDC Aug/USDC',
593
+ shortLabel: 'PT syrupUSDC Aug/USDC',
594
594
  value: types_1.MorphoBlueVersions.MorphoBluePTsyrupUSDCAugUSDC_860,
595
595
  url: 'ptsyrupusdcaug-a3819a7d',
596
596
  loanToken: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
@@ -22,7 +22,9 @@ const staking_1 = require("../staking");
22
22
  const utils_1 = require("../services/utils");
23
23
  const morphoBlueHelpers_1 = require("../helpers/morphoBlueHelpers");
24
24
  const priceService_1 = require("../services/priceService");
25
+ const rewards_1 = require("../rewards");
25
26
  function getMorphoBlueMarketData(web3, network, selectedMarket, mainnetWeb3) {
27
+ var _a;
26
28
  return __awaiter(this, void 0, void 0, function* () {
27
29
  const { loanToken, collateralToken, oracle, irm, lltv, oracleType, } = selectedMarket;
28
30
  const lltvInWei = new decimal_js_1.default(lltv).mul(constants_1.WAD).toString();
@@ -56,15 +58,13 @@ function getMorphoBlueMarketData(web3, network, selectedMarket, mainnetWeb3) {
56
58
  }
57
59
  let morphoSupplyApy = '0';
58
60
  let morphoBorrowApy = '0';
59
- if (!collateralTokenInfo.isPendle) {
60
- try {
61
- const { supplyApy: _morphoSupplyApy, borrowApy: _morphoBorrowApy } = yield (0, morphoBlueHelpers_1.getRewardsForMarket)(selectedMarket.marketId, network);
62
- morphoSupplyApy = _morphoSupplyApy;
63
- morphoBorrowApy = _morphoBorrowApy;
64
- }
65
- catch (e) {
66
- console.error(e);
67
- }
61
+ try {
62
+ const { supplyApy: _morphoSupplyApy, borrowApy: _morphoBorrowApy } = yield (0, morphoBlueHelpers_1.getRewardsForMarket)(selectedMarket.marketId, network);
63
+ morphoSupplyApy = _morphoSupplyApy;
64
+ morphoBorrowApy = _morphoBorrowApy;
65
+ }
66
+ catch (e) {
67
+ console.error(e);
68
68
  }
69
69
  const supplyRate = (0, morphoBlueHelpers_1.getSupplyRate)(marketInfo.totalSupplyAssets, marketInfo.totalBorrowAssets, marketInfo.borrowRate, marketInfo.fee);
70
70
  const compoundedBorrowRate = (0, morphoBlueHelpers_1.getBorrowRate)(marketInfo.borrowRate, marketInfo.totalBorrowShares);
@@ -84,10 +84,20 @@ function getMorphoBlueMarketData(web3, network, selectedMarket, mainnetWeb3) {
84
84
  totalBorrow: new decimal_js_1.default(marketInfo.totalBorrowAssets).div(scale).toString(),
85
85
  canBeSupplied: true,
86
86
  canBeBorrowed: true,
87
- incentiveSupplyApy: morphoSupplyApy,
88
- incentiveBorrowApy: morphoBorrowApy,
89
- incentiveSupplyToken: 'MORPHO',
90
- incentiveBorrowToken: 'MORPHO',
87
+ supplyIncentives: [
88
+ {
89
+ token: 'MORPHO',
90
+ apy: morphoSupplyApy,
91
+ incentiveKind: common_1.IncentiveKind.Reward,
92
+ },
93
+ ],
94
+ borrowIncentives: [
95
+ {
96
+ token: 'MORPHO',
97
+ apy: morphoBorrowApy,
98
+ incentiveKind: common_1.IncentiveKind.Reward,
99
+ },
100
+ ],
91
101
  };
92
102
  assetsData[(0, utils_1.wethToEth)(collateralTokenInfo.symbol)] = {
93
103
  symbol: (0, utils_1.wethToEth)(collateralTokenInfo.symbol),
@@ -97,10 +107,20 @@ function getMorphoBlueMarketData(web3, network, selectedMarket, mainnetWeb3) {
97
107
  borrowRate: '0',
98
108
  canBeSupplied: true,
99
109
  canBeBorrowed: false,
110
+ supplyIncentives: [],
100
111
  };
101
112
  if (staking_1.STAKING_ASSETS.includes(collateralTokenInfo.symbol)) {
102
- assetsData[collateralTokenInfo.symbol].incentiveSupplyApy = yield (0, staking_1.getStakingApy)(collateralTokenInfo.symbol, mainnetWeb3);
103
- assetsData[collateralTokenInfo.symbol].incentiveSupplyToken = collateralTokenInfo.symbol;
113
+ assetsData[collateralTokenInfo.symbol].supplyIncentives = [
114
+ ...assetsData[collateralTokenInfo.symbol].supplyIncentives,
115
+ {
116
+ token: collateralTokenInfo.symbol,
117
+ apy: yield (0, staking_1.getStakingApy)(collateralTokenInfo.symbol, mainnetWeb3),
118
+ incentiveKind: common_1.IncentiveKind.Staking,
119
+ },
120
+ ];
121
+ }
122
+ if (rewards_1.REWARD_ASSETS.includes(collateralTokenInfo.symbol)) {
123
+ (_a = assetsData[collateralTokenInfo.symbol].supplyIncentives) === null || _a === void 0 ? void 0 : _a.push(yield (0, rewards_1.getReward)(collateralTokenInfo.symbol));
104
124
  }
105
125
  return {
106
126
  id: marketInfo.id,
@@ -0,0 +1 @@
1
+ export * from './rewards';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./rewards"), exports);
@@ -0,0 +1,12 @@
1
+ import memoize from 'memoizee';
2
+ import { IncentiveKind } from '../types/common';
3
+ export declare const REWARD_ASSETS: string[];
4
+ export declare const getReward: ((asset: string) => Promise<{
5
+ token: string;
6
+ apy: string;
7
+ incentiveKind: IncentiveKind;
8
+ }>) & memoize.Memoized<(asset: string) => Promise<{
9
+ token: string;
10
+ apy: string;
11
+ incentiveKind: IncentiveKind;
12
+ }>>;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.getReward = exports.REWARD_ASSETS = void 0;
16
+ const memoizee_1 = __importDefault(require("memoizee"));
17
+ const common_1 = require("../types/common");
18
+ exports.REWARD_ASSETS = [
19
+ 'syrupUSDC',
20
+ ];
21
+ const getApyFromDfsApi = (asset) => __awaiter(void 0, void 0, void 0, function* () {
22
+ const res = yield fetch(`https://fe.defisaver.com/api/rewards/apy?asset=${asset}`);
23
+ if (!res.ok)
24
+ throw new Error(`Failed to fetch APY for ${asset}`);
25
+ const data = yield res.json();
26
+ return String(data.apy);
27
+ });
28
+ exports.getReward = (0, memoizee_1.default)((asset) => __awaiter(void 0, void 0, void 0, function* () {
29
+ try {
30
+ if (asset === 'syrupUSDC') {
31
+ return {
32
+ token: '$MAPLE',
33
+ apy: yield getApyFromDfsApi(asset),
34
+ incentiveKind: common_1.IncentiveKind.Reward,
35
+ };
36
+ }
37
+ }
38
+ catch (e) {
39
+ console.error(`Failed to fetch APY for ${asset}`);
40
+ }
41
+ return {
42
+ token: '?',
43
+ apy: '0',
44
+ incentiveKind: common_1.IncentiveKind.Reward,
45
+ };
46
+ }), { promise: true, maxAge: 2 * 60 * 1000 });
@@ -113,7 +113,29 @@ const getApyFromDfsApi = (asset) => __awaiter(void 0, void 0, void 0, function*
113
113
  const data = yield res.json();
114
114
  return String(data.apy);
115
115
  });
116
- exports.STAKING_ASSETS = ['cbETH', 'wstETH', 'cbETH', 'rETH', 'sDAI', 'weETH', 'sUSDe', 'osETH', 'ezETH', 'ETHx', 'rsETH', 'pufETH', 'wrsETH', 'wsuperOETHb', 'sUSDS', 'PT eUSDe May', 'PT sUSDe July', 'PT USDe July', 'PT eUSDe Aug'];
116
+ exports.STAKING_ASSETS = [
117
+ 'cbETH',
118
+ 'wstETH',
119
+ 'cbETH',
120
+ 'rETH',
121
+ 'sDAI',
122
+ 'weETH',
123
+ 'sUSDe',
124
+ 'osETH',
125
+ 'ezETH',
126
+ 'ETHx',
127
+ 'rsETH',
128
+ 'pufETH',
129
+ 'wrsETH',
130
+ 'wsuperOETHb',
131
+ 'sUSDS',
132
+ 'PT eUSDe May',
133
+ 'PT sUSDe July',
134
+ 'PT USDe July',
135
+ 'PT eUSDe Aug',
136
+ 'PT syrupUSDC Aug',
137
+ 'syrupUSDC',
138
+ ];
117
139
  exports.getStakingApy = (0, memoizee_1.default)((asset, web3, blockNumber = 'latest', fromBlock = undefined) => __awaiter(void 0, void 0, void 0, function* () {
118
140
  try {
119
141
  if (asset === 'stETH' || asset === 'wstETH')
@@ -150,6 +172,10 @@ exports.getStakingApy = (0, memoizee_1.default)((asset, web3, blockNumber = 'lat
150
172
  return yield getApyFromDfsApi('PT USDe July');
151
173
  if (asset === 'PT eUSDe Aug')
152
174
  return yield getApyFromDfsApi('PT eUSDe Aug');
175
+ if (asset === 'PT syrupUSDC Aug')
176
+ return yield getApyFromDfsApi('PT syrupUSDC Aug');
177
+ if (asset === 'syrupUSDC')
178
+ return yield getApyFromDfsApi('syrupUSDC');
153
179
  }
154
180
  catch (e) {
155
181
  console.error(`Failed to fetch APY for ${asset}`);
@@ -183,7 +209,15 @@ const calculateNetApy = ({ usedAssets, assetsData, isMorpho = false }) => {
183
209
  : assetData.supplyRate;
184
210
  const supplyInterest = (0, exports.calculateInterestEarned)(amount, rate, 'year', true);
185
211
  acc.supplyInterest = new decimal_js_1.default(acc.supplyInterest).add(supplyInterest.toString()).toString();
186
- if (assetData.incentiveSupplyApy) {
212
+ if (assetData.supplyIncentives && assetData.supplyIncentives.length > 0) {
213
+ let totalApy = '0';
214
+ for (const incentive of assetData.supplyIncentives || []) {
215
+ totalApy = new decimal_js_1.default(totalApy).add(incentive.apy).toString();
216
+ }
217
+ const incentiveInterest = (0, exports.calculateInterestEarned)(amount, totalApy, 'year', true);
218
+ acc.incentiveUsd = new decimal_js_1.default(acc.incentiveUsd).add(incentiveInterest).toString();
219
+ }
220
+ else if (assetData.incentiveSupplyApy) {
187
221
  // take COMP/AAVE yield into account
188
222
  const incentiveInterest = (0, exports.calculateInterestEarned)(amount, assetData.incentiveSupplyApy, 'year', true);
189
223
  acc.incentiveUsd = new decimal_js_1.default(acc.incentiveUsd).add(incentiveInterest).toString();
@@ -199,7 +233,15 @@ const calculateNetApy = ({ usedAssets, assetsData, isMorpho = false }) => {
199
233
  : ((usedAsset === null || usedAsset === void 0 ? void 0 : usedAsset.interestMode) === '1' ? usedAsset.stableBorrowRate : assetData.borrowRate);
200
234
  const borrowInterest = (0, exports.calculateInterestEarned)(amount, rate, 'year', true);
201
235
  acc.borrowInterest = new decimal_js_1.default(acc.borrowInterest).sub(borrowInterest.toString()).toString();
202
- if (assetData.incentiveBorrowApy) {
236
+ if (assetData.borrowIncentives && assetData.borrowIncentives.length > 0) {
237
+ let totalApy = '0';
238
+ for (const incentive of assetData.borrowIncentives || []) {
239
+ totalApy = new decimal_js_1.default(totalApy).add(incentive.apy).toString();
240
+ }
241
+ const incentiveInterest = (0, exports.calculateInterestEarned)(amount, totalApy, 'year', true);
242
+ acc.incentiveUsd = new decimal_js_1.default(acc.incentiveUsd).sub(incentiveInterest).toString();
243
+ }
244
+ else if (assetData.incentiveBorrowApy) {
203
245
  // take COMP/AAVE yield into account
204
246
  const incentiveInterest = (0, exports.calculateInterestEarned)(amount, assetData.incentiveBorrowApy, 'year', true);
205
247
  acc.incentiveUsd = new decimal_js_1.default(acc.incentiveUsd).sub(incentiveInterest).toString();
@@ -1,4 +1,4 @@
1
- import { MMAssetData, MMPositionData, MMUsedAsset, NetworkNumber } from './common';
1
+ import { IncentiveData, MMAssetData, MMPositionData, MMUsedAsset, NetworkNumber } from './common';
2
2
  import { IUiIncentiveDataProviderV3 } from './contracts/generated/AaveUiIncentiveDataProviderV3';
3
3
  export declare enum AaveVersions {
4
4
  AaveV1 = "v1",
@@ -73,11 +73,6 @@ export interface AaveV2AssetData extends AaveAssetData {
73
73
  }
74
74
  export interface MorphoAaveV2AssetData extends AaveV2AssetData {
75
75
  }
76
- export interface IncentiveData {
77
- token: string;
78
- apy: string;
79
- incentiveKind?: 'staking' | 'reward';
80
- }
81
76
  export interface AaveV3AssetData extends AaveAssetData {
82
77
  isIsolated: boolean;
83
78
  isSiloed: boolean;
@@ -9,6 +9,15 @@ export declare enum NetworkNumber {
9
9
  Base = 8453
10
10
  }
11
11
  export type Networkish = string | NetworkNumber;
12
+ export declare enum IncentiveKind {
13
+ Staking = "staking",
14
+ Reward = "reward"
15
+ }
16
+ export interface IncentiveData {
17
+ token: string;
18
+ apy: string;
19
+ incentiveKind?: IncentiveKind;
20
+ }
12
21
  export interface MMAssetData {
13
22
  symbol: string;
14
23
  supplyRate: string;
@@ -29,6 +38,8 @@ export interface MMAssetData {
29
38
  incentiveSupplyToken?: string;
30
39
  borrowRateP2P?: string;
31
40
  supplyRateP2P?: string;
41
+ supplyIncentives?: IncentiveData[];
42
+ borrowIncentives?: IncentiveData[];
32
43
  }
33
44
  export interface MMAssetsData {
34
45
  [token: string]: MMAssetData;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.NetworkNumber = void 0;
3
+ exports.IncentiveKind = exports.NetworkNumber = void 0;
4
4
  var NetworkNumber;
5
5
  (function (NetworkNumber) {
6
6
  NetworkNumber[NetworkNumber["Eth"] = 1] = "Eth";
@@ -8,3 +8,8 @@ var NetworkNumber;
8
8
  NetworkNumber[NetworkNumber["Arb"] = 42161] = "Arb";
9
9
  NetworkNumber[NetworkNumber["Base"] = 8453] = "Base";
10
10
  })(NetworkNumber || (exports.NetworkNumber = NetworkNumber = {}));
11
+ var IncentiveKind;
12
+ (function (IncentiveKind) {
13
+ IncentiveKind["Staking"] = "staking";
14
+ IncentiveKind["Reward"] = "reward";
15
+ })(IncentiveKind || (exports.IncentiveKind = IncentiveKind = {}));
@@ -1,4 +1,4 @@
1
- import { MMUsedAssets, NetworkNumber } from './common';
1
+ import { IncentiveData, MMUsedAssets, NetworkNumber } from './common';
2
2
  export declare enum MorphoBlueVersions {
3
3
  MorphoBlueWstEthUSDC = "morphobluewstethusdc",
4
4
  MorphoBlueSDAIUSDC = "morphobluesdaiusdc",
@@ -83,14 +83,12 @@ export interface MorphoBlueAssetData {
83
83
  price: string;
84
84
  supplyRate: string;
85
85
  borrowRate: string;
86
- incentiveSupplyApy?: string;
87
- incentiveSupplyToken?: string;
88
- incentiveBorrowApy?: string;
89
- incentiveBorrowToken?: string;
90
86
  totalSupply?: string;
91
87
  totalBorrow?: string;
92
88
  canBeSupplied?: boolean;
93
89
  canBeBorrowed?: boolean;
90
+ supplyIncentives?: IncentiveData[];
91
+ borrowIncentives?: IncentiveData[];
94
92
  }
95
93
  export type MorphoBlueAssetsData = {
96
94
  [key: string]: MorphoBlueAssetData;
@@ -1,5 +1,4 @@
1
- import { MMAssetData, MMPositionData, MMUsedAsset, NetworkNumber } from './common';
2
- import { IncentiveData } from './aave';
1
+ import { IncentiveData, MMAssetData, MMPositionData, MMUsedAsset, NetworkNumber } from './common';
3
2
  export declare enum SparkVersions {
4
3
  SparkV1 = "v1default"
5
4
  }
@@ -17,7 +17,7 @@ import { aprToApy, calculateBorrowingAssetLimit } from '../moneymarket';
17
17
  import { multicall } from '../multicall';
18
18
  import { addToObjectIf, ethToWeth, getAbiItem, isEnabledOnBitmap, isLayer2Network, wethToEth, wethToEthByAddress, } from '../services/utils';
19
19
  import { getStakingApy, STAKING_ASSETS } from '../staking';
20
- import { NetworkNumber, } from '../types/common';
20
+ import { IncentiveKind, NetworkNumber, } from '../types/common';
21
21
  export const test = (web3, network) => {
22
22
  const contract = AaveV3ViewContract(web3, 1);
23
23
  return contract.methods.AAVE_REFERRAL_CODE().call();
@@ -189,7 +189,7 @@ export function getAaveV3MarketData(web3, network, market, defaultWeb3) {
189
189
  _market.supplyIncentives.push({
190
190
  apy: _market.incentiveSupplyApy || '0',
191
191
  token: _market.symbol,
192
- incentiveKind: 'staking',
192
+ incentiveKind: IncentiveKind.Staking,
193
193
  });
194
194
  }
195
195
  if (_market.canBeBorrowed && _market.incentiveSupplyApy) {
@@ -201,7 +201,7 @@ export function getAaveV3MarketData(web3, network, market, defaultWeb3) {
201
201
  _market.borrowIncentives.push({
202
202
  apy: _market.incentiveBorrowApy,
203
203
  token: _market.incentiveBorrowToken,
204
- incentiveKind: 'reward',
204
+ incentiveKind: IncentiveKind.Reward,
205
205
  });
206
206
  }
207
207
  if (!rewardForMarket)
@@ -231,7 +231,7 @@ export function getAaveV3MarketData(web3, network, market, defaultWeb3) {
231
231
  _market.supplyIncentives.push({
232
232
  token: supplyRewardData.rewardTokenSymbol,
233
233
  apy: rewardApy,
234
- incentiveKind: 'reward',
234
+ incentiveKind: IncentiveKind.Reward,
235
235
  });
236
236
  }
237
237
  });
@@ -259,7 +259,7 @@ export function getAaveV3MarketData(web3, network, market, defaultWeb3) {
259
259
  _market.borrowIncentives.push({
260
260
  token: borrowRewardData.rewardTokenSymbol,
261
261
  apy: rewardApy,
262
- incentiveKind: 'reward',
262
+ incentiveKind: IncentiveKind.Reward,
263
263
  });
264
264
  }
265
265
  });
package/esm/index.d.ts CHANGED
@@ -21,5 +21,6 @@ import * as exchange from './exchange';
21
21
  import * as morphoBlue from './morphoBlue';
22
22
  import * as llamaLend from './llamaLend';
23
23
  import * as eulerV2 from './eulerV2';
24
+ import * as rewards from './rewards';
24
25
  export * from './types';
25
- export { aaveV2, aaveV3, morphoAaveV2, morphoAaveV3, compoundV2, compoundV3, spark, curveUsd, liquity, liquityV2, maker, chickenBonds, exchange, staking, multicall, moneymarket, markets, helpers, morphoBlue, llamaLend, eulerV2, fluid, };
26
+ export { aaveV2, aaveV3, morphoAaveV2, morphoAaveV3, compoundV2, compoundV3, spark, curveUsd, liquity, liquityV2, maker, chickenBonds, exchange, staking, multicall, moneymarket, markets, helpers, morphoBlue, llamaLend, eulerV2, fluid, rewards, };
package/esm/index.js CHANGED
@@ -21,5 +21,6 @@ import * as exchange from './exchange';
21
21
  import * as morphoBlue from './morphoBlue';
22
22
  import * as llamaLend from './llamaLend';
23
23
  import * as eulerV2 from './eulerV2';
24
+ import * as rewards from './rewards';
24
25
  export * from './types';
25
- export { aaveV2, aaveV3, morphoAaveV2, morphoAaveV3, compoundV2, compoundV3, spark, curveUsd, liquity, liquityV2, maker, chickenBonds, exchange, staking, multicall, moneymarket, markets, helpers, morphoBlue, llamaLend, eulerV2, fluid, };
26
+ export { aaveV2, aaveV3, morphoAaveV2, morphoAaveV3, compoundV2, compoundV3, spark, curveUsd, liquity, liquityV2, maker, chickenBonds, exchange, staking, multicall, moneymarket, markets, helpers, morphoBlue, llamaLend, eulerV2, fluid, rewards, };
@@ -550,7 +550,7 @@ export const MORPHO_BLUE_USR_USDC_915 = (networkId = NetworkNumber.Eth) => ({
550
550
  export const MORPHO_BLUE_PTSYRUPUSDCAUG_USDC_860 = (networkId = NetworkNumber.Eth) => ({
551
551
  chainIds: [1],
552
552
  label: 'Morpho',
553
- shortLabel: 'Pt syrupUSDC Aug/USDC',
553
+ shortLabel: 'PT syrupUSDC Aug/USDC',
554
554
  value: MorphoBlueVersions.MorphoBluePTsyrupUSDCAugUSDC_860,
555
555
  url: 'ptsyrupusdcaug-a3819a7d',
556
556
  loanToken: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
@@ -9,14 +9,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import Dec from 'decimal.js';
11
11
  import { assetAmountInEth, getAssetInfoByAddress } from '@defisaver/tokens';
12
- import { NetworkNumber, } from '../types/common';
12
+ import { IncentiveKind, NetworkNumber, } from '../types/common';
13
13
  import { DFSFeedRegistryContract, FeedRegistryContract, MorphoBlueViewContract } from '../contracts';
14
14
  import { USD_QUOTE, WAD } from '../constants';
15
15
  import { getStakingApy, STAKING_ASSETS } from '../staking';
16
16
  import { isMainnetNetwork, wethToEth } from '../services/utils';
17
17
  import { getBorrowRate, getMorphoBlueAggregatedPositionData, getRewardsForMarket, getSupplyRate, } from '../helpers/morphoBlueHelpers';
18
18
  import { getChainlinkAssetAddress } from '../services/priceService';
19
+ import { getReward, REWARD_ASSETS } from '../rewards';
19
20
  export function getMorphoBlueMarketData(web3, network, selectedMarket, mainnetWeb3) {
21
+ var _a;
20
22
  return __awaiter(this, void 0, void 0, function* () {
21
23
  const { loanToken, collateralToken, oracle, irm, lltv, oracleType, } = selectedMarket;
22
24
  const lltvInWei = new Dec(lltv).mul(WAD).toString();
@@ -50,15 +52,13 @@ export function getMorphoBlueMarketData(web3, network, selectedMarket, mainnetWe
50
52
  }
51
53
  let morphoSupplyApy = '0';
52
54
  let morphoBorrowApy = '0';
53
- if (!collateralTokenInfo.isPendle) {
54
- try {
55
- const { supplyApy: _morphoSupplyApy, borrowApy: _morphoBorrowApy } = yield getRewardsForMarket(selectedMarket.marketId, network);
56
- morphoSupplyApy = _morphoSupplyApy;
57
- morphoBorrowApy = _morphoBorrowApy;
58
- }
59
- catch (e) {
60
- console.error(e);
61
- }
55
+ try {
56
+ const { supplyApy: _morphoSupplyApy, borrowApy: _morphoBorrowApy } = yield getRewardsForMarket(selectedMarket.marketId, network);
57
+ morphoSupplyApy = _morphoSupplyApy;
58
+ morphoBorrowApy = _morphoBorrowApy;
59
+ }
60
+ catch (e) {
61
+ console.error(e);
62
62
  }
63
63
  const supplyRate = getSupplyRate(marketInfo.totalSupplyAssets, marketInfo.totalBorrowAssets, marketInfo.borrowRate, marketInfo.fee);
64
64
  const compoundedBorrowRate = getBorrowRate(marketInfo.borrowRate, marketInfo.totalBorrowShares);
@@ -78,10 +78,20 @@ export function getMorphoBlueMarketData(web3, network, selectedMarket, mainnetWe
78
78
  totalBorrow: new Dec(marketInfo.totalBorrowAssets).div(scale).toString(),
79
79
  canBeSupplied: true,
80
80
  canBeBorrowed: true,
81
- incentiveSupplyApy: morphoSupplyApy,
82
- incentiveBorrowApy: morphoBorrowApy,
83
- incentiveSupplyToken: 'MORPHO',
84
- incentiveBorrowToken: 'MORPHO',
81
+ supplyIncentives: [
82
+ {
83
+ token: 'MORPHO',
84
+ apy: morphoSupplyApy,
85
+ incentiveKind: IncentiveKind.Reward,
86
+ },
87
+ ],
88
+ borrowIncentives: [
89
+ {
90
+ token: 'MORPHO',
91
+ apy: morphoBorrowApy,
92
+ incentiveKind: IncentiveKind.Reward,
93
+ },
94
+ ],
85
95
  };
86
96
  assetsData[wethToEth(collateralTokenInfo.symbol)] = {
87
97
  symbol: wethToEth(collateralTokenInfo.symbol),
@@ -91,10 +101,20 @@ export function getMorphoBlueMarketData(web3, network, selectedMarket, mainnetWe
91
101
  borrowRate: '0',
92
102
  canBeSupplied: true,
93
103
  canBeBorrowed: false,
104
+ supplyIncentives: [],
94
105
  };
95
106
  if (STAKING_ASSETS.includes(collateralTokenInfo.symbol)) {
96
- assetsData[collateralTokenInfo.symbol].incentiveSupplyApy = yield getStakingApy(collateralTokenInfo.symbol, mainnetWeb3);
97
- assetsData[collateralTokenInfo.symbol].incentiveSupplyToken = collateralTokenInfo.symbol;
107
+ assetsData[collateralTokenInfo.symbol].supplyIncentives = [
108
+ ...assetsData[collateralTokenInfo.symbol].supplyIncentives,
109
+ {
110
+ token: collateralTokenInfo.symbol,
111
+ apy: yield getStakingApy(collateralTokenInfo.symbol, mainnetWeb3),
112
+ incentiveKind: IncentiveKind.Staking,
113
+ },
114
+ ];
115
+ }
116
+ if (REWARD_ASSETS.includes(collateralTokenInfo.symbol)) {
117
+ (_a = assetsData[collateralTokenInfo.symbol].supplyIncentives) === null || _a === void 0 ? void 0 : _a.push(yield getReward(collateralTokenInfo.symbol));
98
118
  }
99
119
  return {
100
120
  id: marketInfo.id,
@@ -0,0 +1 @@
1
+ export * from './rewards';
@@ -0,0 +1 @@
1
+ export * from './rewards';
@@ -0,0 +1,12 @@
1
+ import memoize from 'memoizee';
2
+ import { IncentiveKind } from '../types/common';
3
+ export declare const REWARD_ASSETS: string[];
4
+ export declare const getReward: ((asset: string) => Promise<{
5
+ token: string;
6
+ apy: string;
7
+ incentiveKind: IncentiveKind;
8
+ }>) & memoize.Memoized<(asset: string) => Promise<{
9
+ token: string;
10
+ apy: string;
11
+ incentiveKind: IncentiveKind;
12
+ }>>;
@@ -0,0 +1,40 @@
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 memoize from 'memoizee';
11
+ import { IncentiveKind } from '../types/common';
12
+ export const REWARD_ASSETS = [
13
+ 'syrupUSDC',
14
+ ];
15
+ const getApyFromDfsApi = (asset) => __awaiter(void 0, void 0, void 0, function* () {
16
+ const res = yield fetch(`https://fe.defisaver.com/api/rewards/apy?asset=${asset}`);
17
+ if (!res.ok)
18
+ throw new Error(`Failed to fetch APY for ${asset}`);
19
+ const data = yield res.json();
20
+ return String(data.apy);
21
+ });
22
+ export const getReward = memoize((asset) => __awaiter(void 0, void 0, void 0, function* () {
23
+ try {
24
+ if (asset === 'syrupUSDC') {
25
+ return {
26
+ token: '$MAPLE',
27
+ apy: yield getApyFromDfsApi(asset),
28
+ incentiveKind: IncentiveKind.Reward,
29
+ };
30
+ }
31
+ }
32
+ catch (e) {
33
+ console.error(`Failed to fetch APY for ${asset}`);
34
+ }
35
+ return {
36
+ token: '?',
37
+ apy: '0',
38
+ incentiveKind: IncentiveKind.Reward,
39
+ };
40
+ }), { promise: true, maxAge: 2 * 60 * 1000 });
@@ -107,7 +107,29 @@ const getApyFromDfsApi = (asset) => __awaiter(void 0, void 0, void 0, function*
107
107
  const data = yield res.json();
108
108
  return String(data.apy);
109
109
  });
110
- export const STAKING_ASSETS = ['cbETH', 'wstETH', 'cbETH', 'rETH', 'sDAI', 'weETH', 'sUSDe', 'osETH', 'ezETH', 'ETHx', 'rsETH', 'pufETH', 'wrsETH', 'wsuperOETHb', 'sUSDS', 'PT eUSDe May', 'PT sUSDe July', 'PT USDe July', 'PT eUSDe Aug'];
110
+ export const STAKING_ASSETS = [
111
+ 'cbETH',
112
+ 'wstETH',
113
+ 'cbETH',
114
+ 'rETH',
115
+ 'sDAI',
116
+ 'weETH',
117
+ 'sUSDe',
118
+ 'osETH',
119
+ 'ezETH',
120
+ 'ETHx',
121
+ 'rsETH',
122
+ 'pufETH',
123
+ 'wrsETH',
124
+ 'wsuperOETHb',
125
+ 'sUSDS',
126
+ 'PT eUSDe May',
127
+ 'PT sUSDe July',
128
+ 'PT USDe July',
129
+ 'PT eUSDe Aug',
130
+ 'PT syrupUSDC Aug',
131
+ 'syrupUSDC',
132
+ ];
111
133
  export const getStakingApy = memoize((asset, web3, blockNumber = 'latest', fromBlock = undefined) => __awaiter(void 0, void 0, void 0, function* () {
112
134
  try {
113
135
  if (asset === 'stETH' || asset === 'wstETH')
@@ -144,6 +166,10 @@ export const getStakingApy = memoize((asset, web3, blockNumber = 'latest', fromB
144
166
  return yield getApyFromDfsApi('PT USDe July');
145
167
  if (asset === 'PT eUSDe Aug')
146
168
  return yield getApyFromDfsApi('PT eUSDe Aug');
169
+ if (asset === 'PT syrupUSDC Aug')
170
+ return yield getApyFromDfsApi('PT syrupUSDC Aug');
171
+ if (asset === 'syrupUSDC')
172
+ return yield getApyFromDfsApi('syrupUSDC');
147
173
  }
148
174
  catch (e) {
149
175
  console.error(`Failed to fetch APY for ${asset}`);
@@ -176,7 +202,15 @@ export const calculateNetApy = ({ usedAssets, assetsData, isMorpho = false }) =>
176
202
  : assetData.supplyRate;
177
203
  const supplyInterest = calculateInterestEarned(amount, rate, 'year', true);
178
204
  acc.supplyInterest = new Dec(acc.supplyInterest).add(supplyInterest.toString()).toString();
179
- if (assetData.incentiveSupplyApy) {
205
+ if (assetData.supplyIncentives && assetData.supplyIncentives.length > 0) {
206
+ let totalApy = '0';
207
+ for (const incentive of assetData.supplyIncentives || []) {
208
+ totalApy = new Dec(totalApy).add(incentive.apy).toString();
209
+ }
210
+ const incentiveInterest = calculateInterestEarned(amount, totalApy, 'year', true);
211
+ acc.incentiveUsd = new Dec(acc.incentiveUsd).add(incentiveInterest).toString();
212
+ }
213
+ else if (assetData.incentiveSupplyApy) {
180
214
  // take COMP/AAVE yield into account
181
215
  const incentiveInterest = calculateInterestEarned(amount, assetData.incentiveSupplyApy, 'year', true);
182
216
  acc.incentiveUsd = new Dec(acc.incentiveUsd).add(incentiveInterest).toString();
@@ -192,7 +226,15 @@ export const calculateNetApy = ({ usedAssets, assetsData, isMorpho = false }) =>
192
226
  : ((usedAsset === null || usedAsset === void 0 ? void 0 : usedAsset.interestMode) === '1' ? usedAsset.stableBorrowRate : assetData.borrowRate);
193
227
  const borrowInterest = calculateInterestEarned(amount, rate, 'year', true);
194
228
  acc.borrowInterest = new Dec(acc.borrowInterest).sub(borrowInterest.toString()).toString();
195
- if (assetData.incentiveBorrowApy) {
229
+ if (assetData.borrowIncentives && assetData.borrowIncentives.length > 0) {
230
+ let totalApy = '0';
231
+ for (const incentive of assetData.borrowIncentives || []) {
232
+ totalApy = new Dec(totalApy).add(incentive.apy).toString();
233
+ }
234
+ const incentiveInterest = calculateInterestEarned(amount, totalApy, 'year', true);
235
+ acc.incentiveUsd = new Dec(acc.incentiveUsd).sub(incentiveInterest).toString();
236
+ }
237
+ else if (assetData.incentiveBorrowApy) {
196
238
  // take COMP/AAVE yield into account
197
239
  const incentiveInterest = calculateInterestEarned(amount, assetData.incentiveBorrowApy, 'year', true);
198
240
  acc.incentiveUsd = new Dec(acc.incentiveUsd).sub(incentiveInterest).toString();
@@ -1,4 +1,4 @@
1
- import { MMAssetData, MMPositionData, MMUsedAsset, NetworkNumber } from './common';
1
+ import { IncentiveData, MMAssetData, MMPositionData, MMUsedAsset, NetworkNumber } from './common';
2
2
  import { IUiIncentiveDataProviderV3 } from './contracts/generated/AaveUiIncentiveDataProviderV3';
3
3
  export declare enum AaveVersions {
4
4
  AaveV1 = "v1",
@@ -73,11 +73,6 @@ export interface AaveV2AssetData extends AaveAssetData {
73
73
  }
74
74
  export interface MorphoAaveV2AssetData extends AaveV2AssetData {
75
75
  }
76
- export interface IncentiveData {
77
- token: string;
78
- apy: string;
79
- incentiveKind?: 'staking' | 'reward';
80
- }
81
76
  export interface AaveV3AssetData extends AaveAssetData {
82
77
  isIsolated: boolean;
83
78
  isSiloed: boolean;
@@ -9,6 +9,15 @@ export declare enum NetworkNumber {
9
9
  Base = 8453
10
10
  }
11
11
  export type Networkish = string | NetworkNumber;
12
+ export declare enum IncentiveKind {
13
+ Staking = "staking",
14
+ Reward = "reward"
15
+ }
16
+ export interface IncentiveData {
17
+ token: string;
18
+ apy: string;
19
+ incentiveKind?: IncentiveKind;
20
+ }
12
21
  export interface MMAssetData {
13
22
  symbol: string;
14
23
  supplyRate: string;
@@ -29,6 +38,8 @@ export interface MMAssetData {
29
38
  incentiveSupplyToken?: string;
30
39
  borrowRateP2P?: string;
31
40
  supplyRateP2P?: string;
41
+ supplyIncentives?: IncentiveData[];
42
+ borrowIncentives?: IncentiveData[];
32
43
  }
33
44
  export interface MMAssetsData {
34
45
  [token: string]: MMAssetData;
@@ -5,3 +5,8 @@ export var NetworkNumber;
5
5
  NetworkNumber[NetworkNumber["Arb"] = 42161] = "Arb";
6
6
  NetworkNumber[NetworkNumber["Base"] = 8453] = "Base";
7
7
  })(NetworkNumber || (NetworkNumber = {}));
8
+ export var IncentiveKind;
9
+ (function (IncentiveKind) {
10
+ IncentiveKind["Staking"] = "staking";
11
+ IncentiveKind["Reward"] = "reward";
12
+ })(IncentiveKind || (IncentiveKind = {}));
@@ -1,4 +1,4 @@
1
- import { MMUsedAssets, NetworkNumber } from './common';
1
+ import { IncentiveData, MMUsedAssets, NetworkNumber } from './common';
2
2
  export declare enum MorphoBlueVersions {
3
3
  MorphoBlueWstEthUSDC = "morphobluewstethusdc",
4
4
  MorphoBlueSDAIUSDC = "morphobluesdaiusdc",
@@ -83,14 +83,12 @@ export interface MorphoBlueAssetData {
83
83
  price: string;
84
84
  supplyRate: string;
85
85
  borrowRate: string;
86
- incentiveSupplyApy?: string;
87
- incentiveSupplyToken?: string;
88
- incentiveBorrowApy?: string;
89
- incentiveBorrowToken?: string;
90
86
  totalSupply?: string;
91
87
  totalBorrow?: string;
92
88
  canBeSupplied?: boolean;
93
89
  canBeBorrowed?: boolean;
90
+ supplyIncentives?: IncentiveData[];
91
+ borrowIncentives?: IncentiveData[];
94
92
  }
95
93
  export type MorphoBlueAssetsData = {
96
94
  [key: string]: MorphoBlueAssetData;
@@ -1,5 +1,4 @@
1
- import { MMAssetData, MMPositionData, MMUsedAsset, NetworkNumber } from './common';
2
- import { IncentiveData } from './aave';
1
+ import { IncentiveData, MMAssetData, MMPositionData, MMUsedAsset, NetworkNumber } from './common';
3
2
  export declare enum SparkVersions {
4
3
  SparkV1 = "v1default"
5
4
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defisaver/positions-sdk",
3
- "version": "1.0.21-dev-2",
3
+ "version": "1.0.21-dev-3",
4
4
  "description": "",
5
5
  "main": "./cjs/index.js",
6
6
  "module": "./esm/index.js",
@@ -13,7 +13,7 @@
13
13
  "lint": "eslint src/ --fix",
14
14
  "lint-check": "eslint src/",
15
15
  "generate-contracts": "node scripts/generateContracts.js",
16
- "test": "mocha tests/*",
16
+ "test": "mocha tests/morphoBlue.ts",
17
17
  "test-single": "mocha ./tests/$npm_config_name.ts",
18
18
  "test:debugger": "mocha --inspect-brk tests/*",
19
19
  "build-test": "npm run build && npm run test",
@@ -32,7 +32,7 @@ import {
32
32
  EModeCategoryDataMapping,
33
33
  } from '../types/aave';
34
34
  import {
35
- Blockish, EthAddress, NetworkNumber, PositionBalances,
35
+ Blockish, EthAddress, IncentiveKind, NetworkNumber, PositionBalances,
36
36
  } from '../types/common';
37
37
  import { IUiIncentiveDataProviderV3 } from '../types/contracts/generated/AaveUiIncentiveDataProviderV3';
38
38
 
@@ -286,7 +286,7 @@ export async function getAaveV3MarketData(web3: Web3, network: NetworkNumber, ma
286
286
  _market.supplyIncentives.push({
287
287
  apy: _market.incentiveSupplyApy || '0',
288
288
  token: _market.symbol,
289
- incentiveKind: 'staking',
289
+ incentiveKind: IncentiveKind.Staking,
290
290
  });
291
291
  }
292
292
 
@@ -299,7 +299,7 @@ export async function getAaveV3MarketData(web3: Web3, network: NetworkNumber, ma
299
299
  _market.borrowIncentives.push({
300
300
  apy: _market.incentiveBorrowApy,
301
301
  token: _market.incentiveBorrowToken!!,
302
- incentiveKind: 'reward',
302
+ incentiveKind: IncentiveKind.Reward,
303
303
  });
304
304
  }
305
305
 
@@ -328,7 +328,7 @@ export async function getAaveV3MarketData(web3: Web3, network: NetworkNumber, ma
328
328
  _market.supplyIncentives.push({
329
329
  token: supplyRewardData.rewardTokenSymbol,
330
330
  apy: rewardApy,
331
- incentiveKind: 'reward',
331
+ incentiveKind: IncentiveKind.Reward,
332
332
  });
333
333
  }
334
334
  });
@@ -355,7 +355,7 @@ export async function getAaveV3MarketData(web3: Web3, network: NetworkNumber, ma
355
355
  _market.borrowIncentives.push({
356
356
  token: borrowRewardData.rewardTokenSymbol,
357
357
  apy: rewardApy,
358
- incentiveKind: 'reward',
358
+ incentiveKind: IncentiveKind.Reward,
359
359
  });
360
360
  }
361
361
  });
package/src/index.ts CHANGED
@@ -23,6 +23,7 @@ import * as exchange from './exchange';
23
23
  import * as morphoBlue from './morphoBlue';
24
24
  import * as llamaLend from './llamaLend';
25
25
  import * as eulerV2 from './eulerV2';
26
+ import * as rewards from './rewards';
26
27
 
27
28
  export * from './types';
28
29
 
@@ -49,4 +50,5 @@ export {
49
50
  llamaLend,
50
51
  eulerV2,
51
52
  fluid,
53
+ rewards,
52
54
  };
@@ -558,7 +558,7 @@ export const MORPHO_BLUE_USR_USDC_915 = (networkId: NetworkNumber = NetworkNumbe
558
558
  export const MORPHO_BLUE_PTSYRUPUSDCAUG_USDC_860 = (networkId: NetworkNumber = NetworkNumber.Eth): MorphoBlueMarketData => ({
559
559
  chainIds: [1],
560
560
  label: 'Morpho',
561
- shortLabel: 'Pt syrupUSDC Aug/USDC',
561
+ shortLabel: 'PT syrupUSDC Aug/USDC',
562
562
  value: MorphoBlueVersions.MorphoBluePTsyrupUSDCAugUSDC_860,
563
563
  url: 'ptsyrupusdcaug-a3819a7d',
564
564
  loanToken: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
@@ -2,7 +2,7 @@ import Web3 from 'web3';
2
2
  import Dec from 'decimal.js';
3
3
  import { assetAmountInEth, getAssetInfoByAddress } from '@defisaver/tokens';
4
4
  import {
5
- Blockish, EthAddress, MMUsedAssets, NetworkNumber, PositionBalances,
5
+ Blockish, EthAddress, IncentiveKind, MMUsedAssets, NetworkNumber, PositionBalances,
6
6
  } from '../types/common';
7
7
  import { DFSFeedRegistryContract, FeedRegistryContract, MorphoBlueViewContract } from '../contracts';
8
8
  import {
@@ -15,6 +15,7 @@ import {
15
15
  getBorrowRate, getMorphoBlueAggregatedPositionData, getRewardsForMarket, getSupplyRate,
16
16
  } from '../helpers/morphoBlueHelpers';
17
17
  import { getChainlinkAssetAddress } from '../services/priceService';
18
+ import { getReward, REWARD_ASSETS } from '../rewards';
18
19
 
19
20
  export async function getMorphoBlueMarketData(web3: Web3, network: NetworkNumber, selectedMarket: MorphoBlueMarketData, mainnetWeb3: Web3): Promise<MorphoBlueMarketInfo> {
20
21
  const {
@@ -56,14 +57,12 @@ export async function getMorphoBlueMarketData(web3: Web3, network: NetworkNumber
56
57
 
57
58
  let morphoSupplyApy = '0';
58
59
  let morphoBorrowApy = '0';
59
- if (!collateralTokenInfo.isPendle) {
60
- try {
61
- const { supplyApy: _morphoSupplyApy, borrowApy: _morphoBorrowApy } = await getRewardsForMarket(selectedMarket.marketId, network);
62
- morphoSupplyApy = _morphoSupplyApy;
63
- morphoBorrowApy = _morphoBorrowApy;
64
- } catch (e) {
65
- console.error(e);
66
- }
60
+ try {
61
+ const { supplyApy: _morphoSupplyApy, borrowApy: _morphoBorrowApy } = await getRewardsForMarket(selectedMarket.marketId, network);
62
+ morphoSupplyApy = _morphoSupplyApy;
63
+ morphoBorrowApy = _morphoBorrowApy;
64
+ } catch (e) {
65
+ console.error(e);
67
66
  }
68
67
 
69
68
  const supplyRate = getSupplyRate(marketInfo.totalSupplyAssets, marketInfo.totalBorrowAssets, marketInfo.borrowRate, marketInfo.fee);
@@ -87,10 +86,20 @@ export async function getMorphoBlueMarketData(web3: Web3, network: NetworkNumber
87
86
  totalBorrow: new Dec(marketInfo.totalBorrowAssets).div(scale).toString(),
88
87
  canBeSupplied: true,
89
88
  canBeBorrowed: true,
90
- incentiveSupplyApy: morphoSupplyApy,
91
- incentiveBorrowApy: morphoBorrowApy,
92
- incentiveSupplyToken: 'MORPHO',
93
- incentiveBorrowToken: 'MORPHO',
89
+ supplyIncentives: [
90
+ {
91
+ token: 'MORPHO',
92
+ apy: morphoSupplyApy,
93
+ incentiveKind: IncentiveKind.Reward,
94
+ },
95
+ ],
96
+ borrowIncentives: [
97
+ {
98
+ token: 'MORPHO',
99
+ apy: morphoBorrowApy,
100
+ incentiveKind: IncentiveKind.Reward,
101
+ },
102
+ ],
94
103
  };
95
104
 
96
105
  assetsData[wethToEth(collateralTokenInfo.symbol)] = {
@@ -101,10 +110,21 @@ export async function getMorphoBlueMarketData(web3: Web3, network: NetworkNumber
101
110
  borrowRate: '0',
102
111
  canBeSupplied: true,
103
112
  canBeBorrowed: false,
113
+ supplyIncentives: [],
104
114
  };
105
115
  if (STAKING_ASSETS.includes(collateralTokenInfo.symbol)) {
106
- assetsData[collateralTokenInfo.symbol].incentiveSupplyApy = await getStakingApy(collateralTokenInfo.symbol, mainnetWeb3);
107
- assetsData[collateralTokenInfo.symbol].incentiveSupplyToken = collateralTokenInfo.symbol;
116
+ assetsData[collateralTokenInfo.symbol].supplyIncentives = [
117
+ ...assetsData[collateralTokenInfo.symbol].supplyIncentives!,
118
+ {
119
+ token: collateralTokenInfo.symbol,
120
+ apy: await getStakingApy(collateralTokenInfo.symbol, mainnetWeb3),
121
+ incentiveKind: IncentiveKind.Staking,
122
+ },
123
+ ];
124
+ }
125
+
126
+ if (REWARD_ASSETS.includes(collateralTokenInfo.symbol)) {
127
+ assetsData[collateralTokenInfo.symbol].supplyIncentives?.push(await getReward(collateralTokenInfo.symbol));
108
128
  }
109
129
 
110
130
  return {
@@ -0,0 +1 @@
1
+ export * from './rewards';
@@ -0,0 +1,32 @@
1
+ import memoize from 'memoizee';
2
+ import { IncentiveKind } from '../types/common';
3
+
4
+ export const REWARD_ASSETS = [
5
+ 'syrupUSDC',
6
+ ];
7
+
8
+ const getApyFromDfsApi = async (asset: string) => {
9
+ const res = await fetch(`https://fe.defisaver.com/api/rewards/apy?asset=${asset}`);
10
+ if (!res.ok) throw new Error(`Failed to fetch APY for ${asset}`);
11
+ const data = await res.json();
12
+ return String(data.apy);
13
+ };
14
+
15
+ export const getReward = memoize(async (asset: string) => {
16
+ try {
17
+ if (asset === 'syrupUSDC') {
18
+ return {
19
+ token: '$MAPLE',
20
+ apy: await getApyFromDfsApi(asset),
21
+ incentiveKind: IncentiveKind.Reward,
22
+ };
23
+ }
24
+ } catch (e) {
25
+ console.error(`Failed to fetch APY for ${asset}`);
26
+ }
27
+ return {
28
+ token: '?',
29
+ apy: '0',
30
+ incentiveKind: IncentiveKind.Reward,
31
+ };
32
+ }, { promise: true, maxAge: 2 * 60 * 1000 });
@@ -109,7 +109,29 @@ const getApyFromDfsApi = async (asset: string) => {
109
109
  return String(data.apy);
110
110
  };
111
111
 
112
- export const STAKING_ASSETS = ['cbETH', 'wstETH', 'cbETH', 'rETH', 'sDAI', 'weETH', 'sUSDe', 'osETH', 'ezETH', 'ETHx', 'rsETH', 'pufETH', 'wrsETH', 'wsuperOETHb', 'sUSDS', 'PT eUSDe May', 'PT sUSDe July', 'PT USDe July', 'PT eUSDe Aug'];
112
+ export const STAKING_ASSETS = [
113
+ 'cbETH',
114
+ 'wstETH',
115
+ 'cbETH',
116
+ 'rETH',
117
+ 'sDAI',
118
+ 'weETH',
119
+ 'sUSDe',
120
+ 'osETH',
121
+ 'ezETH',
122
+ 'ETHx',
123
+ 'rsETH',
124
+ 'pufETH',
125
+ 'wrsETH',
126
+ 'wsuperOETHb',
127
+ 'sUSDS',
128
+ 'PT eUSDe May',
129
+ 'PT sUSDe July',
130
+ 'PT USDe July',
131
+ 'PT eUSDe Aug',
132
+ 'PT syrupUSDC Aug',
133
+ 'syrupUSDC',
134
+ ];
113
135
 
114
136
  export const getStakingApy = memoize(async (asset: string, web3: Web3, blockNumber: 'latest' | number = 'latest', fromBlock: number | undefined = undefined) => {
115
137
  try {
@@ -130,6 +152,8 @@ export const getStakingApy = memoize(async (asset: string, web3: Web3, blockNumb
130
152
  if (asset === 'PT sUSDe July') return await getApyFromDfsApi('PT sUSDe July');
131
153
  if (asset === 'PT USDe July') return await getApyFromDfsApi('PT USDe July');
132
154
  if (asset === 'PT eUSDe Aug') return await getApyFromDfsApi('PT eUSDe Aug');
155
+ if (asset === 'PT syrupUSDC Aug') return await getApyFromDfsApi('PT syrupUSDC Aug');
156
+ if (asset === 'syrupUSDC') return await getApyFromDfsApi('syrupUSDC');
133
157
  } catch (e) {
134
158
  console.error(`Failed to fetch APY for ${asset}`);
135
159
  }
@@ -165,7 +189,14 @@ export const calculateNetApy = ({ usedAssets, assetsData, isMorpho = false }: {
165
189
  : assetData.supplyRate;
166
190
  const supplyInterest = calculateInterestEarned(amount, rate as string, 'year', true);
167
191
  acc.supplyInterest = new Dec(acc.supplyInterest).add(supplyInterest.toString()).toString();
168
- if (assetData.incentiveSupplyApy) {
192
+ if (assetData.supplyIncentives && assetData.supplyIncentives.length > 0) {
193
+ let totalApy = '0';
194
+ for (const incentive of assetData.supplyIncentives || []) {
195
+ totalApy = new Dec(totalApy).add(incentive.apy).toString();
196
+ }
197
+ const incentiveInterest = calculateInterestEarned(amount, totalApy, 'year', true);
198
+ acc.incentiveUsd = new Dec(acc.incentiveUsd).add(incentiveInterest).toString();
199
+ } else if (assetData.incentiveSupplyApy) {
169
200
  // take COMP/AAVE yield into account
170
201
  const incentiveInterest = calculateInterestEarned(amount, assetData.incentiveSupplyApy, 'year', true);
171
202
  acc.incentiveUsd = new Dec(acc.incentiveUsd).add(incentiveInterest).toString();
@@ -182,7 +213,14 @@ export const calculateNetApy = ({ usedAssets, assetsData, isMorpho = false }: {
182
213
  : (usedAsset?.interestMode === '1' ? usedAsset.stableBorrowRate : assetData.borrowRate);
183
214
  const borrowInterest = calculateInterestEarned(amount, rate as string, 'year', true);
184
215
  acc.borrowInterest = new Dec(acc.borrowInterest).sub(borrowInterest.toString()).toString();
185
- if (assetData.incentiveBorrowApy) {
216
+ if (assetData.borrowIncentives && assetData.borrowIncentives.length > 0) {
217
+ let totalApy = '0';
218
+ for (const incentive of assetData.borrowIncentives || []) {
219
+ totalApy = new Dec(totalApy).add(incentive.apy).toString();
220
+ }
221
+ const incentiveInterest = calculateInterestEarned(amount, totalApy, 'year', true);
222
+ acc.incentiveUsd = new Dec(acc.incentiveUsd).sub(incentiveInterest).toString();
223
+ } else if (assetData.incentiveBorrowApy) {
186
224
  // take COMP/AAVE yield into account
187
225
  const incentiveInterest = calculateInterestEarned(amount, assetData.incentiveBorrowApy, 'year', true);
188
226
  acc.incentiveUsd = new Dec(acc.incentiveUsd).sub(incentiveInterest).toString();
package/src/types/aave.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import {
2
+ IncentiveData,
2
3
  MMAssetData, MMPositionData, MMUsedAsset, NetworkNumber,
3
4
  } from './common';
4
5
 
@@ -84,12 +85,6 @@ export interface AaveV2AssetData extends AaveAssetData {
84
85
  export interface MorphoAaveV2AssetData extends AaveV2AssetData {
85
86
  }
86
87
 
87
- export interface IncentiveData {
88
- token: string,
89
- apy: string,
90
- incentiveKind?: 'staking' | 'reward';
91
- }
92
-
93
88
  export interface AaveV3AssetData extends AaveAssetData {
94
89
  isIsolated: boolean,
95
90
  isSiloed: boolean,
@@ -12,6 +12,17 @@ export enum NetworkNumber {
12
12
  }
13
13
  export type Networkish = string | NetworkNumber;
14
14
 
15
+ export enum IncentiveKind {
16
+ Staking = 'staking',
17
+ Reward = 'reward',
18
+ }
19
+
20
+ export interface IncentiveData {
21
+ token: string,
22
+ apy: string,
23
+ incentiveKind?: IncentiveKind;
24
+ }
25
+
15
26
  // Common
16
27
  export interface MMAssetData {
17
28
  symbol: string,
@@ -33,6 +44,8 @@ export interface MMAssetData {
33
44
  incentiveSupplyToken?: string,
34
45
  borrowRateP2P?: string,
35
46
  supplyRateP2P?: string,
47
+ supplyIncentives?: IncentiveData[];
48
+ borrowIncentives?: IncentiveData[];
36
49
  }
37
50
 
38
51
  export interface MMAssetsData {
@@ -81,4 +94,4 @@ export interface PositionBalances {
81
94
  debt?: Balances,
82
95
  selling?: Balances,
83
96
  deposited?: Balances,
84
- }
97
+ }
@@ -1,4 +1,4 @@
1
- import { MMUsedAssets, NetworkNumber } from './common';
1
+ import { IncentiveData, MMUsedAssets, NetworkNumber } from './common';
2
2
 
3
3
  export enum MorphoBlueVersions {
4
4
  // MAINNET
@@ -97,14 +97,12 @@ export interface MorphoBlueAssetData {
97
97
  price: string,
98
98
  supplyRate: string,
99
99
  borrowRate: string,
100
- incentiveSupplyApy?: string,
101
- incentiveSupplyToken?: string,
102
- incentiveBorrowApy?: string,
103
- incentiveBorrowToken?: string,
104
100
  totalSupply?: string,
105
101
  totalBorrow?: string,
106
102
  canBeSupplied?: boolean,
107
103
  canBeBorrowed?: boolean,
104
+ supplyIncentives?: IncentiveData[];
105
+ borrowIncentives?: IncentiveData[];
108
106
  }
109
107
 
110
108
  export type MorphoBlueAssetsData = { [key: string]: MorphoBlueAssetData };
@@ -1,7 +1,7 @@
1
1
  import {
2
+ IncentiveData,
2
3
  MMAssetData, MMPositionData, MMUsedAsset, NetworkNumber,
3
4
  } from './common';
4
- import { IncentiveData } from './aave';
5
5
 
6
6
  export enum SparkVersions {
7
7
  SparkV1 = 'v1default',