@defisaver/positions-sdk 2.1.162 → 2.1.164
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/aaveV2/index.js +2 -0
- package/cjs/curveUsd/index.d.ts +5 -2
- package/cjs/curveUsd/index.js +30 -15
- package/cjs/fluid/index.d.ts +5 -0
- package/cjs/fluid/index.js +36 -1
- package/cjs/helpers/aaveHelpers/index.js +3 -0
- package/cjs/helpers/aaveV4Helpers/index.js +1 -0
- package/cjs/helpers/compoundHelpers/index.js +2 -0
- package/cjs/helpers/curveUsdHelpers/index.d.ts +3 -1
- package/cjs/helpers/curveUsdHelpers/index.js +15 -2
- package/cjs/helpers/fluidHelpers/index.js +1 -0
- package/cjs/helpers/liquityV2Helpers/index.js +1 -0
- package/cjs/helpers/llamaLendHelpers/index.js +1 -0
- package/cjs/helpers/makerHelpers/index.d.ts +1 -1
- package/cjs/helpers/makerHelpers/index.js +2 -2
- package/cjs/helpers/morphoBlueHelpers/index.js +2 -0
- package/cjs/helpers/morphoMidnightHelpers/index.js +2 -0
- package/cjs/helpers/sparkHelpers/index.js +1 -0
- package/cjs/liquity/index.js +15 -2
- package/cjs/maker/index.d.ts +7 -2
- package/cjs/maker/index.js +44 -12
- package/cjs/markets/index.d.ts +1 -0
- package/cjs/markets/index.js +3 -1
- package/cjs/markets/maker/index.d.ts +1 -0
- package/cjs/markets/maker/index.js +13 -0
- package/cjs/moneymarket/moneymarketCommonService.d.ts +9 -0
- package/cjs/moneymarket/moneymarketCommonService.js +13 -1
- package/cjs/portfolio/index.d.ts +5 -1
- package/cjs/portfolio/index.js +282 -16
- package/cjs/staking/staking.d.ts +20 -0
- package/cjs/staking/staking.js +19 -1
- package/cjs/types/aave.d.ts +2 -0
- package/cjs/types/aaveV4.d.ts +1 -0
- package/cjs/types/compound.d.ts +2 -0
- package/cjs/types/curveUsd.d.ts +6 -0
- package/cjs/types/fluid.d.ts +1 -0
- package/cjs/types/liquity.d.ts +4 -0
- package/cjs/types/liquityV2.d.ts +2 -0
- package/cjs/types/maker.d.ts +4 -0
- package/cjs/types/morphoBlue.d.ts +2 -0
- package/cjs/types/morphoMidnight.d.ts +1 -0
- package/cjs/types/portfolio.d.ts +26 -10
- package/cjs/types/spark.d.ts +2 -0
- package/esm/aaveV2/index.js +2 -0
- package/esm/curveUsd/index.d.ts +5 -2
- package/esm/curveUsd/index.js +30 -15
- package/esm/fluid/index.d.ts +5 -0
- package/esm/fluid/index.js +33 -0
- package/esm/helpers/aaveHelpers/index.js +3 -0
- package/esm/helpers/aaveV4Helpers/index.js +1 -0
- package/esm/helpers/compoundHelpers/index.js +2 -0
- package/esm/helpers/curveUsdHelpers/index.d.ts +3 -1
- package/esm/helpers/curveUsdHelpers/index.js +16 -3
- package/esm/helpers/fluidHelpers/index.js +1 -0
- package/esm/helpers/liquityV2Helpers/index.js +1 -0
- package/esm/helpers/llamaLendHelpers/index.js +2 -1
- package/esm/helpers/makerHelpers/index.d.ts +1 -1
- package/esm/helpers/makerHelpers/index.js +2 -2
- package/esm/helpers/morphoBlueHelpers/index.js +2 -0
- package/esm/helpers/morphoMidnightHelpers/index.js +2 -0
- package/esm/helpers/sparkHelpers/index.js +1 -0
- package/esm/liquity/index.js +16 -3
- package/esm/maker/index.d.ts +7 -2
- package/esm/maker/index.js +44 -14
- package/esm/markets/index.d.ts +1 -0
- package/esm/markets/index.js +1 -0
- package/esm/markets/maker/index.d.ts +1 -0
- package/esm/markets/maker/index.js +10 -0
- package/esm/moneymarket/moneymarketCommonService.d.ts +9 -0
- package/esm/moneymarket/moneymarketCommonService.js +11 -0
- package/esm/portfolio/index.d.ts +5 -1
- package/esm/portfolio/index.js +284 -19
- package/esm/staking/staking.d.ts +20 -0
- package/esm/staking/staking.js +17 -0
- package/esm/types/aave.d.ts +2 -0
- package/esm/types/aaveV4.d.ts +1 -0
- package/esm/types/compound.d.ts +2 -0
- package/esm/types/curveUsd.d.ts +6 -0
- package/esm/types/fluid.d.ts +1 -0
- package/esm/types/liquity.d.ts +4 -0
- package/esm/types/liquityV2.d.ts +2 -0
- package/esm/types/maker.d.ts +4 -0
- package/esm/types/morphoBlue.d.ts +2 -0
- package/esm/types/morphoMidnight.d.ts +1 -0
- package/esm/types/portfolio.d.ts +26 -10
- package/esm/types/spark.d.ts +2 -0
- package/package.json +1 -1
- package/src/aaveV2/index.ts +2 -0
- package/src/curveUsd/index.ts +33 -16
- package/src/fluid/index.ts +40 -0
- package/src/helpers/aaveHelpers/index.ts +3 -0
- package/src/helpers/aaveV4Helpers/index.ts +1 -0
- package/src/helpers/compoundHelpers/index.ts +2 -0
- package/src/helpers/curveUsdHelpers/index.ts +23 -3
- package/src/helpers/fluidHelpers/index.ts +1 -0
- package/src/helpers/liquityV2Helpers/index.ts +1 -0
- package/src/helpers/llamaLendHelpers/index.ts +2 -1
- package/src/helpers/makerHelpers/index.ts +2 -1
- package/src/helpers/morphoBlueHelpers/index.ts +2 -0
- package/src/helpers/morphoMidnightHelpers/index.ts +2 -0
- package/src/helpers/sparkHelpers/index.ts +1 -0
- package/src/liquity/index.ts +17 -3
- package/src/maker/index.ts +77 -30
- package/src/markets/index.ts +2 -1
- package/src/markets/maker/index.ts +10 -0
- package/src/moneymarket/moneymarketCommonService.ts +15 -0
- package/src/portfolio/index.ts +262 -5
- package/src/staking/staking.ts +28 -0
- package/src/types/aave.ts +3 -0
- package/src/types/aaveV4.ts +1 -0
- package/src/types/compound.ts +2 -0
- package/src/types/curveUsd.ts +7 -0
- package/src/types/fluid.ts +1 -0
- package/src/types/liquity.ts +6 -0
- package/src/types/liquityV2.ts +2 -0
- package/src/types/maker.ts +6 -0
- package/src/types/morphoBlue.ts +2 -0
- package/src/types/morphoMidnight.ts +1 -0
- package/src/types/portfolio.ts +31 -12
- package/src/types/spark.ts +2 -0
package/src/curveUsd/index.ts
CHANGED
|
@@ -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
|
|
73
|
-
const
|
|
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
|
-
|
|
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:
|
|
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,
|
|
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
|
-
|
|
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
|
};
|
package/src/fluid/index.ts
CHANGED
|
@@ -1830,3 +1830,43 @@ export const _getUserPositionsPortfolio = async (provider: PublicClient, network
|
|
|
1830
1830
|
userData: userData[i],
|
|
1831
1831
|
})).filter(md => md.marketData !== undefined);
|
|
1832
1832
|
};
|
|
1833
|
+
|
|
1834
|
+
|
|
1835
|
+
export const _getAllFluidMarketDataPortfolio = async (provider: PublicClient, network: NetworkNumber): Promise<Record<string, FluidMarketData>> => {
|
|
1836
|
+
const versions = getFluidVersionsDataForNetwork(network);
|
|
1837
|
+
if (versions.length === 0) return {};
|
|
1838
|
+
|
|
1839
|
+
const view = FluidViewContractViem(provider, network);
|
|
1840
|
+
const vaultsData = await Promise.all(versions.map((version) => view.read.getVaultData([version.marketAddress])));
|
|
1841
|
+
|
|
1842
|
+
const tokens = Array.from(new Set(vaultsData.map((vaultData) => {
|
|
1843
|
+
const vaultTokens = [getAssetInfoByAddress(vaultData.supplyToken0, network).symbol, getAssetInfoByAddress(vaultData.borrowToken0, network).symbol];
|
|
1844
|
+
if (vaultData.supplyToken1 && !compareAddresses(ZERO_ADDRESS, vaultData.supplyToken1)) vaultTokens.push(getAssetInfoByAddress(vaultData.supplyToken1, network).symbol);
|
|
1845
|
+
if (vaultData.borrowToken1 && !compareAddresses(ZERO_ADDRESS, vaultData.borrowToken1)) vaultTokens.push(getAssetInfoByAddress(vaultData.borrowToken1, network).symbol);
|
|
1846
|
+
return vaultTokens;
|
|
1847
|
+
}).flat()));
|
|
1848
|
+
|
|
1849
|
+
// ETH and WBTC needed for other tokens prices
|
|
1850
|
+
if (!tokens.includes('ETH')) tokens.push('ETH');
|
|
1851
|
+
if (!tokens.includes('WBTC')) tokens.push('WBTC');
|
|
1852
|
+
|
|
1853
|
+
const [tokenPrices, merklCampaigns] = await Promise.all([
|
|
1854
|
+
getTokensPricesForPortfolio(tokens, provider, network),
|
|
1855
|
+
getFluidMerklCampaigns(network),
|
|
1856
|
+
]);
|
|
1857
|
+
|
|
1858
|
+
const parsedMarketsData = await Promise.all(vaultsData.map(async (vaultData) => parseMarketData(provider, vaultData, network, tokenPrices)));
|
|
1859
|
+
|
|
1860
|
+
const marketsData: Record<string, FluidMarketData> = {};
|
|
1861
|
+
parsedMarketsData.forEach((marketData, i) => {
|
|
1862
|
+
if (!marketData) return;
|
|
1863
|
+
marketsData[versions[i].value] = attachFluidMerklIncentives(marketData, merklCampaigns);
|
|
1864
|
+
});
|
|
1865
|
+
|
|
1866
|
+
return marketsData;
|
|
1867
|
+
};
|
|
1868
|
+
|
|
1869
|
+
export const getAllFluidMarketDataPortfolio = async (
|
|
1870
|
+
provider: EthereumProvider,
|
|
1871
|
+
network: NetworkNumber,
|
|
1872
|
+
): Promise<Record<string, FluidMarketData>> => _getAllFluidMarketDataPortfolio(getViemProvider(provider, network, { batch: { multicall: true } }), network);
|
|
@@ -186,6 +186,9 @@ export const aaveAnyGetAggregatedPositionData = ({
|
|
|
186
186
|
},
|
|
187
187
|
);
|
|
188
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;
|
|
189
192
|
payload.liqRatio = new Dec(payload.borrowLimitUsd).div(payload.liquidationLimitUsd).toString();
|
|
190
193
|
payload.liqPercent = new Dec(payload.borrowLimitUsd).div(payload.liquidationLimitUsd).mul(100).toString();
|
|
191
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,
|
|
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(
|
|
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;
|
package/src/liquity/index.ts
CHANGED
|
@@ -17,7 +17,8 @@ import { LIQUITY_TROVE_STATUS_ENUM, LiquityTroveInfo } from '../types';
|
|
|
17
17
|
import { ZERO_ADDRESS } from '../constants';
|
|
18
18
|
import { getViemProvider, setViemBlockNumber } from '../services/viem';
|
|
19
19
|
import { getEthAmountForDecimals } from '../services/utils';
|
|
20
|
-
import { getExposure } from '../moneymarket';
|
|
20
|
+
import { getExposure, getSafetyRatioFromCollateralRatio } from '../moneymarket';
|
|
21
|
+
import { calculateNetApyFromRates } from '../staking';
|
|
21
22
|
|
|
22
23
|
export const LIQUITY_NORMAL_MODE_RATIO = 110; // MCR
|
|
23
24
|
export const LIQUITY_RECOVERY_MODE_RATIO = 150; // CCR
|
|
@@ -89,6 +90,15 @@ export const _getLiquityTroveInfo = async (provider: Client, network: NetworkNum
|
|
|
89
90
|
]);
|
|
90
91
|
|
|
91
92
|
const recoveryMode = troveInfo[6];
|
|
93
|
+
const minCollateralRatio = recoveryMode ? LIQUITY_RECOVERY_MODE_RATIO : LIQUITY_NORMAL_MODE_RATIO;
|
|
94
|
+
const collateral = assetAmountInEth(troveInfo[1].toString());
|
|
95
|
+
const debtInAsset = assetAmountInEth(troveInfo[2].toString());
|
|
96
|
+
const collateralUsd = new Dec(collateral).mul(assetAmountInEth(assetPrice.toString())).toString();
|
|
97
|
+
const collRatio = +debtInAsset ? new Dec(collateralUsd).div(debtInAsset).mul(100).toString() : '0';
|
|
98
|
+
|
|
99
|
+
// LUSD debt is interest free (only a one-off borrowing fee on issuance) and ETH collateral earns no yield,
|
|
100
|
+
// so a trove's net APY is always 0. It is exposed for parity with the other protocols.
|
|
101
|
+
const { netApy, totalInterestUsd, incentiveUsd } = calculateNetApyFromRates({ suppliedUsd: collateralUsd, borrowedUsd: debtInAsset });
|
|
92
102
|
|
|
93
103
|
const payload = {
|
|
94
104
|
troveStatus: LIQUITY_TROVE_STATUS_ENUM[+(troveInfo[0].toString())],
|
|
@@ -102,10 +112,14 @@ export const _getLiquityTroveInfo = async (provider: Client, network: NetworkNum
|
|
|
102
112
|
totalETH: totalETH.toString(),
|
|
103
113
|
totalLUSD: totalLUSD.toString(),
|
|
104
114
|
debtInFront: debtInFront.toString(),
|
|
105
|
-
minCollateralRatio
|
|
115
|
+
minCollateralRatio,
|
|
116
|
+
safetyRatio: getSafetyRatioFromCollateralRatio(collRatio, minCollateralRatio),
|
|
106
117
|
priceForRecovery: new Dec(recoveryMode ? LIQUITY_RECOVERY_MODE_RATIO : LIQUITY_NORMAL_MODE_RATIO).mul(totalLUSD).div(totalETH).div(100)
|
|
107
118
|
.toString(),
|
|
108
|
-
exposure: getExposure(
|
|
119
|
+
exposure: getExposure(debtInAsset, collateralUsd),
|
|
120
|
+
netApy,
|
|
121
|
+
totalInterestUsd,
|
|
122
|
+
incentiveUsd,
|
|
109
123
|
};
|
|
110
124
|
|
|
111
125
|
return payload;
|
package/src/maker/index.ts
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import Dec from 'decimal.js';
|
|
2
2
|
import {
|
|
3
|
-
assetAmountInEth, bytesToString, getAssetInfo, ilkToAsset,
|
|
3
|
+
assetAmountInEth, bytesToString, getAssetInfo, ilkToAsset, stringToBytes,
|
|
4
4
|
} from '@defisaver/tokens';
|
|
5
5
|
import { Client, PublicClient } from 'viem';
|
|
6
6
|
import {
|
|
7
|
-
Blockish, EthAddress, EthereumProvider, NetworkNumber, PositionBalances,
|
|
7
|
+
Blockish, EthAddress, EthereumProvider, HexString, NetworkNumber, PositionBalances,
|
|
8
8
|
} from '../types/common';
|
|
9
9
|
import {
|
|
10
10
|
getConfigContractAddress, McdDogContractViem, McdGetCdpsContractViem, McdJugContractViem, McdSpotterContractViem, McdVatContractViem, McdViewContractViem,
|
|
11
11
|
} from '../contracts';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
CdpData, CdpInfo, CdpType, IlkInfo,
|
|
14
|
+
} from '../types';
|
|
13
15
|
import { wethToEth } from '../services/utils';
|
|
14
16
|
import { parseCollateralInfo } from '../helpers/makerHelpers';
|
|
15
17
|
import { getViemProvider, setViemBlockNumber } from '../services/viem';
|
|
16
|
-
import { getExposure } from '../moneymarket';
|
|
18
|
+
import { getExposure, getSafetyRatioFromCollateralRatio } from '../moneymarket';
|
|
19
|
+
import { calculateNetApyFromRates, getStakingApy, STAKING_ASSETS } from '../staking';
|
|
17
20
|
|
|
18
21
|
export const _getMakerAccountBalances = async (provider: PublicClient, network: NetworkNumber, block: Blockish, addressMapping: boolean, cdpId: string, _managerAddress?: EthAddress): Promise<PositionBalances> => {
|
|
19
22
|
let balances: PositionBalances = {
|
|
@@ -48,7 +51,7 @@ export const _getMakerAccountBalances = async (provider: PublicClient, network:
|
|
|
48
51
|
const [
|
|
49
52
|
par,
|
|
50
53
|
[_, mat],
|
|
51
|
-
[artGlobal, rate, spot, line],
|
|
54
|
+
[artGlobal, rate, spot, line, dust],
|
|
52
55
|
[duty],
|
|
53
56
|
futureRate,
|
|
54
57
|
chop,
|
|
@@ -69,6 +72,7 @@ export const _getMakerAccountBalances = async (provider: PublicClient, network:
|
|
|
69
72
|
rate.toString(),
|
|
70
73
|
spot.toString(),
|
|
71
74
|
line.toString(),
|
|
75
|
+
dust.toString(),
|
|
72
76
|
duty.toString(),
|
|
73
77
|
futureRate.toString(),
|
|
74
78
|
chop.toString(),
|
|
@@ -129,44 +133,73 @@ export const getUserCdps = async (
|
|
|
129
133
|
userAddress: EthAddress,
|
|
130
134
|
): Promise<CdpInfo[]> => _getUserCdps(getViemProvider(provider, network), network, userAddress);
|
|
131
135
|
|
|
132
|
-
export const
|
|
136
|
+
export const _getMakerIlksData = async (provider: Client, network: NetworkNumber, ilkLabels: string[]): Promise<Record<string, IlkInfo>> => {
|
|
133
137
|
const vatContract = McdVatContractViem(provider, network);
|
|
134
138
|
const spotterContract = McdSpotterContractViem(provider, network);
|
|
135
139
|
const dogContract = McdDogContractViem(provider, network);
|
|
136
140
|
const jugContract = McdJugContractViem(provider, network);
|
|
137
141
|
|
|
142
|
+
const par = await spotterContract.read.par();
|
|
143
|
+
|
|
144
|
+
const ilksInfo = await Promise.all(ilkLabels.map(async (ilkLabel) => {
|
|
145
|
+
const ilk = stringToBytes(ilkLabel) as HexString;
|
|
146
|
+
const [
|
|
147
|
+
[_, mat],
|
|
148
|
+
[artGlobal, rate, spot, line, dust],
|
|
149
|
+
[duty],
|
|
150
|
+
futureRate,
|
|
151
|
+
chop,
|
|
152
|
+
] = await Promise.all([
|
|
153
|
+
spotterContract.read.ilks([ilk]),
|
|
154
|
+
vatContract.read.ilks([ilk]),
|
|
155
|
+
jugContract.read.ilks([ilk]),
|
|
156
|
+
jugContract.read.drip([ilk]),
|
|
157
|
+
dogContract.read.chop([ilk]),
|
|
158
|
+
]);
|
|
159
|
+
|
|
160
|
+
return parseCollateralInfo(
|
|
161
|
+
ilk,
|
|
162
|
+
par.toString(),
|
|
163
|
+
mat.toString(),
|
|
164
|
+
artGlobal.toString(),
|
|
165
|
+
rate.toString(),
|
|
166
|
+
spot.toString(),
|
|
167
|
+
line.toString(),
|
|
168
|
+
dust.toString(),
|
|
169
|
+
duty.toString(),
|
|
170
|
+
futureRate.toString(),
|
|
171
|
+
chop.toString(),
|
|
172
|
+
);
|
|
173
|
+
}));
|
|
174
|
+
|
|
175
|
+
return Object.fromEntries(ilksInfo.map((ilkInfo) => [ilkInfo.ilkLabel, ilkInfo]));
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
export const getMakerIlksData = async (
|
|
179
|
+
provider: EthereumProvider,
|
|
180
|
+
network: NetworkNumber,
|
|
181
|
+
ilkLabels: string[],
|
|
182
|
+
): Promise<Record<string, IlkInfo>> => _getMakerIlksData(getViemProvider(provider, network, { batch: { multicall: true } }), network, ilkLabels);
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @param ilkInfo optional precomputed ilk data (from `_getMakerIlksData`); when provided the per-ilk reads are skipped
|
|
186
|
+
*/
|
|
187
|
+
export const _getMakerCdpData = async (provider: Client, network: NetworkNumber, cdp: CdpInfo, ilkInfo?: IlkInfo): Promise<CdpData> => {
|
|
188
|
+
const vatContract = McdVatContractViem(provider, network);
|
|
189
|
+
|
|
138
190
|
const [
|
|
139
191
|
[ink, art],
|
|
140
192
|
coll,
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
[artGlobal, rate, spot, line],
|
|
144
|
-
[duty],
|
|
145
|
-
futureRate,
|
|
146
|
-
chop,
|
|
193
|
+
fetchedIlkInfo,
|
|
194
|
+
collStakingApy,
|
|
147
195
|
] = await Promise.all([
|
|
148
196
|
vatContract.read.urns([cdp.ilk, cdp.urn]),
|
|
149
197
|
vatContract.read.gem([cdp.ilk, cdp.urn]),
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
vatContract.read.ilks([cdp.ilk]),
|
|
153
|
-
jugContract.read.ilks([cdp.ilk]),
|
|
154
|
-
jugContract.read.drip([cdp.ilk]),
|
|
155
|
-
dogContract.read.chop([cdp.ilk]),
|
|
198
|
+
ilkInfo || _getMakerIlksData(provider, network, [cdp.ilkLabel]).then((ilks) => ilks[cdp.ilkLabel]),
|
|
199
|
+
STAKING_ASSETS.includes(cdp.asset) ? getStakingApy(cdp.asset) : Promise.resolve('0'),
|
|
156
200
|
]);
|
|
157
201
|
|
|
158
|
-
const collInfo =
|
|
159
|
-
cdp.ilk,
|
|
160
|
-
par.toString(),
|
|
161
|
-
mat.toString(),
|
|
162
|
-
artGlobal.toString(),
|
|
163
|
-
rate.toString(),
|
|
164
|
-
spot.toString(),
|
|
165
|
-
line.toString(),
|
|
166
|
-
duty.toString(),
|
|
167
|
-
futureRate.toString(),
|
|
168
|
-
chop.toString(),
|
|
169
|
-
);
|
|
202
|
+
const collInfo = fetchedIlkInfo;
|
|
170
203
|
|
|
171
204
|
const collateral = assetAmountInEth(ink.toString(), `MCD-${cdp.asset}`);
|
|
172
205
|
|
|
@@ -180,9 +213,19 @@ export const _getMakerCdpData = async (provider: Client, network: NetworkNumber,
|
|
|
180
213
|
let ratio = new Dec(ink).times(collInfo.assetPrice).div(debt).times(100)
|
|
181
214
|
.toString();
|
|
182
215
|
if (new Dec(debt).eq(0)) ratio = '0';
|
|
216
|
+
const safetyRatio = getSafetyRatioFromCollateralRatio(ratio, collInfo.liqPercent);
|
|
183
217
|
|
|
184
218
|
const debtTooLow = new Dec(debt).gt(0) && new Dec(assetAmountInEth(debt, 'DAI')).lt(collInfo.minDebt);
|
|
185
219
|
|
|
220
|
+
// DAI debt accrues the ilk's stability fee. Collateral earns nothing inside the vault, except for the
|
|
221
|
+
// native yield of staked collateral (e.g. wstETH), which is tracked as an incentive.
|
|
222
|
+
const { netApy, totalInterestUsd, incentiveUsd } = calculateNetApyFromRates({
|
|
223
|
+
suppliedUsd: collateralUsd,
|
|
224
|
+
borrowedUsd: assetAmountInEth(debt, 'DAI'),
|
|
225
|
+
borrowRate: collInfo.stabilityFee.toString(),
|
|
226
|
+
incentives: [{ apy: collStakingApy, amountUsd: collateralUsd }],
|
|
227
|
+
});
|
|
228
|
+
|
|
186
229
|
return {
|
|
187
230
|
owner: cdp.owner,
|
|
188
231
|
id: cdp.id.toString(),
|
|
@@ -201,6 +244,7 @@ export const _getMakerCdpData = async (provider: Client, network: NetworkNumber,
|
|
|
201
244
|
debtAssetMarketPrice: '1',
|
|
202
245
|
liquidationPrice,
|
|
203
246
|
ratio,
|
|
247
|
+
safetyRatio,
|
|
204
248
|
liqRatio: collInfo.liqRatio.toString(),
|
|
205
249
|
liqPercent: parseFloat(collInfo.liqPercent.toString()),
|
|
206
250
|
assetPrice: collInfo.assetPrice,
|
|
@@ -216,6 +260,9 @@ export const _getMakerCdpData = async (provider: Client, network: NetworkNumber,
|
|
|
216
260
|
liquidationFee: collInfo.liquidationFee,
|
|
217
261
|
lastUpdated: Date.now(),
|
|
218
262
|
exposure: getExposure(assetAmountInEth(debt, 'DAI'), collateralUsd),
|
|
263
|
+
netApy,
|
|
264
|
+
totalInterestUsd,
|
|
265
|
+
incentiveUsd,
|
|
219
266
|
};
|
|
220
267
|
};
|
|
221
268
|
|
package/src/markets/index.ts
CHANGED
|
@@ -30,4 +30,5 @@ export {
|
|
|
30
30
|
getFTokenAddress,
|
|
31
31
|
getFluidMarketInfoByAddress,
|
|
32
32
|
} from './fluid';
|
|
33
|
-
export { AaveV4Spokes, findAaveV4SpokeByAddress } from './aaveV4';
|
|
33
|
+
export { AaveV4Spokes, findAaveV4SpokeByAddress } from './aaveV4';
|
|
34
|
+
export { MakerActiveIlks } from './maker';
|
|
@@ -92,3 +92,18 @@ export const getExposure = (borrowedUsd: string, suppliedUsd: string) => {
|
|
|
92
92
|
const balanceUsd = new Dec(suppliedUsd).sub(borrowedUsd).toString();
|
|
93
93
|
return new Dec(suppliedUsd).div(balanceUsd).toDecimalPlaces(2).toString();
|
|
94
94
|
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* A collateral ratio rebased so that 100 means "sitting exactly on the liquidation ratio": the scale the
|
|
98
|
+
* shared `safetyRatio` field assumes. Protocols that liquidate on a raw collateral ratio (Maker at the ilk's
|
|
99
|
+
* liquidation ratio, Liquity at 110%, crvUSD/LlamaLend at the band-derived minimum) pass through here.
|
|
100
|
+
*
|
|
101
|
+
* Yields '0' when the liquidation ratio isn't available (or is 0), the "no signal" value consumers already recognise.
|
|
102
|
+
* Mirrors `getSafetyRatioFromCollateralRatio` on the client.
|
|
103
|
+
*/
|
|
104
|
+
export const getSafetyRatioFromCollateralRatio = (
|
|
105
|
+
collateralRatio: string | number | undefined,
|
|
106
|
+
liquidationRatio: string | number | undefined,
|
|
107
|
+
): string => (+(liquidationRatio ?? 0) > 0
|
|
108
|
+
? new Dec(collateralRatio || 0).div(liquidationRatio!).mul(100).toString()
|
|
109
|
+
: '0');
|