@defisaver/positions-sdk 2.0.9--dev → 2.0.10-dev-linea-1

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 (104) hide show
  1. package/.mocharc.json +4 -4
  2. package/.nvmrc +1 -1
  3. package/README.md +64 -64
  4. package/cjs/aaveV3/index.js +1 -1
  5. package/cjs/config/contracts.d.ts +194 -33
  6. package/cjs/config/contracts.js +18 -1
  7. package/cjs/contracts.d.ts +1283 -293
  8. package/cjs/helpers/morphoBlueHelpers/index.js +66 -66
  9. package/cjs/markets/aave/index.js +1 -1
  10. package/cjs/markets/aave/marketAssets.d.ts +4 -0
  11. package/cjs/markets/aave/marketAssets.js +5 -1
  12. package/cjs/markets/compound/index.js +11 -0
  13. package/cjs/markets/compound/marketsAssets.d.ts +7 -0
  14. package/cjs/markets/compound/marketsAssets.js +7 -0
  15. package/cjs/markets/spark/marketAssets.d.ts +1 -0
  16. package/cjs/markets/spark/marketAssets.js +1 -0
  17. package/cjs/portfolio/index.js +2 -2
  18. package/cjs/services/viem.d.ts +46 -0
  19. package/cjs/services/viem.js +2 -0
  20. package/cjs/types/common.d.ts +2 -1
  21. package/cjs/types/common.js +1 -0
  22. package/esm/aaveV3/index.js +1 -1
  23. package/esm/config/contracts.d.ts +194 -33
  24. package/esm/config/contracts.js +18 -1
  25. package/esm/contracts.d.ts +1283 -293
  26. package/esm/helpers/morphoBlueHelpers/index.js +66 -66
  27. package/esm/markets/aave/index.js +1 -1
  28. package/esm/markets/aave/marketAssets.d.ts +4 -0
  29. package/esm/markets/aave/marketAssets.js +4 -0
  30. package/esm/markets/compound/index.js +11 -0
  31. package/esm/markets/compound/marketsAssets.d.ts +7 -0
  32. package/esm/markets/compound/marketsAssets.js +7 -0
  33. package/esm/markets/spark/marketAssets.d.ts +1 -0
  34. package/esm/markets/spark/marketAssets.js +1 -0
  35. package/esm/portfolio/index.js +2 -2
  36. package/esm/services/viem.d.ts +46 -0
  37. package/esm/services/viem.js +3 -1
  38. package/esm/types/common.d.ts +2 -1
  39. package/esm/types/common.js +1 -0
  40. package/package.json +47 -47
  41. package/src/aaveV2/index.ts +236 -236
  42. package/src/aaveV3/index.ts +489 -489
  43. package/src/compoundV2/index.ts +240 -240
  44. package/src/compoundV3/index.ts +270 -270
  45. package/src/config/contracts.ts +1107 -1090
  46. package/src/constants/index.ts +6 -6
  47. package/src/contracts.ts +107 -107
  48. package/src/curveUsd/index.ts +250 -250
  49. package/src/eulerV2/index.ts +314 -314
  50. package/src/exchange/index.ts +25 -25
  51. package/src/fluid/index.ts +1568 -1568
  52. package/src/helpers/aaveHelpers/index.ts +170 -170
  53. package/src/helpers/compoundHelpers/index.ts +261 -261
  54. package/src/helpers/curveUsdHelpers/index.ts +40 -40
  55. package/src/helpers/eulerHelpers/index.ts +259 -259
  56. package/src/helpers/fluidHelpers/index.ts +324 -324
  57. package/src/helpers/index.ts +10 -10
  58. package/src/helpers/liquityV2Helpers/index.ts +80 -80
  59. package/src/helpers/llamaLendHelpers/index.ts +53 -53
  60. package/src/helpers/makerHelpers/index.ts +52 -52
  61. package/src/helpers/morphoBlueHelpers/index.ts +390 -390
  62. package/src/helpers/sparkHelpers/index.ts +155 -155
  63. package/src/index.ts +45 -45
  64. package/src/liquity/index.ts +104 -104
  65. package/src/liquityV2/index.ts +408 -408
  66. package/src/llamaLend/index.ts +296 -296
  67. package/src/maker/index.ts +223 -223
  68. package/src/markets/aave/index.ts +116 -116
  69. package/src/markets/aave/marketAssets.ts +49 -44
  70. package/src/markets/compound/index.ts +227 -216
  71. package/src/markets/compound/marketsAssets.ts +90 -83
  72. package/src/markets/curveUsd/index.ts +69 -69
  73. package/src/markets/euler/index.ts +26 -26
  74. package/src/markets/fluid/index.ts +2456 -2456
  75. package/src/markets/index.ts +25 -25
  76. package/src/markets/liquityV2/index.ts +102 -102
  77. package/src/markets/llamaLend/contractAddresses.ts +141 -141
  78. package/src/markets/llamaLend/index.ts +235 -235
  79. package/src/markets/morphoBlue/index.ts +895 -895
  80. package/src/markets/spark/index.ts +29 -29
  81. package/src/markets/spark/marketAssets.ts +11 -10
  82. package/src/moneymarket/moneymarketCommonService.ts +80 -80
  83. package/src/morphoBlue/index.ts +222 -222
  84. package/src/portfolio/index.ts +285 -285
  85. package/src/services/priceService.ts +159 -159
  86. package/src/services/utils.ts +63 -63
  87. package/src/services/viem.ts +32 -30
  88. package/src/setup.ts +8 -8
  89. package/src/spark/index.ts +456 -456
  90. package/src/staking/staking.ts +192 -192
  91. package/src/types/aave.ts +194 -194
  92. package/src/types/common.ts +88 -87
  93. package/src/types/compound.ts +136 -136
  94. package/src/types/curveUsd.ts +121 -121
  95. package/src/types/euler.ts +174 -174
  96. package/src/types/fluid.ts +450 -450
  97. package/src/types/index.ts +11 -11
  98. package/src/types/liquity.ts +30 -30
  99. package/src/types/liquityV2.ts +126 -126
  100. package/src/types/llamaLend.ts +157 -157
  101. package/src/types/maker.ts +63 -63
  102. package/src/types/morphoBlue.ts +194 -194
  103. package/src/types/portfolio.ts +60 -60
  104. package/src/types/spark.ts +137 -137
@@ -1,193 +1,193 @@
1
- import Dec from 'decimal.js';
2
- import memoize from 'memoizee';
3
- import { MMAssetsData, MMUsedAssets } from '../types/common';
4
- import { BLOCKS_IN_A_YEAR } from '../constants';
5
- import { DEFAULT_TIMEOUT } from '../services/utils';
6
-
7
- const getSsrApy = async () => {
8
- try {
9
- const res = await fetch('https://fe.defisaver.com/api/sky/data',
10
- { signal: AbortSignal.timeout(DEFAULT_TIMEOUT) });
11
- const data = await res.json();
12
- return new Dec(data.data.skyData[0].sky_savings_rate_apy).mul(100).toString();
13
- } catch (e) {
14
- console.error('External API Failure: Failed to fetch SSR APY from external API', e);
15
- return '0';
16
- }
17
- };
18
-
19
- const getSuperOETHApy = async () => {
20
- try {
21
- const res = await fetch('https://origin.squids.live/origin-squid/graphql', {
22
- method: 'POST',
23
- headers: {
24
- 'Content-Type': 'application/json',
25
- },
26
- body: JSON.stringify({
27
- query: '\n query OTokenApy($chainId: Int!, $token: String!) {\n oTokenApies(\n limit: 1\n orderBy: timestamp_DESC\n where: {chainId_eq: $chainId, otoken_containsInsensitive: $token}\n ) {\n apy7DayAvg\n apy14DayAvg\n apy30DayAvg\n apr\n apy\n }\n}\n ',
28
- variables: {
29
- token: '0xdbfefd2e8460a6ee4955a68582f85708baea60a3',
30
- chainId: 8453,
31
- },
32
- }),
33
- signal: AbortSignal.timeout(DEFAULT_TIMEOUT),
34
- });
35
-
36
- const data = await res.json();
37
- return new Dec(data.data.oTokenApies[0].apy).mul(100).toString();
38
- } catch (e) {
39
- console.error('External API Failure: Failed to fetch Super OETH APY from external API', e);
40
- return '0';
41
- }
42
- };
43
-
44
- const getApyFromDfsApi = async (asset: string) => {
45
- try {
46
- const res = await fetch(`https://fe.defisaver.com/api/staking/apy?asset=${asset}`,
47
- { signal: AbortSignal.timeout(DEFAULT_TIMEOUT) });
48
- if (!res.ok) throw new Error(`Failed to fetch APY for ${asset}`);
49
- const data = await res.json();
50
- return String(data.apy);
51
- } catch (e) {
52
- console.error(`External API Failure: Failed to fetch APY for ${asset} from DFS API`, e);
53
- return '0';
54
- }
55
- };
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'];
58
-
59
- export const getStakingApy = memoize(async (asset: string) => {
60
- try {
61
- if (asset === 'stETH' || asset === 'wstETH') return await getApyFromDfsApi('wstETH');
62
- if (asset === 'cbETH') return await getApyFromDfsApi('cbETH');
63
- if (asset === 'rETH') return await getApyFromDfsApi('rETH');
64
- if (asset === 'sDAI') return await getApyFromDfsApi('sDAI');
65
- if (asset === 'sUSDe') return await getApyFromDfsApi('sUSDe');
66
- if (asset === 'weETH') return await getApyFromDfsApi('weETH');
67
- if (asset === 'ezETH') return await getApyFromDfsApi('ezETH');
68
- if (asset === 'osETH') return await getApyFromDfsApi('osETH');
69
- if (asset === 'ETHx') return await getApyFromDfsApi('ETHx');
70
- if (asset === 'rsETH' || asset === 'wrsETH') return await getApyFromDfsApi('rsETH');
71
- if (asset === 'pufETH') return await getApyFromDfsApi('pufETH');
72
- if (asset === 'wsuperOETHb') return await getSuperOETHApy();
73
- if (asset === 'sUSDS') return await getSsrApy();
74
- if (asset === 'PT eUSDe May') return await getApyFromDfsApi('PT eUSDe May');
75
- if (asset === 'PT sUSDe July') return await getApyFromDfsApi('PT sUSDe July');
76
- if (asset === 'PT USDe July') return await getApyFromDfsApi('PT USDe July');
77
- if (asset === 'PT eUSDe Aug') return await getApyFromDfsApi('PT eUSDe Aug');
78
- if (asset === 'PT sUSDe Sep') return await getApyFromDfsApi('PT sUSDe Sep');
79
- if (asset === 'PT USDe Sep') return await getApyFromDfsApi('PT USDe Sep');
80
- if (asset === 'tETH') return await getApyFromDfsApi('tETH');
81
- if (asset === 'USDe') return await getApyFromDfsApi('USDe');
82
- } catch (e) {
83
- console.error(`Failed to fetch APY for ${asset}`);
84
- }
85
- return '0';
86
- }, { promise: true, maxAge: 2 * 60 * 1000 });
87
-
88
- export const calculateInterestEarned = (principal: string, interest: string, type: string, apy = false) => {
89
- let interval = 1;
90
-
91
- if (+interest === 0) return 0;
92
-
93
- if (type === 'month') interval = 1 / 12;
94
- if (type === 'week') interval = 1 / 52.1429;
95
-
96
- if (apy) {
97
- // interest rate already compounded
98
- return (+principal * (1 + (+interest / 100 * interval))) - +principal;
99
- }
100
-
101
- return (+principal * (((1 + (+interest / 100) / BLOCKS_IN_A_YEAR)) ** (BLOCKS_IN_A_YEAR * interval))) - +principal; // eslint-disable-line
102
- };
103
-
104
- export const isEligibleForEthenaUSDeRewards = (usedAssets: MMUsedAssets) => {
105
- const USDeUSDAmountSupplied = usedAssets.USDe?.suppliedUsd || '0';
106
- const sUSDeUSDAmountSupplied = usedAssets.sUSDe?.suppliedUsd || '0';
107
- const anythingElseSupplied = Object.values(usedAssets).some((asset) => asset.symbol !== 'USDe' && asset.symbol !== 'sUSDe' && asset.isSupplied);
108
- if (anythingElseSupplied) return { isEligible: false, eligibleUSDAmount: '0' };
109
- const totalAmountSupplied = new Dec(USDeUSDAmountSupplied).add(sUSDeUSDAmountSupplied).toString();
110
- const percentageInUSDe = new Dec(USDeUSDAmountSupplied).div(totalAmountSupplied).toNumber();
111
- if (percentageInUSDe < 0.45 || percentageInUSDe > 0.55) return { isEligible: false, eligibleUSDAmount: '0' }; // 45% - 55% of total amount supplied must be in USDe
112
- const percentageInSUSDe = new Dec(sUSDeUSDAmountSupplied).div(totalAmountSupplied).toNumber();
113
- if (percentageInSUSDe < 0.45 || percentageInSUSDe > 0.55) return { isEligible: false, eligibleUSDAmount: '0' }; // 45% - 55% of total amount supplied must be in sUSDe
114
-
115
- const allowedBorrowAssets = ['USDC', 'USDT', 'USDS'];
116
- const anythingBorrowedNotAllowed = Object.values(usedAssets).some((asset) => asset.isBorrowed && !allowedBorrowAssets.includes(asset.symbol));
117
- if (anythingBorrowedNotAllowed) return { isEligible: false, eligibleUSDAmount: '0' };
118
-
119
- const totalAmountBorrowed = Object.values(usedAssets).reduce((acc, asset) => {
120
- if (asset.isBorrowed) {
121
- return acc.add(asset.borrowedUsd);
122
- }
123
- return acc;
124
- }, new Dec(0)).toString();
125
-
126
- const borrowPercentage = new Dec(totalAmountBorrowed).div(totalAmountSupplied).toNumber();
127
- if (borrowPercentage < 0.5) return { isEligible: false, eligibleUSDAmount: '0' }; // must be looped at least once
128
-
129
- const halfAmountSupplied = new Dec(totalAmountSupplied).div(2).toString();
130
- const USDeAmountEligibleForRewards = Dec.min(USDeUSDAmountSupplied, halfAmountSupplied).toString(); // rewards are given to amount of USDe supplied up to half of total amount supplied
131
-
132
- return { isEligible: true, eligibleUSDAmount: USDeAmountEligibleForRewards };
133
- };
134
-
135
- export const calculateNetApy = ({
136
- usedAssets, assetsData, isMorpho = false, isAave = false,
137
- }: { usedAssets: MMUsedAssets, assetsData: MMAssetsData, isMorpho?: boolean, isAave?: boolean }) => {
138
- const { isEligible, eligibleUSDAmount } = isAave ? isEligibleForEthenaUSDeRewards(usedAssets) : { isEligible: true, eligibleUSDAmount: '0' };
139
- const sumValues = Object.values(usedAssets).reduce((_acc, usedAsset) => {
140
- const acc = { ..._acc };
141
- const assetData = assetsData[usedAsset.symbol];
142
-
143
- if (usedAsset.isSupplied) {
144
- const amount = usedAsset.suppliedUsd;
145
- acc.suppliedUsd = new Dec(acc.suppliedUsd).add(amount).toString();
146
- const rate = isMorpho
147
- ? usedAsset.supplyRate === '0' ? assetData.supplyRateP2P : usedAsset.supplyRate
148
- : assetData.supplyRate;
149
- const supplyInterest = calculateInterestEarned(amount, rate as string, 'year', true);
150
- acc.supplyInterest = new Dec(acc.supplyInterest).add(supplyInterest.toString()).toString();
151
- if (assetData.incentiveSupplyApy) {
152
- // take COMP/AAVE yield into account
153
- const incentiveInterest = calculateInterestEarned(amount, assetData.incentiveSupplyApy, 'year', true);
154
- acc.incentiveUsd = new Dec(acc.incentiveUsd).add(incentiveInterest).toString();
155
- }
156
-
157
- if (usedAsset.symbol === 'USDe' && isEligible) {
158
- // @ts-ignore
159
- const incentiveInterest = calculateInterestEarned(eligibleUSDAmount, assetData.supplyIncentives?.[0]?.apy || '0', 'year', true);
160
- acc.incentiveUsd = new Dec(acc.incentiveUsd).add(incentiveInterest).toString();
161
- }
162
- }
163
-
164
- if (usedAsset.isBorrowed) {
165
- const amount = usedAsset.borrowedUsd;
166
- acc.borrowedUsd = new Dec(acc.borrowedUsd).add(amount).toString();
167
- const rate = isMorpho
168
- ? usedAsset.borrowRate === '0' ? assetData.borrowRateP2P : usedAsset.borrowRate
169
- : (usedAsset?.interestMode === '1' ? usedAsset.stableBorrowRate : assetData.borrowRate);
170
- const borrowInterest = calculateInterestEarned(amount, rate as string, 'year', true);
171
- acc.borrowInterest = new Dec(acc.borrowInterest).sub(borrowInterest.toString()).toString();
172
- if (assetData.incentiveBorrowApy) {
173
- // take COMP/AAVE yield into account
174
- const incentiveInterest = calculateInterestEarned(amount, assetData.incentiveBorrowApy, 'year', true);
175
- acc.incentiveUsd = new Dec(acc.incentiveUsd).sub(incentiveInterest).toString();
176
- }
177
- }
178
-
179
- return acc;
180
- }, {
181
- borrowInterest: '0', supplyInterest: '0', incentiveUsd: '0', borrowedUsd: '0', suppliedUsd: '0',
182
- });
183
-
184
- const {
185
- borrowedUsd, suppliedUsd, borrowInterest, supplyInterest, incentiveUsd,
186
- } = sumValues;
187
-
188
- const totalInterestUsd = new Dec(borrowInterest).add(supplyInterest).add(incentiveUsd).toString();
189
- const balance = new Dec(suppliedUsd).sub(borrowedUsd);
190
- const netApy = new Dec(totalInterestUsd).div(balance).times(100).toString();
191
-
192
- return { netApy, totalInterestUsd, incentiveUsd };
1
+ import Dec from 'decimal.js';
2
+ import memoize from 'memoizee';
3
+ import { MMAssetsData, MMUsedAssets } from '../types/common';
4
+ import { BLOCKS_IN_A_YEAR } from '../constants';
5
+ import { DEFAULT_TIMEOUT } from '../services/utils';
6
+
7
+ const getSsrApy = async () => {
8
+ try {
9
+ const res = await fetch('https://fe.defisaver.com/api/sky/data',
10
+ { signal: AbortSignal.timeout(DEFAULT_TIMEOUT) });
11
+ const data = await res.json();
12
+ return new Dec(data.data.skyData[0].sky_savings_rate_apy).mul(100).toString();
13
+ } catch (e) {
14
+ console.error('External API Failure: Failed to fetch SSR APY from external API', e);
15
+ return '0';
16
+ }
17
+ };
18
+
19
+ const getSuperOETHApy = async () => {
20
+ try {
21
+ const res = await fetch('https://origin.squids.live/origin-squid/graphql', {
22
+ method: 'POST',
23
+ headers: {
24
+ 'Content-Type': 'application/json',
25
+ },
26
+ body: JSON.stringify({
27
+ query: '\n query OTokenApy($chainId: Int!, $token: String!) {\n oTokenApies(\n limit: 1\n orderBy: timestamp_DESC\n where: {chainId_eq: $chainId, otoken_containsInsensitive: $token}\n ) {\n apy7DayAvg\n apy14DayAvg\n apy30DayAvg\n apr\n apy\n }\n}\n ',
28
+ variables: {
29
+ token: '0xdbfefd2e8460a6ee4955a68582f85708baea60a3',
30
+ chainId: 8453,
31
+ },
32
+ }),
33
+ signal: AbortSignal.timeout(DEFAULT_TIMEOUT),
34
+ });
35
+
36
+ const data = await res.json();
37
+ return new Dec(data.data.oTokenApies[0].apy).mul(100).toString();
38
+ } catch (e) {
39
+ console.error('External API Failure: Failed to fetch Super OETH APY from external API', e);
40
+ return '0';
41
+ }
42
+ };
43
+
44
+ const getApyFromDfsApi = async (asset: string) => {
45
+ try {
46
+ const res = await fetch(`https://fe.defisaver.com/api/staking/apy?asset=${asset}`,
47
+ { signal: AbortSignal.timeout(DEFAULT_TIMEOUT) });
48
+ if (!res.ok) throw new Error(`Failed to fetch APY for ${asset}`);
49
+ const data = await res.json();
50
+ return String(data.apy);
51
+ } catch (e) {
52
+ console.error(`External API Failure: Failed to fetch APY for ${asset} from DFS API`, e);
53
+ return '0';
54
+ }
55
+ };
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'];
58
+
59
+ export const getStakingApy = memoize(async (asset: string) => {
60
+ try {
61
+ if (asset === 'stETH' || asset === 'wstETH') return await getApyFromDfsApi('wstETH');
62
+ if (asset === 'cbETH') return await getApyFromDfsApi('cbETH');
63
+ if (asset === 'rETH') return await getApyFromDfsApi('rETH');
64
+ if (asset === 'sDAI') return await getApyFromDfsApi('sDAI');
65
+ if (asset === 'sUSDe') return await getApyFromDfsApi('sUSDe');
66
+ if (asset === 'weETH') return await getApyFromDfsApi('weETH');
67
+ if (asset === 'ezETH') return await getApyFromDfsApi('ezETH');
68
+ if (asset === 'osETH') return await getApyFromDfsApi('osETH');
69
+ if (asset === 'ETHx') return await getApyFromDfsApi('ETHx');
70
+ if (asset === 'rsETH' || asset === 'wrsETH') return await getApyFromDfsApi('rsETH');
71
+ if (asset === 'pufETH') return await getApyFromDfsApi('pufETH');
72
+ if (asset === 'wsuperOETHb') return await getSuperOETHApy();
73
+ if (asset === 'sUSDS') return await getSsrApy();
74
+ if (asset === 'PT eUSDe May') return await getApyFromDfsApi('PT eUSDe May');
75
+ if (asset === 'PT sUSDe July') return await getApyFromDfsApi('PT sUSDe July');
76
+ if (asset === 'PT USDe July') return await getApyFromDfsApi('PT USDe July');
77
+ if (asset === 'PT eUSDe Aug') return await getApyFromDfsApi('PT eUSDe Aug');
78
+ if (asset === 'PT sUSDe Sep') return await getApyFromDfsApi('PT sUSDe Sep');
79
+ if (asset === 'PT USDe Sep') return await getApyFromDfsApi('PT USDe Sep');
80
+ if (asset === 'tETH') return await getApyFromDfsApi('tETH');
81
+ if (asset === 'USDe') return await getApyFromDfsApi('USDe');
82
+ } catch (e) {
83
+ console.error(`Failed to fetch APY for ${asset}`);
84
+ }
85
+ return '0';
86
+ }, { promise: true, maxAge: 2 * 60 * 1000 });
87
+
88
+ export const calculateInterestEarned = (principal: string, interest: string, type: string, apy = false) => {
89
+ let interval = 1;
90
+
91
+ if (+interest === 0) return 0;
92
+
93
+ if (type === 'month') interval = 1 / 12;
94
+ if (type === 'week') interval = 1 / 52.1429;
95
+
96
+ if (apy) {
97
+ // interest rate already compounded
98
+ return (+principal * (1 + (+interest / 100 * interval))) - +principal;
99
+ }
100
+
101
+ return (+principal * (((1 + (+interest / 100) / BLOCKS_IN_A_YEAR)) ** (BLOCKS_IN_A_YEAR * interval))) - +principal; // eslint-disable-line
102
+ };
103
+
104
+ export const isEligibleForEthenaUSDeRewards = (usedAssets: MMUsedAssets) => {
105
+ const USDeUSDAmountSupplied = usedAssets.USDe?.suppliedUsd || '0';
106
+ const sUSDeUSDAmountSupplied = usedAssets.sUSDe?.suppliedUsd || '0';
107
+ const anythingElseSupplied = Object.values(usedAssets).some((asset) => asset.symbol !== 'USDe' && asset.symbol !== 'sUSDe' && asset.isSupplied);
108
+ if (anythingElseSupplied) return { isEligible: false, eligibleUSDAmount: '0' };
109
+ const totalAmountSupplied = new Dec(USDeUSDAmountSupplied).add(sUSDeUSDAmountSupplied).toString();
110
+ const percentageInUSDe = new Dec(USDeUSDAmountSupplied).div(totalAmountSupplied).toNumber();
111
+ if (percentageInUSDe < 0.45 || percentageInUSDe > 0.55) return { isEligible: false, eligibleUSDAmount: '0' }; // 45% - 55% of total amount supplied must be in USDe
112
+ const percentageInSUSDe = new Dec(sUSDeUSDAmountSupplied).div(totalAmountSupplied).toNumber();
113
+ if (percentageInSUSDe < 0.45 || percentageInSUSDe > 0.55) return { isEligible: false, eligibleUSDAmount: '0' }; // 45% - 55% of total amount supplied must be in sUSDe
114
+
115
+ const allowedBorrowAssets = ['USDC', 'USDT', 'USDS'];
116
+ const anythingBorrowedNotAllowed = Object.values(usedAssets).some((asset) => asset.isBorrowed && !allowedBorrowAssets.includes(asset.symbol));
117
+ if (anythingBorrowedNotAllowed) return { isEligible: false, eligibleUSDAmount: '0' };
118
+
119
+ const totalAmountBorrowed = Object.values(usedAssets).reduce((acc, asset) => {
120
+ if (asset.isBorrowed) {
121
+ return acc.add(asset.borrowedUsd);
122
+ }
123
+ return acc;
124
+ }, new Dec(0)).toString();
125
+
126
+ const borrowPercentage = new Dec(totalAmountBorrowed).div(totalAmountSupplied).toNumber();
127
+ if (borrowPercentage < 0.5) return { isEligible: false, eligibleUSDAmount: '0' }; // must be looped at least once
128
+
129
+ const halfAmountSupplied = new Dec(totalAmountSupplied).div(2).toString();
130
+ const USDeAmountEligibleForRewards = Dec.min(USDeUSDAmountSupplied, halfAmountSupplied).toString(); // rewards are given to amount of USDe supplied up to half of total amount supplied
131
+
132
+ return { isEligible: true, eligibleUSDAmount: USDeAmountEligibleForRewards };
133
+ };
134
+
135
+ export const calculateNetApy = ({
136
+ usedAssets, assetsData, isMorpho = false, isAave = false,
137
+ }: { usedAssets: MMUsedAssets, assetsData: MMAssetsData, isMorpho?: boolean, isAave?: boolean }) => {
138
+ const { isEligible, eligibleUSDAmount } = isAave ? isEligibleForEthenaUSDeRewards(usedAssets) : { isEligible: true, eligibleUSDAmount: '0' };
139
+ const sumValues = Object.values(usedAssets).reduce((_acc, usedAsset) => {
140
+ const acc = { ..._acc };
141
+ const assetData = assetsData[usedAsset.symbol];
142
+
143
+ if (usedAsset.isSupplied) {
144
+ const amount = usedAsset.suppliedUsd;
145
+ acc.suppliedUsd = new Dec(acc.suppliedUsd).add(amount).toString();
146
+ const rate = isMorpho
147
+ ? usedAsset.supplyRate === '0' ? assetData.supplyRateP2P : usedAsset.supplyRate
148
+ : assetData.supplyRate;
149
+ const supplyInterest = calculateInterestEarned(amount, rate as string, 'year', true);
150
+ acc.supplyInterest = new Dec(acc.supplyInterest).add(supplyInterest.toString()).toString();
151
+ if (assetData.incentiveSupplyApy) {
152
+ // take COMP/AAVE yield into account
153
+ const incentiveInterest = calculateInterestEarned(amount, assetData.incentiveSupplyApy, 'year', true);
154
+ acc.incentiveUsd = new Dec(acc.incentiveUsd).add(incentiveInterest).toString();
155
+ }
156
+
157
+ if (usedAsset.symbol === 'USDe' && isEligible) {
158
+ // @ts-ignore
159
+ const incentiveInterest = calculateInterestEarned(eligibleUSDAmount, assetData.supplyIncentives?.[0]?.apy || '0', 'year', true);
160
+ acc.incentiveUsd = new Dec(acc.incentiveUsd).add(incentiveInterest).toString();
161
+ }
162
+ }
163
+
164
+ if (usedAsset.isBorrowed) {
165
+ const amount = usedAsset.borrowedUsd;
166
+ acc.borrowedUsd = new Dec(acc.borrowedUsd).add(amount).toString();
167
+ const rate = isMorpho
168
+ ? usedAsset.borrowRate === '0' ? assetData.borrowRateP2P : usedAsset.borrowRate
169
+ : (usedAsset?.interestMode === '1' ? usedAsset.stableBorrowRate : assetData.borrowRate);
170
+ const borrowInterest = calculateInterestEarned(amount, rate as string, 'year', true);
171
+ acc.borrowInterest = new Dec(acc.borrowInterest).sub(borrowInterest.toString()).toString();
172
+ if (assetData.incentiveBorrowApy) {
173
+ // take COMP/AAVE yield into account
174
+ const incentiveInterest = calculateInterestEarned(amount, assetData.incentiveBorrowApy, 'year', true);
175
+ acc.incentiveUsd = new Dec(acc.incentiveUsd).sub(incentiveInterest).toString();
176
+ }
177
+ }
178
+
179
+ return acc;
180
+ }, {
181
+ borrowInterest: '0', supplyInterest: '0', incentiveUsd: '0', borrowedUsd: '0', suppliedUsd: '0',
182
+ });
183
+
184
+ const {
185
+ borrowedUsd, suppliedUsd, borrowInterest, supplyInterest, incentiveUsd,
186
+ } = sumValues;
187
+
188
+ const totalInterestUsd = new Dec(borrowInterest).add(supplyInterest).add(incentiveUsd).toString();
189
+ const balance = new Dec(suppliedUsd).sub(borrowedUsd);
190
+ const netApy = new Dec(totalInterestUsd).div(balance).times(100).toString();
191
+
192
+ return { netApy, totalInterestUsd, incentiveUsd };
193
193
  };