UNPKG

@indigo-labs/indigo-sdk

Version:

Indigo SDK for interacting with Indigo endpoints via lucid-evolution

176 lines (162 loc) 4.84 kB
import { Network, slotToUnixTime, UTxO } from '@lucid-evolution/lucid'; import { calculateAccruedInterest } from '../interest-oracle/helpers'; import { match, P } from 'ts-pattern'; import { calculateFeeFromRatio } from '../../utils/indigo-helpers'; import { assetClassValueOf } from '@3rd-eye-labs/cardano-offchain-common'; import { InterestOracleDatum } from '../interest-oracle/types-new'; import { CDPContent } from './types-new'; import { Rational, rationalAdd, rationalCeil, rationalDiv, rationalFloor, rationalFromInt, rationalMul, rationalNegate, rationalSub, } from '../../types/rational'; /** * Amount of iasset equal in value to the given number of collateral amount. */ export function iassetValueOfCollateral( collateralAmt: bigint, oraclePrice: Rational, ): bigint { return rationalFloor( rationalDiv(rationalFromInt(collateralAmt), oraclePrice), ); } /** * This is mostly for debugging purposes. */ export function cdpCollateralRatioPercentage( currentSlot: number, iassetPrice: Rational, cdpUtxo: UTxO, cdpContent: CDPContent, interestOracleDatum: InterestOracleDatum, network: Network, ): number { const currentTime = BigInt(slotToUnixTime(network, currentSlot)); return match(cdpContent.cdpFees) .with({ ActiveCDPInterestTracking: P.select() }, (interest) => { const interestAmt = calculateAccruedInterest( currentTime, interest.unitaryInterestSnapshot, cdpContent.mintedAmt, interest.lastSettled, interestOracleDatum, ); const collateral = assetClassValueOf( cdpUtxo.assets, cdpContent.collateralAsset, ); const ratio = rationalDiv( rationalFromInt(collateral), rationalMul( rationalFromInt(cdpContent.mintedAmt + interestAmt), iassetPrice, ), ); return Number((ratio.numerator * 100n) / ratio.denominator); }) .with({ FrozenCDPAccumulatedFees: P.any }, () => 0) .exhaustive(); } /** * The amount of iassets to redeem to reach the RMR. */ export function calculateIAssetRedemptionAmt( collateralAmt: bigint, mintedAmt: bigint, price: Rational, rmr: Rational, ): bigint { return rationalCeil( rationalDiv( rationalAdd( rationalNegate(rationalDiv(rationalFromInt(collateralAmt), price)), rationalMul(rmr, rationalFromInt(mintedAmt)), ), rationalSub(rmr, rationalFromInt(1n)), ), ); } /** * Calculates the allowable redemption amount so the min collateral constraint still holds. * It caps the redemption amount to still satisfy the min collateral. * * Returns uncapped max iassets /\ capped max iassets * * The derived calculation comes from the following equation where: * c - collateral * m - min collateral * r - reimburstment ratio * x - redemption amount * * `c - x + r * x = m` * `-x + r * x = m - c` * `x * (r - 1) = m - c` * `x = (m - c) / r - 1` */ export function calculateMinCollateralCappedIAssetRedemptionAmt( collateralAmt: bigint, mintedAmt: bigint, price: Rational, rmr: Rational, reimbursementRatio: Rational, minCollateral: bigint, ): { uncappedIAssetRedemptionAmt: bigint; cappedIAssetRedemptionAmt: bigint; } { const uncappedMaxIAssetRedemptionAmt = calculateIAssetRedemptionAmt( collateralAmt, mintedAmt, price, rmr, ); const uncappedMaxRedemptionLovelacesAmt = rationalFloor( rationalMul(price, rationalFromInt(uncappedMaxIAssetRedemptionAmt)), ); const maxReimburstment = calculateFeeFromRatio( reimbursementRatio, uncappedMaxRedemptionLovelacesAmt, ); const doesMaxBreakMinCollateral = collateralAmt - uncappedMaxRedemptionLovelacesAmt + maxReimburstment < minCollateral; if (!doesMaxBreakMinCollateral) { return { uncappedIAssetRedemptionAmt: uncappedMaxIAssetRedemptionAmt, cappedIAssetRedemptionAmt: uncappedMaxIAssetRedemptionAmt, }; // already below min collateral } else if (collateralAmt <= minCollateral) { return { uncappedIAssetRedemptionAmt: uncappedMaxIAssetRedemptionAmt, cappedIAssetRedemptionAmt: 0n, }; } else { const resLovelaces = rationalDiv( rationalFromInt(minCollateral - collateralAmt), rationalSub(reimbursementRatio, rationalFromInt(1n)), ); const resIAsset = rationalDiv(resLovelaces, price); return { uncappedIAssetRedemptionAmt: uncappedMaxIAssetRedemptionAmt, cappedIAssetRedemptionAmt: rationalFloor(resIAsset), }; } } export function adjustPriceToDecimals( extraDecimals: bigint, price: Rational, ): Rational { return extraDecimals === 0n ? price : extraDecimals > 0n ? rationalMul(price, rationalFromInt(10n ** extraDecimals)) : rationalDiv(price, rationalFromInt(10n ** -extraDecimals)); }