diff --git a/apps/dapp/src/components/Pages/Core/DappPages/Borrow/TLC/Borrow.tsx b/apps/dapp/src/components/Pages/Core/DappPages/Borrow/TLC/Borrow.tsx
index d7c9b109f..334b0dfbf 100644
--- a/apps/dapp/src/components/Pages/Core/DappPages/Borrow/TLC/Borrow.tsx
+++ b/apps/dapp/src/components/Pages/Core/DappPages/Borrow/TLC/Borrow.tsx
@@ -22,7 +22,7 @@ import {
} from '../index';
import { fromAtto, toAtto, ZERO } from 'utils/bigNumber';
import styled from 'styled-components';
-import { ReactNode, useEffect, useMemo, useState } from 'react';
+import { ReactNode, useMemo, useState } from 'react';
interface IProps {
accountPosition: ITlcDataTypes.AccountPositionStructOutput | undefined;
@@ -56,10 +56,7 @@ export const Borrow: React.FC = ({
: '0.00';
};
- const maxBorrowValueWithCircuitBreaker = useMemo((): {
- value: number;
- isCircuitBreakerActive: boolean;
- } => {
+ const maxBorrowValue = useMemo((): number => {
const userMaxBorrow = accountPosition
? fromAtto(accountPosition.collateral) * prices.tpi * (MAX_LTV / 100) -
fromAtto(accountPosition.currentDebt)
@@ -67,28 +64,12 @@ export const Borrow: React.FC = ({
const userMaxBorrowBigNumber = toAtto(userMaxBorrow);
- let returnValue = { value: userMaxBorrow, isCircuitBreakerActive: false };
-
- // Check if the dai circuit breaker is active
- if (
- tlcInfo &&
- tlcInfo.daiCircuitBreakerRemaining.lt(userMaxBorrowBigNumber)
- ) {
- returnValue = {
- value: fromAtto(tlcInfo.daiCircuitBreakerRemaining),
- isCircuitBreakerActive: true,
- };
- }
-
// Check if trvAvailable from the contract is less than the user max borrow
- if (tlcInfo && tlcInfo.trvAvailable.lt(userMaxBorrowBigNumber)) {
- returnValue = {
- value: fromAtto(tlcInfo.trvAvailable || ZERO),
- isCircuitBreakerActive: true,
- };
+ if (tlcInfo && tlcInfo.availableToBorrow.lt(userMaxBorrowBigNumber)) {
+ return fromAtto(tlcInfo.availableToBorrow || ZERO);
}
- return returnValue;
+ return userMaxBorrow;
}, [tlcInfo, accountPosition, prices.tpi]);
return (
@@ -109,11 +90,11 @@ export const Borrow: React.FC = ({
onHintClick={() => {
setState({
...state,
- borrowValue: maxBorrowValueWithCircuitBreaker.value.toFixed(2),
+ borrowValue: maxBorrowValue.toFixed(2),
});
}}
min={1000}
- hint={`Max: ${maxBorrowValueWithCircuitBreaker.value.toFixed(2)}`}
+ hint={`Max: ${maxBorrowValue.toFixed(2)}`}
width="100%"
/>
@@ -138,22 +119,23 @@ export const Borrow: React.FC = ({
)}
- {tlcInfo && tlcInfo.strategyBalance < Number(state.borrowValue) && (
-
-
- i
-
-
- Amount exceeds available DAI.
-
- Current max borrow:{' '}
- {tlcInfo.strategyBalance
- ? Number(tlcInfo.strategyBalance).toFixed(4)
- : 0}{' '}
- DAI
-
-
- )}
+ {tlcInfo &&
+ fromAtto(tlcInfo.availableToBorrow) < Number(state.borrowValue) && (
+
+
+ i
+
+
+ Amount exceeds available DAI.
+
+ Current max borrow:{' '}
+ {tlcInfo.availableToBorrow
+ ? fromAtto(tlcInfo.availableToBorrow).toFixed(4)
+ : 0}{' '}
+ DAI
+
+
+ )}
Estimated DAI LTV: {getEstimatedLTV()}%
= ({
fromAtto(accountPosition.maxBorrow) <
Number(state.borrowValue)) ||
(tlcInfo && tlcInfo.minBorrow > Number(state.borrowValue)) ||
- (tlcInfo && tlcInfo.strategyBalance < Number(state.borrowValue)) ||
- Number(getEstimatedLTV()) > MAX_LTV ||
- (maxBorrowValueWithCircuitBreaker.isCircuitBreakerActive &&
- Number(state.borrowValue) >
- maxBorrowValueWithCircuitBreaker.value)
+ (tlcInfo &&
+ fromAtto(tlcInfo.availableToBorrow) <
+ Number(state.borrowValue)) ||
+ Number(getEstimatedLTV()) > MAX_LTV
}
>
Borrow
diff --git a/apps/dapp/src/components/Pages/Core/DappPages/Borrow/TLC/Withdraw.tsx b/apps/dapp/src/components/Pages/Core/DappPages/Borrow/TLC/Withdraw.tsx
index cdf3a6690..b22992cc6 100644
--- a/apps/dapp/src/components/Pages/Core/DappPages/Borrow/TLC/Withdraw.tsx
+++ b/apps/dapp/src/components/Pages/Core/DappPages/Borrow/TLC/Withdraw.tsx
@@ -59,10 +59,7 @@ export const Withdraw: React.FC = ({
return getEstimatedCollateral() * prices.tpi * (MAX_LTV / 100);
};
- const maxWithdrawWithCircuitBreaker = useMemo((): {
- value: number;
- isCircuitBreakerActive: boolean;
- } => {
+ const maxWithdrawValue = useMemo((): number => {
const userMaxWithdraw = accountPosition
? fromAtto(accountPosition.collateral) -
fromAtto(accountPosition.currentDebt) / (MAX_LTV / 100) / prices.tpi
@@ -70,18 +67,16 @@ export const Withdraw: React.FC = ({
const userMaxWithdrawBigNumber = toAtto(userMaxWithdraw);
- if (!tlcInfo) {
- return { value: userMaxWithdraw, isCircuitBreakerActive: false };
+ if (
+ tlcInfo &&
+ tlcInfo.circuitBreakers.templeCircuitBreakerRemaining.lt(
+ userMaxWithdrawBigNumber
+ )
+ ) {
+ return fromAtto(tlcInfo.circuitBreakers.templeCircuitBreakerRemaining);
}
- if (tlcInfo.templeCircuitBreakerRemaining.lt(userMaxWithdrawBigNumber)) {
- return {
- value: fromAtto(tlcInfo.templeCircuitBreakerRemaining),
- isCircuitBreakerActive: true,
- };
- }
-
- return { value: userMaxWithdraw, isCircuitBreakerActive: false };
+ return userMaxWithdraw;
}, [accountPosition, prices.tpi, tlcInfo]);
return (
@@ -102,11 +97,11 @@ export const Withdraw: React.FC = ({
onHintClick={() => {
setState({
...state,
- withdrawValue: maxWithdrawWithCircuitBreaker.value.toFixed(2),
+ withdrawValue: maxWithdrawValue.toFixed(2),
});
}}
min={0}
- hint={`Max: ${maxWithdrawWithCircuitBreaker.value.toFixed(2)}`}
+ hint={`Max: ${maxWithdrawValue.toFixed(2)}`}
width="100%"
/>
{/* Only display if user has borrows */}
@@ -168,7 +163,7 @@ export const Withdraw: React.FC = ({
// Disable if amount is 0 or greater than max withdraw
disabled={
Number(state.withdrawValue) <= 0 ||
- Number(state.withdrawValue) > maxWithdrawWithCircuitBreaker.value
+ Number(state.withdrawValue) > maxWithdrawValue
}
>
Withdraw
diff --git a/apps/dapp/src/components/Pages/Core/DappPages/Borrow/index.tsx b/apps/dapp/src/components/Pages/Core/DappPages/Borrow/index.tsx
index 01bce1b18..a4f744f49 100644
--- a/apps/dapp/src/components/Pages/Core/DappPages/Borrow/index.tsx
+++ b/apps/dapp/src/components/Pages/Core/DappPages/Borrow/index.tsx
@@ -15,7 +15,7 @@ import {
queryTlcPrices,
subgraphQuery,
} from 'utils/subgraph';
-import { BigNumber, ethers } from 'ethers';
+import { BigNumber } from 'ethers';
import daiImg from 'assets/images/newui-images/tokens/dai.png';
import templeImg from 'assets/images/newui-images/tokens/temple.png';
import { formatToken } from 'utils/formatter';
@@ -49,18 +49,23 @@ export type TlcInfo = {
minBorrow: number;
borrowRate: number;
liquidationLtv: number;
- strategyBalance: number;
debtCeiling: number;
- daiCircuitBreakerRemaining: BigNumber;
- templeCircuitBreakerRemaining: BigNumber;
+ circuitBreakers: {
+ daiCircuitBreakerRemaining: BigNumber;
+ templeCircuitBreakerRemaining: BigNumber;
+ };
outstandingUserDebt: number;
- trvAvailable: BigNumber;
+ availableToBorrow: BigNumber;
};
export const MAX_LTV = 85;
export type Prices = { templePrice: number; daiPrice: number; tpi: number };
+const minBN = (v1: BigNumber, v2: BigNumber): BigNumber => {
+ return v1.lt(v2) ? v1 : v2;
+};
+
export const BorrowPage = () => {
const [{}, connect] = useConnectWallet();
const { balance, wallet, updateBalance, signer, ensureAllowance } =
@@ -147,60 +152,48 @@ export const BorrowPage = () => {
const tlcContract = new TempleLineOfCredit__factory(signer).attach(
env.contracts.tlc
);
- const debtPosition = await tlcContract.totalDebtPosition();
- const totalUserDebt = debtPosition.totalDebt;
- const utilizationRatio = debtPosition.utilizationRatio;
- const outstandingUserDebt = debtPosition[2];
-
- // NOTE: We are intentionally rounding here to nearest 1e18
- const debtCeiling = totalUserDebt
- .div(utilizationRatio)
- .mul(ethers.utils.parseEther('1'));
-
- const userAvailableToBorrowFromTlc = debtCeiling.sub(totalUserDebt);
-
const trvContract = new TreasuryReservesVault__factory(signer).attach(
env.contracts.treasuryReservesVault
);
- const trvAvailable = await trvContract.totalAvailable(env.contracts.dai);
-
- const strategyAvailalableToBorrowFromTrv =
- await trvContract.availableForStrategyToBorrow(
+ const [
+ debtPosition,
+ debtCeiling,
+ trvAvailableCash,
+ tlcAvailalableToBorrow,
+ [debtTokenConfig, debtTokenData],
+ circuitBreakers,
+ ] = await Promise.all([
+ tlcContract.totalDebtPosition(),
+ trvContract.strategyDebtCeiling(
env.contracts.strategies.tlcStrategy,
env.contracts.dai
- );
-
- // available to borrow
- // return the lesser of userAvailableToBorrowFromTlc and strategyAvailalableToBorrowFromTrv
- const maxAvailableToBorrow = userAvailableToBorrowFromTlc.gte(
- strategyAvailalableToBorrowFromTrv
- )
- ? strategyAvailalableToBorrowFromTrv
- : userAvailableToBorrowFromTlc;
-
- // Getting the max borrow LTV and interest rate
- const [debtTokenConfig, debtTokenData] =
- await tlcContract.debtTokenDetails();
- const maxLtv = debtTokenConfig.maxLtvRatio;
-
- // current borrow apy
- const currentBorrowInterestRate = aprToApy(
- fromAtto(debtTokenData.interestRate)
+ ),
+ trvContract.totalAvailable(env.contracts.dai),
+ trvContract.availableForStrategyToBorrow(
+ env.contracts.strategies.tlcStrategy,
+ env.contracts.dai
+ ),
+ tlcContract.debtTokenDetails(),
+ getCircuitBreakers(),
+ ]);
+
+ // The minimum of:
+ // - What cash is available
+ // - The TLC free to borrow under it's debt ceiling cap
+ // - The circuit breaker availability
+ const trvAvailable = minBN(
+ minBN(trvAvailableCash, tlcAvailalableToBorrow),
+ circuitBreakers?.daiCircuitBreakerRemaining || ZERO
);
- const circuitBreakers = await getCircuitBreakers();
-
return {
debtCeiling: fromAtto(debtCeiling),
- strategyBalance: fromAtto(maxAvailableToBorrow),
- borrowRate: currentBorrowInterestRate,
- liquidationLtv: fromAtto(maxLtv),
- outstandingUserDebt: fromAtto(outstandingUserDebt),
- trvAvailable: trvAvailable,
- daiCircuitBreakerRemaining: circuitBreakers?.daiCircuitBreakerRemaining,
- templeCircuitBreakerRemaining:
- circuitBreakers?.templeCircuitBreakerRemaining,
+ availableToBorrow: trvAvailable,
+ borrowRate: aprToApy(fromAtto(debtTokenData.interestRate)),
+ liquidationLtv: fromAtto(debtTokenConfig.maxLtvRatio),
+ outstandingUserDebt: fromAtto(debtPosition.totalDebt),
+ circuitBreakers,
};
}, [signer, getCircuitBreakers]);
@@ -238,14 +231,13 @@ export const BorrowPage = () => {
minBorrow: parseFloat(response.tlcDailySnapshots[0].minBorrowAmount),
borrowRate: tlcInfoFromContracts?.borrowRate || 0,
liquidationLtv: tlcInfoFromContracts?.liquidationLtv || 0,
- strategyBalance: tlcInfoFromContracts?.strategyBalance || 0,
debtCeiling: tlcInfoFromContracts?.debtCeiling || 0,
- daiCircuitBreakerRemaining:
- tlcInfoFromContracts?.daiCircuitBreakerRemaining || ZERO,
- templeCircuitBreakerRemaining:
- tlcInfoFromContracts?.templeCircuitBreakerRemaining || ZERO,
outstandingUserDebt: tlcInfoFromContracts?.outstandingUserDebt || 0,
- trvAvailable: tlcInfoFromContracts?.trvAvailable || ZERO,
+ availableToBorrow: tlcInfoFromContracts?.availableToBorrow || ZERO,
+ circuitBreakers: tlcInfoFromContracts?.circuitBreakers || {
+ daiCircuitBreakerRemaining: ZERO,
+ templeCircuitBreakerRemaining: ZERO,
+ },
});
} catch (e) {
setMetricsLoading(false);
@@ -488,19 +480,8 @@ export const BorrowPage = () => {
const availableToBorrow = useMemo(() => {
if (!tlcInfo) return '...';
- const availableAsBigNumber = toAtto(tlcInfo.strategyBalance);
- let borrowableAmount = tlcInfo.strategyBalance;
-
- if (tlcInfo.daiCircuitBreakerRemaining.lt(availableAsBigNumber)) {
- borrowableAmount = fromAtto(tlcInfo.daiCircuitBreakerRemaining);
- }
-
- const trvAvailable = fromAtto(tlcInfo.trvAvailable);
- if (trvAvailable < borrowableAmount) {
- borrowableAmount = trvAvailable;
- }
-
- return `$${Number(borrowableAmount).toLocaleString('en', {
+ const borrowableAmount = Number(fromAtto(tlcInfo.availableToBorrow));
+ return `$${borrowableAmount.toLocaleString('en', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}`;