/ src / utils / ghoUtilities.tsx
ghoUtilities.tsx
  1  import { GhoReserveData, GhoUserData, normalize } from '@aave/math-utils';
  2  import { ComputedReserveData } from 'src/hooks/app-data-provider/useAppDataProvider';
  3  
  4  export const GHO_SYMBOL = 'GHO';
  5  
  6  /**
  7   * List of markets where new GHO minting is available.
  8   * Note that his is different from markets where GHO is listed as a reserve.
  9   */
 10  export const GHO_MINTING_MARKETS = [
 11    'proto_mainnet_v3',
 12    'fork_proto_mainnet_v3',
 13    'proto_sepolia_v3',
 14    'fork_proto_sepolia_v3',
 15  ];
 16  
 17  export const getGhoReserve = (reserves: ComputedReserveData[]) => {
 18    return reserves.find((reserve) => reserve.symbol === GHO_SYMBOL);
 19  };
 20  
 21  /**
 22   * Calculates the weighted average APY
 23   * @param baseVariableBorrowRate - The base variable borrow rate, normalized
 24   * @param totalBorrowAmount - The total amount of the asset that is being borrowed
 25   * @param discountableAmount - The amount that can be discounted for the user
 26   * @param borrowRateAfterDiscount - The borrow rate after the discount is applied
 27   * @returns
 28   */
 29  export const weightedAverageAPY = (
 30    baseVariableBorrowRate: number,
 31    totalBorrowAmount: number,
 32    discountableAmount: number,
 33    borrowRateAfterDiscount: number
 34  ) => {
 35    if (discountableAmount === 0) return baseVariableBorrowRate;
 36    if (totalBorrowAmount <= discountableAmount) return borrowRateAfterDiscount;
 37  
 38    const nonDiscountableAmount = totalBorrowAmount - discountableAmount;
 39  
 40    return (
 41      (nonDiscountableAmount * baseVariableBorrowRate +
 42        discountableAmount * borrowRateAfterDiscount) /
 43      totalBorrowAmount
 44    );
 45  };
 46  
 47  /**
 48   * This helps display the discountable amount of GHO based off of how much is being borrowed and how much is discountable.
 49   * This is used in both the borrow modal and the discount rate calculator.
 50   * @param discountableGhoAmount - The amount of GHO that is discountable
 51   * @param amountGhoBeingBorrowed - The amount of GHO requesting to be borrowed
 52   * @returns The amount of discountable GHO as a number in a display-friendly form
 53   */
 54  export const displayDiscountableAmount = (
 55    discountableGhoAmount: number,
 56    amountGhoBeingBorrowed: number
 57  ): number => {
 58    return discountableGhoAmount >= amountGhoBeingBorrowed
 59      ? amountGhoBeingBorrowed
 60      : discountableGhoAmount;
 61  };
 62  
 63  /**
 64   * This helps display the non-discountable amount of GHO based off of how much is being borrowed and how much is discountable.
 65   * This is used in both the borrow modal and the discount rate calculator.
 66   * @param discountableGhoAmount - The amount of GHO that is discountable
 67   * @param amountGhoBeingBorrowed - The amount of GHO requesting to be borrowed
 68   * @returns The amount of non-discountable GHO as a number in a display-friendly form
 69   */
 70  export const displayNonDiscountableAmount = (
 71    discountableGhoAmount: number,
 72    amountGhoBeingBorrowed: number
 73  ): number => {
 74    return discountableGhoAmount >= amountGhoBeingBorrowed
 75      ? 0
 76      : amountGhoBeingBorrowed - discountableGhoAmount;
 77  };
 78  
 79  interface ReserveWithSymbol {
 80    symbol: string;
 81  }
 82  
 83  type FindAndFilterReturn<T> = {
 84    value: T | undefined;
 85    filtered: Array<T>;
 86  };
 87  
 88  export const findAndFilterMintableGhoReserve = <T extends ReserveWithSymbol>(
 89    reserves: Array<T>,
 90    currentMarket: string
 91  ) => {
 92    if (!GHO_MINTING_MARKETS.includes(currentMarket)) return { value: undefined, filtered: reserves };
 93  
 94    return reserves.reduce<FindAndFilterReturn<T>>(
 95      (acum, reserve) => {
 96        if (reserve.symbol === GHO_SYMBOL) return { value: reserve, filtered: acum.filtered };
 97        else return { ...acum, filtered: acum.filtered.concat(reserve) };
 98      },
 99      {
100        value: undefined,
101        filtered: [],
102      }
103    );
104  };
105  
106  /**
107   * Determines if the given symbol is GHO and the market supports minting new GHO
108   */
109  export const displayGhoForMintableMarket = ({
110    symbol,
111    currentMarket,
112  }: GhoUtilMintingAvailableParams): boolean => {
113    return symbol === GHO_SYMBOL && GHO_MINTING_MARKETS.includes(currentMarket);
114  };
115  
116  interface GhoUtilMintingAvailableParams {
117    symbol: string;
118    currentMarket: string;
119  }
120  
121  export const ghoUserQualifiesForDiscount = (
122    ghoReserveData: GhoReserveData,
123    ghoUserData: GhoUserData,
124    futureBorrowAmount = '0'
125  ) => {
126    const borrowBalance = Number(normalize(ghoUserData.userGhoScaledBorrowBalance, 18));
127    const minBorrowBalanceForDiscount = Number(
128      normalize(ghoReserveData.ghoMinDebtTokenBalanceForDiscount, 18)
129    );
130  
131    const stkAaveBalance = Number(normalize(ghoUserData.userDiscountTokenBalance, 18));
132    const minStkAaveBalanceForDiscount = Number(
133      normalize(ghoReserveData.ghoMinDiscountTokenBalanceForDiscount, 18)
134    );
135  
136    return (
137      borrowBalance + Number(futureBorrowAmount) >= minBorrowBalanceForDiscount &&
138      stkAaveBalance >= minStkAaveBalanceForDiscount
139    );
140  };