@defisaver/positions-sdk 2.1.14 → 2.1.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defisaver/positions-sdk",
3
- "version": "2.1.14",
3
+ "version": "2.1.16",
4
4
  "description": "",
5
5
  "main": "./cjs/index.js",
6
6
  "module": "./esm/index.js",
@@ -264,23 +264,69 @@ const getAllMarketsUnbackedDebts = async (markets: Record<LiquityV2Versions, Liq
264
264
  return Object.fromEntries(allMarketsUnbackedDebt) as Record<LiquityV2Versions, string>;
265
265
  };
266
266
 
267
- const calculateDebtInFrontLiquityV2 = (markets: Record<LiquityV2Versions, LiquityV2MarketData>, selectedMarket: LiquityV2Versions, allMarketsUnbackedDebts: Record<LiquityV2Versions, string>, interestRateDebtInFront: string): string => {
267
+ export const calculateDebtInFrontLiquityV2 = (markets: Record<LiquityV2Versions, LiquityV2MarketData>, selectedMarket: LiquityV2Versions, allMarketsUnbackedDebts: Record<LiquityV2Versions, string>, interestRateDebtInFront: string): string => {
268
+ // Sanity check to avoid division by 0. Very unlikely to ever happen.
269
+ const selectedMarketTotalBorrow = new Dec(markets[selectedMarket].assetsData[LiquityV2Markets(NetworkNumber.Eth)[selectedMarket].debtToken].totalBorrow);
270
+ if (selectedMarketTotalBorrow.eq(0)) return new Dec(0).toString();
271
+
268
272
  const selectedMarketUnbackedDebt = new Dec(allMarketsUnbackedDebts[selectedMarket]);
269
273
  const { isLegacy } = LiquityV2Markets(NetworkNumber.Eth)[selectedMarket];
270
- if (selectedMarketUnbackedDebt.eq(0)) return interestRateDebtInFront;
274
+ const totalUnbackedDebt = Object.values(allMarketsUnbackedDebts).reduce((acc, val) => acc.plus(new Dec(val)), new Dec(0));
275
+
276
+ // When totalUnbackedDebt is 0, redemptions will be proportional with the branch size and not to unbacked debt.
277
+ // When unbacked debt is 0 for branch, next redemption call won't touch that branch, so in order to estimate total debt in front we will:
278
+ // - First add up all the unbacked debt from other branches, as that will be the only debt that will be redeemed on the fist redemption call
279
+ // - Perform split the same way as we would do when totalUnbackedDebt == 0, this would represent the second call to the redemption function
280
+ if (selectedMarketUnbackedDebt.eq(0)) {
281
+ // Special case if the branch debt in front is 0, it means that all debt in front is unbacked debt from other branches.
282
+ if (new Dec(interestRateDebtInFront).eq(0)) return totalUnbackedDebt.toString();
283
+
284
+ // Then calculate how much of that estimated amount would go to each branch
285
+ // Second redemption call - calculate proportional redemption based on updated total debt
286
+ const amountBeingRedeemedOnEachMarketByTotalBorrow = Object.entries(markets).map(([version, market]) => {
287
+ const { isLegacy: isLegacyMarket } = LiquityV2Markets(NetworkNumber.Eth)[version as LiquityV2Versions];
288
+ if (version === selectedMarket && isLegacyMarket !== isLegacy) return new Dec(interestRateDebtInFront);
289
+ const { assetsData } = market;
290
+ const { debtToken } = LiquityV2Markets(NetworkNumber.Eth)[version as LiquityV2Versions];
291
+ // For other markets, subtract their unbacked debt as it will be cleared in first redemption call
292
+ const marketUnbackedDebt = new Dec(allMarketsUnbackedDebts[version as LiquityV2Versions]);
293
+ const totalBorrow = new Dec(assetsData[debtToken].totalBorrow).sub(marketUnbackedDebt);
294
+ const amountToRedeem = new Dec(interestRateDebtInFront).mul(totalBorrow).div(selectedMarketTotalBorrow);
295
+ return Dec.min(amountToRedeem, totalBorrow);
296
+ });
271
297
 
272
- const amountBeingReedemedOnEachMarket = Object.entries(markets).map(([version, market]) => {
298
+ const redemptionAmount = amountBeingRedeemedOnEachMarketByTotalBorrow.reduce((acc, val) => acc.plus(val), new Dec(0));
299
+ return totalUnbackedDebt.plus(redemptionAmount).toString();
300
+ }
301
+
302
+ const amountBeingRedeemedOnEachMarketByUnbackedDebt = Object.entries(markets).map(([version, market]) => {
273
303
  const { isLegacy: isLegacyMarket } = LiquityV2Markets(NetworkNumber.Eth)[version as LiquityV2Versions];
274
304
  if (version === selectedMarket && isLegacyMarket !== isLegacy) return new Dec(interestRateDebtInFront);
275
305
  const { assetsData } = market;
276
306
  const { debtToken } = LiquityV2Markets(NetworkNumber.Eth)[version as LiquityV2Versions];
277
307
  const unbackedDebt = new Dec(allMarketsUnbackedDebts[version as LiquityV2Versions]);
278
308
  const totalBorrow = new Dec(assetsData[debtToken].totalBorrow);
279
- const amountToReedem = new Dec(interestRateDebtInFront).mul(unbackedDebt).div(selectedMarketUnbackedDebt);
280
- return Dec.min(amountToReedem, totalBorrow);
309
+ const amountToRedeem = new Dec(interestRateDebtInFront).mul(unbackedDebt).div(selectedMarketUnbackedDebt);
310
+ return Dec.min(amountToRedeem, totalBorrow);
281
311
  });
282
312
 
283
- return amountBeingReedemedOnEachMarket.reduce((acc, val) => acc.plus(val), new Dec(0)).toString();
313
+ return amountBeingRedeemedOnEachMarketByUnbackedDebt.reduce((acc, val) => acc.plus(val), new Dec(0)).toString();
314
+ };
315
+
316
+ // @dev The amount redeemed on each branch depends on the unbacked debt of every branch (the difference between total borrow and stability pool deposits).
317
+ // When new debt is generated on the selected market, the unbacked debt will increase, resulting in a higher redemption amount on that branch.
318
+ // This function accepts the new debt that's about to be generated (e.g., trove creation) and estimates the debt in front based on the new state.
319
+ export const getDebtInFrontForInterestRateIncludingNewDebtLiquityV2 = async (newDebt: string, markets: Record<LiquityV2Versions, LiquityV2MarketData>, selectedMarket: LiquityV2Versions, provider: Client, network: NetworkNumber, interestRate: string) => {
320
+ const marketsWithNewDebt = structuredClone(markets);
321
+ const selectedMarketDebtToken = LiquityV2Markets(network)[selectedMarket].debtToken;
322
+ const currentTotalBorrow = new Dec(marketsWithNewDebt[selectedMarket].assetsData[selectedMarketDebtToken].totalBorrow);
323
+ marketsWithNewDebt[selectedMarket].assetsData[selectedMarketDebtToken].totalBorrow = currentTotalBorrow.add(newDebt).toString();
324
+
325
+ const { isLegacy } = LiquityV2Markets(NetworkNumber.Eth)[selectedMarket];
326
+ const allMarketsUnbackedDebts = await getAllMarketsUnbackedDebts(marketsWithNewDebt, isLegacy, provider, network);
327
+ const interestRateDebtInFront = new Dec(await getDebtInFrontForInterestRateSingleMarketLiquityV2(provider, network, isLegacy, LiquityV2Markets(network)[selectedMarket].marketAddress, interestRate));
328
+
329
+ return calculateDebtInFrontLiquityV2(marketsWithNewDebt, selectedMarket, allMarketsUnbackedDebts, interestRateDebtInFront.toString());
284
330
  };
285
331
 
286
332
  const getDebtInFrontLiquityV2 = async (markets: Record<LiquityV2Versions, LiquityV2MarketData>, selectedMarket: LiquityV2Versions, provider: Client, network: NetworkNumber, viewContract: any, troveId: string) => {