@defisaver/positions-sdk 2.1.161-portfolio-api-1-dev → 2.1.161-portfolio-api-3-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.
Files changed (193) hide show
  1. package/cjs/aaveV2/index.js +2 -0
  2. package/cjs/aaveV3/index.d.ts +41 -12
  3. package/cjs/aaveV3/index.js +237 -2
  4. package/cjs/aaveV3/sgho.d.ts +2 -16
  5. package/cjs/aaveV4/lend.d.ts +2 -43
  6. package/cjs/claiming/aaveV3.d.ts +2 -2
  7. package/cjs/claiming/ethena.d.ts +2 -1
  8. package/cjs/claiming/king.d.ts +2 -1
  9. package/cjs/claiming/spark.d.ts +2 -2
  10. package/cjs/curveUsd/index.d.ts +5 -2
  11. package/cjs/curveUsd/index.js +30 -15
  12. package/cjs/fluid/index.d.ts +10 -49
  13. package/cjs/fluid/index.js +36 -1
  14. package/cjs/helpers/aaveHelpers/index.d.ts +9 -1
  15. package/cjs/helpers/aaveHelpers/index.js +26 -6
  16. package/cjs/helpers/aaveV4Helpers/index.js +1 -0
  17. package/cjs/helpers/compoundHelpers/index.js +2 -0
  18. package/cjs/helpers/curveUsdHelpers/index.d.ts +3 -1
  19. package/cjs/helpers/curveUsdHelpers/index.js +15 -2
  20. package/cjs/helpers/fluidHelpers/index.js +1 -0
  21. package/cjs/helpers/liquityV2Helpers/index.js +1 -0
  22. package/cjs/helpers/llamaLendHelpers/index.js +1 -0
  23. package/cjs/helpers/makerHelpers/index.d.ts +1 -1
  24. package/cjs/helpers/makerHelpers/index.js +2 -2
  25. package/cjs/helpers/morphoBlueHelpers/index.js +2 -0
  26. package/cjs/helpers/morphoMidnightHelpers/index.js +2 -0
  27. package/cjs/helpers/sparkHelpers/index.js +1 -0
  28. package/cjs/liquity/index.d.ts +2 -12
  29. package/cjs/liquity/index.js +15 -2
  30. package/cjs/liquityV2/index.d.ts +8 -23
  31. package/cjs/liquityV2/index.js +37 -19
  32. package/cjs/maker/index.d.ts +7 -2
  33. package/cjs/maker/index.js +44 -12
  34. package/cjs/markets/index.d.ts +1 -0
  35. package/cjs/markets/index.js +3 -1
  36. package/cjs/markets/maker/index.d.ts +1 -0
  37. package/cjs/markets/maker/index.js +13 -0
  38. package/cjs/moneymarket/moneymarketCommonService.d.ts +9 -0
  39. package/cjs/moneymarket/moneymarketCommonService.js +13 -1
  40. package/cjs/portfolio/index.d.ts +17 -5
  41. package/cjs/portfolio/index.js +583 -381
  42. package/cjs/portfolio/lendingProtocols.d.ts +184 -0
  43. package/cjs/portfolio/lendingProtocols.js +196 -0
  44. package/cjs/savings/index.d.ts +8 -2
  45. package/cjs/savings/index.js +37 -5
  46. package/cjs/savings/morphoVaults/index.d.ts +1 -1
  47. package/cjs/savings/morphoVaults/index.js +56 -18
  48. package/cjs/savings/morphoVaults/options.d.ts +2 -0
  49. package/cjs/savings/morphoVaults/options.js +61 -1
  50. package/cjs/spark/index.js +1 -0
  51. package/cjs/staking/staking.d.ts +20 -0
  52. package/cjs/staking/staking.js +19 -1
  53. package/cjs/types/aave.d.ts +86 -0
  54. package/cjs/types/aaveV4.d.ts +45 -0
  55. package/cjs/types/compound.d.ts +2 -0
  56. package/cjs/types/curveUsd.d.ts +6 -0
  57. package/cjs/types/fluid.d.ts +14 -0
  58. package/cjs/types/index.d.ts +1 -0
  59. package/cjs/types/index.js +1 -0
  60. package/cjs/types/liquity.d.ts +16 -0
  61. package/cjs/types/liquityV2.d.ts +26 -0
  62. package/cjs/types/maker.d.ts +4 -0
  63. package/cjs/types/morphoBlue.d.ts +2 -0
  64. package/cjs/types/morphoMidnight.d.ts +1 -0
  65. package/cjs/types/portfolio.d.ts +127 -6
  66. package/cjs/types/savings/index.d.ts +9 -1
  67. package/cjs/types/savings/morphoVaults.d.ts +10 -2
  68. package/cjs/types/savings/morphoVaults.js +9 -1
  69. package/cjs/types/spark.d.ts +2 -0
  70. package/cjs/umbrella/index.d.ts +2 -3
  71. package/esm/aaveV2/index.js +2 -0
  72. package/esm/aaveV3/index.d.ts +41 -12
  73. package/esm/aaveV3/index.js +231 -2
  74. package/esm/aaveV3/sgho.d.ts +2 -16
  75. package/esm/aaveV4/lend.d.ts +2 -43
  76. package/esm/claiming/aaveV3.d.ts +2 -2
  77. package/esm/claiming/aaveV3.js +1 -1
  78. package/esm/claiming/ethena.d.ts +2 -1
  79. package/esm/claiming/king.d.ts +2 -1
  80. package/esm/claiming/spark.d.ts +2 -2
  81. package/esm/claiming/spark.js +1 -1
  82. package/esm/curveUsd/index.d.ts +5 -2
  83. package/esm/curveUsd/index.js +30 -15
  84. package/esm/fluid/index.d.ts +10 -49
  85. package/esm/fluid/index.js +33 -0
  86. package/esm/helpers/aaveHelpers/index.d.ts +9 -1
  87. package/esm/helpers/aaveHelpers/index.js +23 -5
  88. package/esm/helpers/aaveV4Helpers/index.js +1 -0
  89. package/esm/helpers/compoundHelpers/index.js +2 -0
  90. package/esm/helpers/curveUsdHelpers/index.d.ts +3 -1
  91. package/esm/helpers/curveUsdHelpers/index.js +16 -3
  92. package/esm/helpers/fluidHelpers/index.js +1 -0
  93. package/esm/helpers/liquityV2Helpers/index.js +1 -0
  94. package/esm/helpers/llamaLendHelpers/index.js +2 -1
  95. package/esm/helpers/makerHelpers/index.d.ts +1 -1
  96. package/esm/helpers/makerHelpers/index.js +2 -2
  97. package/esm/helpers/morphoBlueHelpers/index.js +2 -0
  98. package/esm/helpers/morphoMidnightHelpers/index.js +2 -0
  99. package/esm/helpers/sparkHelpers/index.js +1 -0
  100. package/esm/liquity/index.d.ts +2 -12
  101. package/esm/liquity/index.js +16 -3
  102. package/esm/liquityV2/index.d.ts +8 -23
  103. package/esm/liquityV2/index.js +35 -18
  104. package/esm/maker/index.d.ts +7 -2
  105. package/esm/maker/index.js +44 -14
  106. package/esm/markets/index.d.ts +1 -0
  107. package/esm/markets/index.js +1 -0
  108. package/esm/markets/maker/index.d.ts +1 -0
  109. package/esm/markets/maker/index.js +10 -0
  110. package/esm/moneymarket/moneymarketCommonService.d.ts +9 -0
  111. package/esm/moneymarket/moneymarketCommonService.js +11 -0
  112. package/esm/portfolio/index.d.ts +17 -5
  113. package/esm/portfolio/index.js +584 -385
  114. package/esm/portfolio/lendingProtocols.d.ts +184 -0
  115. package/esm/portfolio/lendingProtocols.js +189 -0
  116. package/esm/savings/index.d.ts +8 -2
  117. package/esm/savings/index.js +35 -4
  118. package/esm/savings/morphoVaults/index.d.ts +1 -1
  119. package/esm/savings/morphoVaults/index.js +57 -19
  120. package/esm/savings/morphoVaults/options.d.ts +2 -0
  121. package/esm/savings/morphoVaults/options.js +61 -1
  122. package/esm/spark/index.js +1 -0
  123. package/esm/staking/staking.d.ts +20 -0
  124. package/esm/staking/staking.js +17 -0
  125. package/esm/types/aave.d.ts +86 -0
  126. package/esm/types/aaveV4.d.ts +45 -0
  127. package/esm/types/compound.d.ts +2 -0
  128. package/esm/types/curveUsd.d.ts +6 -0
  129. package/esm/types/fluid.d.ts +14 -0
  130. package/esm/types/index.d.ts +1 -0
  131. package/esm/types/index.js +1 -0
  132. package/esm/types/liquity.d.ts +16 -0
  133. package/esm/types/liquityV2.d.ts +26 -0
  134. package/esm/types/maker.d.ts +4 -0
  135. package/esm/types/morphoBlue.d.ts +2 -0
  136. package/esm/types/morphoMidnight.d.ts +1 -0
  137. package/esm/types/portfolio.d.ts +127 -6
  138. package/esm/types/savings/index.d.ts +9 -1
  139. package/esm/types/savings/morphoVaults.d.ts +10 -2
  140. package/esm/types/savings/morphoVaults.js +8 -0
  141. package/esm/types/spark.d.ts +2 -0
  142. package/esm/umbrella/index.d.ts +2 -3
  143. package/package.json +3 -2
  144. package/src/aaveV2/index.ts +2 -0
  145. package/src/aaveV3/index.ts +293 -2
  146. package/src/aaveV3/sgho.ts +2 -17
  147. package/src/aaveV4/lend.ts +2 -48
  148. package/src/claiming/aaveV3.ts +4 -2
  149. package/src/claiming/ethena.ts +5 -5
  150. package/src/claiming/king.ts +3 -3
  151. package/src/claiming/spark.ts +6 -4
  152. package/src/curveUsd/index.ts +33 -16
  153. package/src/fluid/index.ts +44 -3
  154. package/src/helpers/aaveHelpers/index.ts +27 -7
  155. package/src/helpers/aaveV4Helpers/index.ts +1 -0
  156. package/src/helpers/compoundHelpers/index.ts +2 -0
  157. package/src/helpers/curveUsdHelpers/index.ts +23 -3
  158. package/src/helpers/fluidHelpers/index.ts +1 -0
  159. package/src/helpers/liquityV2Helpers/index.ts +1 -0
  160. package/src/helpers/llamaLendHelpers/index.ts +2 -1
  161. package/src/helpers/makerHelpers/index.ts +2 -1
  162. package/src/helpers/morphoBlueHelpers/index.ts +2 -0
  163. package/src/helpers/morphoMidnightHelpers/index.ts +2 -0
  164. package/src/helpers/sparkHelpers/index.ts +1 -0
  165. package/src/liquity/index.ts +19 -5
  166. package/src/liquityV2/index.ts +48 -22
  167. package/src/maker/index.ts +77 -30
  168. package/src/markets/index.ts +2 -1
  169. package/src/markets/maker/index.ts +10 -0
  170. package/src/moneymarket/moneymarketCommonService.ts +15 -0
  171. package/src/portfolio/index.ts +477 -248
  172. package/src/portfolio/lendingProtocols.ts +281 -0
  173. package/src/savings/index.ts +45 -5
  174. package/src/savings/morphoVaults/index.ts +73 -21
  175. package/src/savings/morphoVaults/options.ts +67 -1
  176. package/src/spark/index.ts +1 -0
  177. package/src/staking/staking.ts +28 -0
  178. package/src/types/aave.ts +90 -0
  179. package/src/types/aaveV4.ts +50 -0
  180. package/src/types/compound.ts +2 -0
  181. package/src/types/curveUsd.ts +7 -0
  182. package/src/types/fluid.ts +15 -0
  183. package/src/types/index.ts +2 -1
  184. package/src/types/liquity.ts +19 -1
  185. package/src/types/liquityV2.ts +28 -1
  186. package/src/types/maker.ts +6 -0
  187. package/src/types/morphoBlue.ts +2 -0
  188. package/src/types/morphoMidnight.ts +1 -0
  189. package/src/types/portfolio.ts +153 -7
  190. package/src/types/savings/index.ts +12 -1
  191. package/src/types/savings/morphoVaults.ts +11 -1
  192. package/src/types/spark.ts +2 -0
  193. package/src/umbrella/index.ts +2 -1
@@ -7,26 +7,9 @@ import {
7
7
  EthereumProvider,
8
8
  NetworkNumber,
9
9
  } from '../types/common';
10
+ import { AaveV4TokenizationSpokeDataParsed } from '../types/aaveV4';
10
11
 
11
- export interface AaveV4TokenizationSpokeData {
12
- underlyingAsset: EthAddress;
13
- assetId: string;
14
- decimals: number;
15
- spoke: EthAddress;
16
- spokeActive: boolean;
17
- spokeHalted: boolean;
18
- spokeDepositCap: string;
19
- spokeTotalAssets: string;
20
- spokeTotalShares: string;
21
- hub: EthAddress;
22
- hubLiquidity: string;
23
- hubDrawnRate: string;
24
- convertToShares: string;
25
- convertToAssets: string;
26
- user: EthAddress;
27
- userSuppliedAssets: string;
28
- userSuppliedShares: string;
29
- }
12
+ export type { AaveV4TokenizationSpokeData, AaveV4TokenizationSpokeDataParsed } from '../types/aaveV4';
30
13
 
31
14
  export const AAVE_V4_TOKENIZED_SPOKES: Record<string, EthAddress> = {
32
15
  EURC_CORE: '0x6D9e2Cdd61CaF69af99b275704B6e272C41c6718',
@@ -102,34 +85,6 @@ export const aaveV4GetTokenizedVaultAddress = (
102
85
  return AAVE_V4_TOKENIZED_SPOKES[key];
103
86
  };
104
87
 
105
- /** Parsed tokenization spoke data with human-readable supplied amounts for display */
106
- export interface AaveV4TokenizationSpokeDataParsed {
107
- vaultAddress: EthAddress;
108
- key: string | null;
109
- symbol: string;
110
- hubKey: string;
111
- // ---- Spoke ----
112
- spokeActive: boolean;
113
- spokeHalted: boolean;
114
- /** Deposit cap in asset units (wei string) */
115
- spokeDepositCap: string;
116
- /** Total assets currently in spoke in asset units (wei string) */
117
- spokeTotalAssets: string;
118
- // ---- Hub ----
119
- /** Available hub liquidity in asset units (wei string) */
120
- hubLiquidity: string;
121
- /** The conversion rate from assets to shares expressed in asset units. */
122
- convertToShares: string;
123
- // ---- User ----
124
- userSuppliedAssetsEth: string;
125
- userSuppliedSharesEth: string;
126
- userSuppliedAssets: string;
127
- userSuppliedShares: string;
128
- underlyingAsset: EthAddress;
129
- spoke: EthAddress;
130
- decimals: number;
131
- }
132
-
133
88
  const AAVE_V4_TOKENIZED_SPOKE_ADDRESS_TO_KEY: Record<string, string> = Object.entries(
134
89
  AAVE_V4_TOKENIZED_SPOKES,
135
90
  ).reduce((acc, [k, v]) => {
@@ -189,4 +144,3 @@ export async function getAaveV4TokenizationSpokesData(
189
144
  }).filter(item => item != null);
190
145
  }
191
146
 
192
-
@@ -1,7 +1,9 @@
1
1
  import { Client } from 'viem';
2
2
  import Dec from 'decimal.js';
3
3
  import { EthAddress, NetworkNumber } from '../types';
4
- import { ClaimableToken, ClaimType, MerklRewardsClaimableToken } from '../types/claiming';
4
+ import {
5
+ AaveRewardsClaimableToken, ClaimableToken, ClaimType, MerklRewardsClaimableToken,
6
+ } from '../types/claiming';
5
7
  import {
6
8
  AaveIncentiveDataProviderV3ContractViem,
7
9
  AaveRewardsControllerViem,
@@ -37,7 +39,7 @@ export async function getUnclaimedRewardsForAllMarkets(
37
39
  network: NetworkNumber,
38
40
  walletAddress: EthAddress,
39
41
  marketAddress: EthAddress,
40
- ): Promise<ClaimableToken[]> {
42
+ ): Promise<AaveRewardsClaimableToken[]> {
41
43
  const contract = AaveIncentiveDataProviderV3ContractViem(provider, network);
42
44
  const tokensData = await contract.read.getUserReservesIncentivesData([marketAddress, walletAddress]);
43
45
  const allTokensDataArrays = tokensData.reduce((acc: any[], val) => {
@@ -2,7 +2,7 @@ import { getAssetInfo } from '@defisaver/tokens';
2
2
  import Dec from 'decimal.js';
3
3
  import { getAddress } from 'viem';
4
4
  import { EthAddress } from '../types/common';
5
- import { ClaimType } from '../types/claiming';
5
+ import { ClaimType, EthenaAirdropClaimableToken } from '../types/claiming';
6
6
  import { getEthAmountForDecimals } from '../services/utils';
7
7
 
8
8
  export const fetchEthenaAirdropReward = async (address: EthAddress) => {
@@ -23,11 +23,11 @@ export const fetchEthenaAirdropReward = async (address: EthAddress) => {
23
23
  }
24
24
  };
25
25
 
26
- export const fetchEthenaAirdropRewards = async (walletAddresses: EthAddress[]): Promise<Record<string, any[]>> => {
26
+ export const fetchEthenaAirdropRewards = async (walletAddresses: EthAddress[]): Promise<Record<string, EthenaAirdropClaimableToken[]>> => {
27
27
  const apiDataPromises = walletAddresses.map(address => fetchEthenaAirdropReward(address));
28
28
  const apiDataArray = await Promise.all(apiDataPromises);
29
29
 
30
- const results: Record<string, any[]> = {};
30
+ const results: Record<string, EthenaAirdropClaimableToken[]> = {};
31
31
  for (let i = 0; i < walletAddresses.length; i++) {
32
32
  const walletAddress = walletAddresses[i];
33
33
  const data = apiDataArray[i];
@@ -36,7 +36,7 @@ export const fetchEthenaAirdropRewards = async (walletAddresses: EthAddress[]):
36
36
  continue;
37
37
  }
38
38
 
39
- const processedRewards = [];
39
+ const processedRewards: EthenaAirdropClaimableToken[] = [];
40
40
  const assetInfo = getAssetInfo('sENA');
41
41
 
42
42
  const amount = getEthAmountForDecimals(data.events[0].awardAmount, assetInfo.decimals);
@@ -47,7 +47,7 @@ export const fetchEthenaAirdropRewards = async (walletAddresses: EthAddress[]):
47
47
  underlyingSymbol: assetInfo.symbol,
48
48
  amount,
49
49
  claimType: ClaimType.ETHENA_AIRDROP,
50
- tokenAddress: assetInfo.address,
50
+ tokenAddress: assetInfo.address as EthAddress,
51
51
  walletAddress,
52
52
  label: 'Ethena Airdrop',
53
53
  });
@@ -3,7 +3,7 @@ import { assetAmountInEth } from '@defisaver/tokens';
3
3
  import { Client } from 'viem';
4
4
  import { UUPSViem } from '../contracts';
5
5
  import { EthAddress, HexString, NetworkNumber } from '../types/common';
6
- import { ClaimType } from '../types/claiming';
6
+ import { ClaimType, KingRewardsClaimableToken } from '../types/claiming';
7
7
 
8
8
  export const fetchKingRewards = async (walletAddress: EthAddress) => {
9
9
  try {
@@ -19,7 +19,7 @@ export const fetchKingRewards = async (walletAddress: EthAddress) => {
19
19
  }
20
20
  };
21
21
 
22
- export const getKingRewards = async (provider: Client, network: NetworkNumber, walletAddresses: EthAddress[]) => {
22
+ export const getKingRewards = async (provider: Client, network: NetworkNumber, walletAddresses: EthAddress[]): Promise<Record<string, KingRewardsClaimableToken[]>> => {
23
23
  // Fetch all API data in parallel (these are external API calls, can't be batched with multicall)
24
24
  const apiDataPromises = walletAddresses.map(address => fetchKingRewards(address));
25
25
  const apiDataArray = await Promise.all(apiDataPromises);
@@ -31,7 +31,7 @@ export const getKingRewards = async (provider: Client, network: NetworkNumber, w
31
31
  const cumulativeResults = await Promise.all(cumulativePromises);
32
32
 
33
33
  // Process results
34
- const results: Record<string, any[]> = {};
34
+ const results: Record<string, KingRewardsClaimableToken[]> = {};
35
35
 
36
36
  for (let i = 0; i < walletAddresses.length; i++) {
37
37
  const walletAddress = walletAddresses[i];
@@ -7,7 +7,9 @@ import {
7
7
  SparkRewardsControllerViem,
8
8
  } from '../contracts';
9
9
  import { EthAddress, NetworkNumber } from '../types/common';
10
- import { ClaimType, SparkAirdropType, SparkRewardsClaimableToken } from '../types/claiming';
10
+ import {
11
+ ClaimType, SparkAirdropClaimableToken, SparkAirdropType, SparkRewardsClaimableToken,
12
+ } from '../types/claiming';
11
13
  import { compareAddresses, getEthAmountForDecimals } from '../services/utils';
12
14
 
13
15
  const IGNITION_REWARDS = '0xCBA0C0a2a0B6Bb11233ec4EA85C5bFfea33e724d';
@@ -50,7 +52,7 @@ export const fetchSparkAirdropRewards = async (
50
52
  provider: Client,
51
53
  network: NetworkNumber,
52
54
  walletAddresses: EthAddress[],
53
- ) => {
55
+ ): Promise<Record<string, SparkAirdropClaimableToken[]>> => {
54
56
  // Fetch all API data in parallel (these are external API calls, can't be batched with multicall)
55
57
  const apiDataPromises = walletAddresses.map(address => fetchSpkAirdropRewards(address));
56
58
  const apiDataArray = await Promise.all(apiDataPromises);
@@ -92,7 +94,7 @@ export const fetchSparkAirdropRewards = async (
92
94
  const cumulativeClaimedAmounts = await getCumulativeClaimedSpkAirdrop(provider, network, contractCallsData);
93
95
 
94
96
  // Process results
95
- const results: Record<string, any[]> = {};
97
+ const results: Record<string, SparkAirdropClaimableToken[]> = {};
96
98
  let contractCallIndex = 0;
97
99
 
98
100
  for (const { walletAddress, data } of allClaimData) {
@@ -101,7 +103,7 @@ export const fetchSparkAirdropRewards = async (
101
103
  continue;
102
104
  }
103
105
 
104
- const processedRewards = [];
106
+ const processedRewards: SparkAirdropClaimableToken[] = [];
105
107
  for (let i = 0; i < data.length; i++) {
106
108
  const rewardInfo = data[i];
107
109
  const assetInfo = getAssetInfoByAddress(rewardInfo.token_address);
@@ -14,6 +14,13 @@ import { getCrvUsdAggregatedData } from '../helpers/curveUsdHelpers';
14
14
  import { CrvUsdMarkets } from '../markets';
15
15
  import { wethToEth } from '../services/utils';
16
16
  import { getViemProvider, setViemBlockNumber } from '../services/viem';
17
+ import { getStakingApy, STAKING_ASSETS } from '../staking';
18
+
19
+ /** Converts a per-second AMM rate (wei, 18 decimals) into a yearly compounded borrow APY in %. */
20
+ const ammRateToBorrowApy = (rateWei: string) => {
21
+ const exponent = new Dec(assetAmountInEth(rateWei)).mul(365).mul(86400);
22
+ return new Dec(new Dec(2.718281828459).pow(exponent).minus(1)).mul(100).toString();
23
+ };
17
24
 
18
25
  const getAndFormatBands = async (provider: Client, network: NetworkNumber, selectedMarket: CrvUSDMarketData, _minBand: string, _maxBand: string) => {
19
26
  const contract = CrvUSDViewContractViem(provider, network);
@@ -69,15 +76,8 @@ export const _getCurveUsdGlobalData = async (provider: Client, network: NetworkN
69
76
  const totalDebt = assetAmountInEth(data.totalDebt.toString(), debtAsset);
70
77
  const ammPrice = assetAmountInEth(data.ammPrice.toString(), debtAsset);
71
78
 
72
- const rate = assetAmountInEth(data.ammRate.toString());
73
- const futureRate = assetAmountInEth(data.monetaryPolicyRate.toString());
74
-
75
- const exponentRate = new Dec(rate).mul(365).mul(86400);
76
- const exponentFutureRate = new Dec(futureRate).mul(365).mul(86400);
77
- const borrowRate = new Dec(new Dec(2.718281828459).pow(exponentRate).minus(1)).mul(100)
78
- .toString();
79
- const futureBorrowRate = new Dec(new Dec(2.718281828459).pow(exponentFutureRate).minus(1)).mul(100)
80
- .toString();
79
+ const borrowRate = ammRateToBorrowApy(data.ammRate.toString());
80
+ const futureBorrowRate = ammRateToBorrowApy(data.monetaryPolicyRate.toString());
81
81
 
82
82
  const bandsData = await getAndFormatBands(provider, network, selectedMarket, data.minBand.toString(), data.maxBand.toString());
83
83
 
@@ -164,13 +164,22 @@ export const getCrvUsdAccountBalances = async (
164
164
  controllerAddress: EthAddress,
165
165
  ): Promise<PositionBalances> => _getCrvUsdAccountBalances(getViemProvider(provider, network), network, block, addressMapping, address, controllerAddress);
166
166
 
167
- export const _getCurveUsdUserData = async (provider: Client, network: NetworkNumber, address: EthAddress, selectedMarket: CrvUSDMarketData, activeBand: string): Promise<CrvUSDUserData> => {
167
+ /**
168
+ * @param borrowRate market borrow APY in % (`CrvUSDGlobalMarketData.borrowRate`); when omitted it is read from the view contract
169
+ */
170
+ export const _getCurveUsdUserData = async (provider: Client, network: NetworkNumber, address: EthAddress, selectedMarket: CrvUSDMarketData, activeBand: string, borrowRate?: string): Promise<CrvUSDUserData> => {
168
171
  const contract = CrvUSDViewContractViem(provider, network);
169
-
170
- const data = await contract.read.userData([selectedMarket.controllerAddress, address]);
171
172
  const collAsset = selectedMarket.collAsset;
172
173
  const debtAsset = selectedMarket.baseAsset;
173
174
 
175
+ const [data, collStakingApy, marketBorrowRate] = await Promise.all([
176
+ contract.read.userData([selectedMarket.controllerAddress, address]),
177
+ STAKING_ASSETS.includes(collAsset) ? getStakingApy(collAsset) : Promise.resolve('0'),
178
+ borrowRate !== undefined
179
+ ? Promise.resolve(borrowRate)
180
+ : contract.read.globalData([selectedMarket.controllerAddress]).then((globalData) => ammRateToBorrowApy(globalData.ammRate.toString())),
181
+ ]);
182
+
174
183
  const health = assetAmountInEth(data.health.toString());
175
184
  const healthPercent = new Dec(health).mul(100).toString();
176
185
  const collPrice = assetAmountInEth(data.collateralPrice.toString(), debtAsset);
@@ -202,7 +211,7 @@ export const _getCurveUsdUserData = async (provider: Client, network: NetworkNum
202
211
  isBorrowed: new Dec(debtBorrowed).gt('0'),
203
212
  symbol: 'crvUSD',
204
213
  price: '1',
205
- interestRate: '0',
214
+ interestRate: marketBorrowRate,
206
215
  },
207
216
  } : {};
208
217
 
@@ -232,8 +241,15 @@ export const _getCurveUsdUserData = async (provider: Client, network: NetworkNum
232
241
  numOfBands: data.N.toString(),
233
242
  usedAssets,
234
243
  status,
244
+ borrowRate: marketBorrowRate,
235
245
  ...getCrvUsdAggregatedData({
236
- loanExists: data.loanExists, usedAssets, network: NetworkNumber.Eth, selectedMarket, numOfBands: data.N.toString(),
246
+ loanExists: data.loanExists,
247
+ usedAssets,
248
+ network: NetworkNumber.Eth,
249
+ selectedMarket,
250
+ numOfBands: data.N.toString(),
251
+ borrowRate: marketBorrowRate,
252
+ collStakingApy,
237
253
  }),
238
254
  userBands,
239
255
  };
@@ -245,10 +261,11 @@ export const getCurveUsdUserData = async (
245
261
  address: EthAddress,
246
262
  selectedMarket: CrvUSDMarketData,
247
263
  activeBand: string,
248
- ): Promise<CrvUSDUserData> => _getCurveUsdUserData(getViemProvider(provider, network), network, address, selectedMarket, activeBand);
264
+ borrowRate?: string,
265
+ ): Promise<CrvUSDUserData> => _getCurveUsdUserData(getViemProvider(provider, network), network, address, selectedMarket, activeBand, borrowRate);
249
266
 
250
267
  export const getCurveUsdFullPositionData = async (provider: EthereumProvider, network: NetworkNumber, address: EthAddress, selectedMarket: CrvUSDMarketData): Promise<CrvUSDUserData> => {
251
268
  const marketData = await getCurveUsdGlobalData(provider, network, selectedMarket);
252
- const positionData = await getCurveUsdUserData(provider, network, address, selectedMarket, marketData.activeBand);
269
+ const positionData = await getCurveUsdUserData(provider, network, address, selectedMarket, marketData.activeBand, marketData.borrowRate);
253
270
  return positionData;
254
271
  };
@@ -10,6 +10,7 @@ import {
10
10
  FluidAggregatedVaultData,
11
11
  FluidAssetData,
12
12
  FluidAssetsData,
13
+ FluidEarnPositionData,
13
14
  FluidFTokenDataStructOutput,
14
15
  FluidMarketData,
15
16
  FluidMarketInfo,
@@ -1597,7 +1598,7 @@ export const getFluidTokenData = async (
1597
1598
  token: string,
1598
1599
  ) => _getFluidTokenData(getViemProvider(provider, network), network, token);
1599
1600
 
1600
- const parseFDepositTokenData = (fTokenData: FluidFTokenDataStructOutput, userPosition: FluidUserEarnPositionStructOutput, apiData: any, fTokenAddress?: string) => {
1601
+ const parseFDepositTokenData = (fTokenData: FluidFTokenDataStructOutput, userPosition: FluidUserEarnPositionStructOutput, apiData: any, fTokenAddress?: string): FluidEarnPositionData => {
1601
1602
  const decimals = fTokenData.decimals.toString();
1602
1603
  const depositRate = new Dec(getEthAmountForDecimals(fTokenData.convertToShares.toString(), decimals)).toString();
1603
1604
  const withdrawRate = new Dec(getEthAmountForDecimals(fTokenData.convertToAssets.toString(), decimals)).toString();
@@ -1645,7 +1646,7 @@ export const getFluidDepositData = async (
1645
1646
  address: EthAddress,
1646
1647
  ) => _getFluidDepositData(getViemProvider(provider, network), network, token, address);
1647
1648
 
1648
- export const _getAllUserEarnPositionsWithFTokens = async (provider: Client, network: NetworkNumber, user: EthAddress) => {
1649
+ export const _getAllUserEarnPositionsWithFTokens = async (provider: Client, network: NetworkNumber, user: EthAddress): Promise<FluidEarnPositionData[]> => {
1649
1650
  const view = FluidViewContractViem(provider, network);
1650
1651
  const [
1651
1652
  [userPositions, fTokensData],
@@ -1664,7 +1665,7 @@ export const _getAllUserEarnPositionsWithFTokens = async (provider: Client, netw
1664
1665
  rewardsData = await rewardsApiResponse.json();
1665
1666
  }
1666
1667
 
1667
- const parsedRes = fTokensData.reduce<ReturnType<typeof parseFDepositTokenData>[]>((acc, fTokenData, i) => {
1668
+ const parsedRes = fTokensData.reduce<FluidEarnPositionData[]>((acc, fTokenData, i) => {
1668
1669
  const userPosition = userPositions[i];
1669
1670
  const deposited = userPosition?.underlyingAssets;
1670
1671
 
@@ -1830,3 +1831,43 @@ export const _getUserPositionsPortfolio = async (provider: PublicClient, network
1830
1831
  userData: userData[i],
1831
1832
  })).filter(md => md.marketData !== undefined);
1832
1833
  };
1834
+
1835
+
1836
+ export const _getAllFluidMarketDataPortfolio = async (provider: PublicClient, network: NetworkNumber): Promise<Record<string, FluidMarketData>> => {
1837
+ const versions = getFluidVersionsDataForNetwork(network);
1838
+ if (versions.length === 0) return {};
1839
+
1840
+ const view = FluidViewContractViem(provider, network);
1841
+ const vaultsData = await Promise.all(versions.map((version) => view.read.getVaultData([version.marketAddress])));
1842
+
1843
+ const tokens = Array.from(new Set(vaultsData.map((vaultData) => {
1844
+ const vaultTokens = [getAssetInfoByAddress(vaultData.supplyToken0, network).symbol, getAssetInfoByAddress(vaultData.borrowToken0, network).symbol];
1845
+ if (vaultData.supplyToken1 && !compareAddresses(ZERO_ADDRESS, vaultData.supplyToken1)) vaultTokens.push(getAssetInfoByAddress(vaultData.supplyToken1, network).symbol);
1846
+ if (vaultData.borrowToken1 && !compareAddresses(ZERO_ADDRESS, vaultData.borrowToken1)) vaultTokens.push(getAssetInfoByAddress(vaultData.borrowToken1, network).symbol);
1847
+ return vaultTokens;
1848
+ }).flat()));
1849
+
1850
+ // ETH and WBTC needed for other tokens prices
1851
+ if (!tokens.includes('ETH')) tokens.push('ETH');
1852
+ if (!tokens.includes('WBTC')) tokens.push('WBTC');
1853
+
1854
+ const [tokenPrices, merklCampaigns] = await Promise.all([
1855
+ getTokensPricesForPortfolio(tokens, provider, network),
1856
+ getFluidMerklCampaigns(network),
1857
+ ]);
1858
+
1859
+ const parsedMarketsData = await Promise.all(vaultsData.map(async (vaultData) => parseMarketData(provider, vaultData, network, tokenPrices)));
1860
+
1861
+ const marketsData: Record<string, FluidMarketData> = {};
1862
+ parsedMarketsData.forEach((marketData, i) => {
1863
+ if (!marketData) return;
1864
+ marketsData[versions[i].value] = attachFluidMerklIncentives(marketData, merklCampaigns);
1865
+ });
1866
+
1867
+ return marketsData;
1868
+ };
1869
+
1870
+ export const getAllFluidMarketDataPortfolio = async (
1871
+ provider: EthereumProvider,
1872
+ network: NetworkNumber,
1873
+ ): Promise<Record<string, FluidMarketData>> => _getAllFluidMarketDataPortfolio(getViemProvider(provider, network, { batch: { multicall: true } }), network);
@@ -2,7 +2,7 @@ import Dec from 'decimal.js';
2
2
  import { assetAmountInWei, getAssetInfo, getAssetInfoByAddress } from '@defisaver/tokens';
3
3
  import { Client } from 'viem';
4
4
  import {
5
- AaveAssetData, AaveHelperCommon, AaveMarketInfo, AaveV3AggregatedPositionData, AaveV3AssetsData, AaveV3UsedAsset, AaveV3UsedAssets, AaveVersions,
5
+ AaveAssetData, AaveHelperCommon, AaveMarketInfo, AaveV3AggregatedPositionData, AaveV3AssetsData, AaveV3UsedAsset, AaveV3UsedAssets, AaveVersions, EModeCategoriesData,
6
6
  } from '../../types';
7
7
  import { getNativeAssetFromWrapped, getWrappedNativeAssetFromUnwrapped } from '../../services/utils';
8
8
  import {
@@ -24,6 +24,13 @@ export const isAaveV3 = ({ selectedMarket }: { selectedMarket: Partial<AaveMarke
24
24
  export const aaveV3IsInIsolationMode = ({ usedAssets, assetsData }: { usedAssets: AaveV3UsedAssets, assetsData: AaveV3AssetsData }) => Object.values(usedAssets).some(({ symbol, collateral }) => collateral && assetsData[symbol].isIsolated);
25
25
  export const aaveV3IsInSiloedMode = ({ usedAssets, assetsData }: { usedAssets: AaveV3UsedAssets, assetsData: AaveV3AssetsData }) => Object.values(usedAssets).some(({ symbol, debt }) => debt && assetsData[symbol].isSiloed);
26
26
 
27
+ export const aaveV3IsEmodeIsolated = ({ eModeCategory, eModeCategoriesData }: { eModeCategory: number, eModeCategoriesData?: EModeCategoriesData }) => eModeCategory !== 0 && !!eModeCategoriesData?.[eModeCategory]?.isolated;
28
+
29
+ export const aaveV3CanBeCollateralInEmode = ({ eModeCategory, eModeCategoriesData }: { eModeCategory: number, eModeCategoriesData?: EModeCategoriesData }, _asset: string) => {
30
+ if (!aaveV3IsEmodeIsolated({ eModeCategory, eModeCategoriesData })) return true;
31
+ return eModeCategoriesData![eModeCategory].collateralAssets.includes(getNativeAssetFromWrapped(_asset));
32
+ };
33
+
27
34
  export const aaveAnyGetCollSuppliedAssets = ({ usedAssets }: { usedAssets: AaveV3UsedAssets }) => Object.values(usedAssets)
28
35
  .filter(({ isSupplied, collateral }: { isSupplied: boolean, collateral: boolean }) => isSupplied && collateral);
29
36
 
@@ -37,14 +44,18 @@ export const aaveAnyGetSuppliableAssets = ({
37
44
  const collAccountAssets = aaveAnyGetCollSuppliedAssets(data);
38
45
  const marketAssets = Object.values(assetsData) as AaveAssetData[];
39
46
 
40
- if (collAccountAssets.length === 0 || !isAaveV3(data)) return marketAssets.filter(({ canBeSupplied }) => canBeSupplied).map(({ symbol }) => ({ symbol, canBeCollateral: true }));
47
+ if (!isAaveV3(data)) return marketAssets.filter(({ canBeSupplied }) => canBeSupplied).map(({ symbol }) => ({ symbol, canBeCollateral: true }));
48
+
49
+ const canBeCollateralInEmode = (symbol: string) => aaveV3CanBeCollateralInEmode(data, symbol);
50
+
51
+ if (collAccountAssets.length === 0) return marketAssets.filter(({ canBeSupplied }) => canBeSupplied).map(({ symbol }) => ({ symbol, canBeCollateral: canBeCollateralInEmode(symbol) }));
41
52
 
42
53
  if (aaveV3IsInIsolationMode(data)) {
43
54
  const collAsset = collAccountAssets[0].symbol;
44
- return marketAssets.filter(d => d.canBeSupplied).map(({ symbol }) => ({ symbol, canBeCollateral: symbol === collAsset }));
55
+ return marketAssets.filter(d => d.canBeSupplied).map(({ symbol }) => ({ symbol, canBeCollateral: symbol === collAsset && canBeCollateralInEmode(symbol) }));
45
56
  }
46
57
 
47
- return marketAssets.filter(d => d.canBeSupplied).map(({ symbol, isIsolated }) => ({ symbol, canBeCollateral: !isIsolated }));
58
+ return marketAssets.filter(d => d.canBeSupplied).map(({ symbol, isIsolated }) => ({ symbol, canBeCollateral: !isIsolated && canBeCollateralInEmode(symbol) }));
48
59
  };
49
60
 
50
61
  export const aaveAnyGetSuppliableAsCollAssets = ({
@@ -62,8 +73,8 @@ export const aaveAnyGetEmodeMutableProps = (
62
73
  const asset = getNativeAssetFromWrapped(_asset);
63
74
 
64
75
  const assetData = assetsData[asset];
65
- const eModeCategoryData: { collateralAssets: string[], collateralFactor: string, liquidationRatio: string, ltvZeroAssets: string[] } = eModeCategoriesData?.[eModeCategory] || {
66
- collateralAssets: [], ltvZeroAssets: [], collateralFactor: '0', liquidationRatio: '0',
76
+ const eModeCategoryData: { collateralAssets: string[], collateralFactor: string, liquidationRatio: string, ltvZeroAssets: string[], isolated?: boolean } = eModeCategoriesData?.[eModeCategory] || {
77
+ collateralAssets: [], ltvZeroAssets: [], collateralFactor: '0', liquidationRatio: '0', isolated: false,
67
78
  };
68
79
 
69
80
  if (
@@ -72,6 +83,9 @@ export const aaveAnyGetEmodeMutableProps = (
72
83
  || new Dec(eModeCategoryData.collateralFactor || 0).eq(0)
73
84
  ) {
74
85
  const { liquidationRatio, collateralFactor } = assetData;
86
+ if (eModeCategory !== 0 && eModeCategoryData.isolated && !eModeCategoryData.collateralAssets.includes(asset)) {
87
+ return ({ liquidationRatio, collateralFactor: '0' });
88
+ }
75
89
  return ({ liquidationRatio, collateralFactor });
76
90
  }
77
91
  if (eModeCategoryData.ltvZeroAssets.includes(asset)) return ({ liquidationRatio: '0', collateralFactor: '0' });
@@ -118,7 +132,10 @@ export const aaveAnyGetUserReserveLtvAndLltv = (
118
132
  || !eModeCategoryData.collateralAssets.includes(asset)
119
133
  || new Dec(eModeCategoryData.collateralFactor || 0).eq(0)
120
134
  ) {
121
- return { ltv: assetData.collateralFactor, lltv: assetData.liquidationRatio };
135
+ const ltv = eModeCategory !== 0 && eModeCategoryData?.isolated && !eModeCategoryData.collateralAssets.includes(asset)
136
+ ? '0'
137
+ : assetData.collateralFactor;
138
+ return { ltv, lltv: assetData.liquidationRatio };
122
139
  }
123
140
 
124
141
  const ltv = eModeCategoryData.ltvZeroAssets.includes(asset) ? '0' : eModeCategoryData.collateralFactor;
@@ -169,6 +186,9 @@ export const aaveAnyGetAggregatedPositionData = ({
169
186
  },
170
187
  );
171
188
  payload.safetyRatioWithLtvZeroFallback = +payload.suppliedUsd ? new Dec(payload.borrowLimitWithLtvZeroFallbackUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
189
+ // Normalised safety ratio (100 = liquidation on every protocol): the automation ratio above, falling back
190
+ // to the regular ratio when the fallback carries its '0' placeholder.
191
+ payload.safetyRatio = +payload.safetyRatioWithLtvZeroFallback ? payload.safetyRatioWithLtvZeroFallback : payload.ratio;
172
192
  payload.liqRatio = new Dec(payload.borrowLimitUsd).div(payload.liquidationLimitUsd).toString();
173
193
  payload.liqPercent = new Dec(payload.borrowLimitUsd).div(payload.liquidationLimitUsd).mul(100).toString();
174
194
  const { leveragedType, leveragedAsset } = isLeveragedPos(usedAssets);
@@ -270,6 +270,7 @@ export const aaveV4GetAggregatedPositionData = ({
270
270
  payload.ratio = +payload.suppliedUsd ? new Dec(payload.borrowLimitUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
271
271
  payload.minRatio = '100';
272
272
  payload.collRatio = +payload.suppliedUsd ? new Dec(payload.suppliedCollateralUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
273
+ payload.safetyRatio = payload.ratio;
273
274
  payload.liqRatio = new Dec(payload.borrowLimitUsd).div(payload.liquidationLimitUsd).toString();
274
275
  payload.liqPercent = new Dec(payload.borrowLimitUsd).div(payload.liquidationLimitUsd).mul(100).toString();
275
276
  const { leveragedType, leveragedAsset } = isLeveragedPosAaveV4(usedAssets);
@@ -139,6 +139,7 @@ export const getCompoundV2AggregatedData = ({
139
139
  payload.collRatio = payload.borrowedUsd && payload.borrowedUsd !== '0'
140
140
  ? new Dec(payload.suppliedCollateralUsd).div(payload.borrowedUsd).mul(100).toString()
141
141
  : '0';
142
+ payload.safetyRatio = payload.ratio;
142
143
 
143
144
  // Calculate borrow limits per asset
144
145
  Object.values(usedAssets).forEach((item) => {
@@ -185,6 +186,7 @@ export const getCompoundV3AggregatedData = ({
185
186
  payload.incentiveUsd = incentiveUsd;
186
187
  payload.totalInterestUsd = totalInterestUsd;
187
188
  payload.minRatio = '100';
189
+ payload.safetyRatio = payload.ratio;
188
190
  payload.liqRatio = new Dec(payload.borrowLimitUsd).div(payload.liquidationLimitUsd).toString();
189
191
  payload.liqPercent = new Dec(payload.borrowLimitUsd).div(payload.liquidationLimitUsd).mul(100).toString();
190
192
  payload.minDebt = assetsData[selectedMarket.baseAsset].minDebt;
@@ -2,14 +2,21 @@ import Dec from 'decimal.js';
2
2
  import { CrvUSDAggregatedPositionData, CrvUSDMarketData, CrvUSDUsedAssets } from '../../types';
3
3
  import { MMUsedAssets, NetworkNumber } from '../../types/common';
4
4
  import {
5
- calcLeverageLiqPrice, getAssetsTotal, getExposure, isLeveragedPos,
5
+ calcLeverageLiqPrice, getAssetsTotal, getExposure, getSafetyRatioFromCollateralRatio, isLeveragedPos,
6
6
  } from '../../moneymarket';
7
7
  import { mapRange } from '../../services/utils';
8
+ import { calculateNetApyFromRates } from '../../staking';
8
9
 
9
10
  export const getCrvUsdAggregatedData = ({
10
- loanExists, usedAssets, network, selectedMarket, numOfBands, ...rest
11
+ loanExists, usedAssets, network, selectedMarket, numOfBands, borrowRate = '0', collStakingApy = '0', ...rest
11
12
  }:{
12
- loanExists: boolean, usedAssets: CrvUSDUsedAssets, network: NetworkNumber, selectedMarket: CrvUSDMarketData, numOfBands: number | string
13
+ loanExists: boolean,
14
+ usedAssets: CrvUSDUsedAssets,
15
+ network: NetworkNumber,
16
+ selectedMarket: CrvUSDMarketData,
17
+ numOfBands: number | string,
18
+ borrowRate?: string, // market borrow APY in %, see `CrvUSDGlobalMarketData.borrowRate`
19
+ collStakingApy?: string, // native yield APY in % of the collateral asset, if it is a staked asset
13
20
  }): CrvUSDAggregatedPositionData => {
14
21
  const payload = {} as CrvUSDAggregatedPositionData;
15
22
  payload.supplied = getAssetsTotal(usedAssets, ({ isSupplied }: { isSupplied: boolean }) => isSupplied, ({ supplied }: { supplied: string }) => supplied); // this is wrong if we are in soft-liquidations
@@ -26,6 +33,7 @@ export const getCrvUsdAggregatedData = ({
26
33
 
27
34
  // this is all approximation
28
35
  payload.minAllowedRatio = mapRange(numOfBands, 4, 50, 115, 140); // collateral ratio
36
+ payload.safetyRatio = loanExists ? getSafetyRatioFromCollateralRatio(payload.ratio, payload.minAllowedRatio) : '0';
29
37
  payload.collFactor = new Dec(1).div(payload.minAllowedRatio).mul(100).toString(); // collateral factor = 1 / collateral ratio
30
38
  // only take in consideration collAsset
31
39
  payload.borrowLimitUsd = usedAssets?.[selectedMarket.collAsset]?.isSupplied
@@ -42,5 +50,17 @@ export const getCrvUsdAggregatedData = ({
42
50
 
43
51
  payload.exposure = getExposure(payload.borrowedUsd, payload.suppliedUsd);
44
52
 
53
+ // crvUSD debt accrues the market borrow rate. Collateral (including crvUSD held during soft liquidation) earns
54
+ // nothing from the protocol itself; only the native yield of staked collateral is counted, as an incentive.
55
+ const { netApy, totalInterestUsd, incentiveUsd } = calculateNetApyFromRates({
56
+ suppliedUsd: payload.suppliedUsd,
57
+ borrowedUsd: payload.borrowedUsd,
58
+ borrowRate,
59
+ incentives: [{ apy: collStakingApy, amountUsd: usedAssets?.[selectedMarket.collAsset]?.suppliedUsd || '0' }],
60
+ });
61
+ payload.netApy = netApy;
62
+ payload.totalInterestUsd = totalInterestUsd;
63
+ payload.incentiveUsd = incentiveUsd;
64
+
45
65
  return payload;
46
66
  };
@@ -143,6 +143,7 @@ borrowShares?: string,
143
143
  payload.ratio = +payload.suppliedUsd ? new Dec(payload.borrowLimitUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
144
144
  payload.collRatio = +payload.suppliedUsd ? new Dec(payload.suppliedUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
145
145
  payload.minRatio = marketData.minRatio;
146
+ payload.safetyRatio = payload.ratio;
146
147
  const { leveragedType, leveragedAsset } = isLeveragedPos(usedAssets);
147
148
 
148
149
  payload.leveragedType = leveragedType;
@@ -69,6 +69,7 @@ export const getLiquityV2AggregatedPositionData = ({
69
69
  payload.leftToBorrowUsd = leftToBorrowUsd.lte('0') ? '0' : leftToBorrowUsd.toString();
70
70
  payload.ratio = (+payload.suppliedUsd && +payload.borrowedUsd) ? new Dec(payload.borrowLimitUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
71
71
  payload.collRatio = (+payload.suppliedUsd && +payload.borrowedUsd) ? new Dec(payload.suppliedUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
72
+ payload.safetyRatio = payload.ratio;
72
73
  const { netApy, incentiveUsd, totalInterestUsd } = calculateNetApyLiquityV2(usedAssets, assetsData, interestRate);
73
74
  payload.netApy = netApy;
74
75
  payload.incentiveUsd = incentiveUsd;
@@ -4,7 +4,7 @@ import {
4
4
  } from '../../types';
5
5
  import { MMAssetsData, MMUsedAssets, NetworkNumber } from '../../types/common';
6
6
  import {
7
- calcLeverageLiqPrice, getAssetsTotal, getExposure, isLeveragedPos,
7
+ calcLeverageLiqPrice, getAssetsTotal, getExposure, getSafetyRatioFromCollateralRatio, isLeveragedPos,
8
8
  } from '../../moneymarket';
9
9
  import { mapRange } from '../../services/utils';
10
10
  import { calculateNetApy } from '../../staking';
@@ -38,6 +38,7 @@ export const getLlamaLendAggregatedData = ({
38
38
 
39
39
  // this is all approximation
40
40
  payload.minAllowedRatio = mapRange(numOfBands, 4, 50, 115, 140); // collateral ratio
41
+ payload.safetyRatio = loanExists ? getSafetyRatioFromCollateralRatio(payload.ratio, payload.minAllowedRatio) : '0';
41
42
  payload.collFactor = new Dec(1).div(payload.minAllowedRatio).mul(100).toString(); // collateral factor = 1 / collateral ratio
42
43
  // only take in consideration collAsset
43
44
  payload.borrowLimitUsd = usedAssets?.[collAsset]?.isSupplied
@@ -10,6 +10,7 @@ export const parseCollateralInfo = (
10
10
  _rate: string,
11
11
  _spot: string,
12
12
  _line: string,
13
+ _dust: string,
13
14
  _duty: string,
14
15
  _futureRate: string,
15
16
  _chop: string,
@@ -20,7 +21,7 @@ export const parseCollateralInfo = (
20
21
  const rate = new Dec(_rate).toString();
21
22
  const spot = new Dec(_spot).div(1e27).toString();
22
23
  const line = new Dec(_line).div(1e45).toString();
23
- const dust = new Dec(_rate).div(1e45).toString();
24
+ const dust = new Dec(_dust).div(1e45).toString(); // Vat.ilks.dust, rad (1e45) -> DAI
24
25
  const duty = new Dec(_duty).toString();
25
26
  const futureRate = new Dec(_futureRate).toString();
26
27
  const chop = new Dec(_chop).div(1e18).toString();
@@ -54,6 +54,8 @@ export const getMorphoBlueAggregatedPositionData = ({ usedAssets, assetsData, ma
54
54
  payload.ltv = new Dec(usedAssets[loanToken]?.borrowed || 0).div(oracle).div(usedAssets[collateralToken]?.supplied || 1).toString(); // default to 1 because can't div 0
55
55
  payload.ratio = new Dec(usedAssets[collateralToken]?.supplied || 0).mul(oracle).div(usedAssets[loanToken]?.borrowed || 1).mul(100)
56
56
  .toString();
57
+ // Borrow limit over debt, so 100 sits on the market's LLTV however low it is (`ratio` is the raw collateral ratio).
58
+ payload.safetyRatio = +payload.borrowedUsd > 0 ? new Dec(payload.borrowLimitUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
57
59
 
58
60
  const { leveragedType, leveragedAsset } = isLeveragedPos(usedAssets);
59
61
  payload.leveragedType = leveragedType;
@@ -102,6 +102,8 @@ export const getMorphoMidnightAggregatedPositionData = ({
102
102
  payload.ltv = new Dec(payload.suppliedCollateralUsd).eq(0) ? '0' : new Dec(payload.borrowedUsd).div(payload.suppliedCollateralUsd).toString();
103
103
  payload.ratio = new Dec(payload.borrowedUsd).eq(0) ? '0' : new Dec(payload.suppliedCollateralUsd).div(payload.borrowedUsd).mul(100).toString();
104
104
  payload.healthRatio = new Dec(payload.borrowedUsd).eq(0) ? 'Infinity' : new Dec(payload.liquidationLimitUsd).div(payload.borrowedUsd).toDP(4).toString();
105
+ // Borrow limit over debt, so 100 sits on the market's LLTV however low it is (`ratio` is the raw collateral ratio).
106
+ payload.safetyRatio = +payload.borrowedUsd > 0 ? new Dec(payload.borrowLimitUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
105
107
 
106
108
  const { leveragedType, leveragedAsset } = isLeveragedPos(usedAssets);
107
109
  payload.leveragedType = leveragedType;
@@ -96,6 +96,7 @@ export const sparkGetAggregatedPositionData = ({
96
96
  payload.leftToBorrowUsd = leftToBorrowUsd.lte('0') ? '0' : leftToBorrowUsd.toString();
97
97
  payload.ratio = +payload.suppliedUsd ? new Dec(payload.borrowLimitUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
98
98
  payload.collRatio = +payload.suppliedUsd ? new Dec(payload.suppliedCollateralUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
99
+ payload.safetyRatio = payload.ratio;
99
100
  const { netApy, incentiveUsd, totalInterestUsd } = calculateNetApy({ usedAssets, assetsData });
100
101
  payload.netApy = netApy;
101
102
  payload.incentiveUsd = incentiveUsd;