Skip to content

Commit

Permalink
Merge branch 'stage' into 978-fix-dashboard-net-debt-metric-formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
pocin authored Mar 25, 2024
2 parents 5839449 + b30d7aa commit 924250a
Show file tree
Hide file tree
Showing 202 changed files with 27,166 additions and 48,168 deletions.
4 changes: 2 additions & 2 deletions apps/automation-v2/src/config/prodnets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ const TLC_BATCH_LIQUIDATE_CONFIG: TlcBatchLiquidateConfig = {
ACC_LIQ_MAX_CHUNK_NO: 100,
MIN_ETH_BALANCE_WARNING: parseEther('0.1'),
GAS_LIMIT: 1_000_000n,
SUBGRAPH_URL: 'https://api.thegraph.com/subgraphs/name/medariox/v2-mainnet',
SUBGRAPH_ALCHEMY_URL: 'https://subgraph.satsuma-prod.com/a912521dd162/templedao/temple-v2-mainnet/api',
SUBGRAPH_URL: 'https://api.thegraph.com/subgraphs/name/templedao/templedao-tlc-liquidations',
SUBGRAPH_ALCHEMY_URL: 'https://subgraph.satsuma-prod.com/a912521dd162/templedao/tlc-liquidations-mainnet/api',
SUBGRAPH_RETRY_LIMIT: 3,
};

Expand Down
2 changes: 1 addition & 1 deletion apps/automation-v2/src/config/testnets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const TLC_BATCH_LIQUIDATE_CONFIG: TlcBatchLiquidateConfig = {
ACC_LIQ_MAX_CHUNK_NO: 2,
MIN_ETH_BALANCE_WARNING: parseEther('0.1'),
GAS_LIMIT: 1_000_000n,
SUBGRAPH_URL: 'https://api.studio.thegraph.com/proxy/520/v2-sepolia/version/latest',
SUBGRAPH_URL: 'https://thegraph.com/hosted-service/subgraph/medariox/tlc-liquidations-sepolia',
SUBGRAPH_ALCHEMY_URL: '',
SUBGRAPH_RETRY_LIMIT: 3,
};
Expand Down
13 changes: 6 additions & 7 deletions apps/dapp/src/components/Layouts/V2Layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,12 @@ const V2Layout = () => {
Logo: Dashboard,
selected: V2DashboardLocPaths.Trv === loc.pathname,
},
// TODO: Hidden until launch
// {
// label: 'Borrow',
// linkTo: V2DashboardLocPaths.Borrow,
// Logo: Payments,
// selected: V2DashboardLocPaths.Borrow === loc.pathname,
// },
{
label: 'Borrow',
linkTo: V2DashboardLocPaths.Borrow,
Logo: Payments,
selected: V2DashboardLocPaths.Borrow === loc.pathname,
},
{
label: 'Ohmage',
linkTo: V2DashboardLocPaths.Ohmage,
Expand Down
14 changes: 7 additions & 7 deletions apps/dapp/src/components/Pages/Core/DappPages/Borrow/Chart.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChartSupportedTimeInterval, LabeledTimeIntervals, TIME_INTERVAL } from 'utils/time-intervals';
import { LabeledTimeIntervals, TIME_INTERVAL } from 'utils/time-intervals';
import type { AxisDomain } from 'recharts/types/util/types';
import { useEffect, useState } from 'react';
import styled, { useTheme } from 'styled-components';
Expand Down Expand Up @@ -30,14 +30,14 @@ const tooltipLabelFormatters: Record<ChartIntervals, XAxisTickFormatter> = {
...tickFormatters,
};

type Metric = { timestamp: number; utilRatio: number; interestRate: number };
type Metric = { timestamp: number; utilRatio: number; interestYield: number };

const tooltipValuesFormatter = (value: number, name: string) => [
`${formatNumberFixedDecimals(value, 4).toString()}%`,
name,
];

const yDomain: AxisDomain = ([dataMin, dataMax]) => [dataMin * 0.5, Number((dataMax * 1.5).toFixed(2))];
const yDomain: AxisDomain = [0, 100];

export const TlcChart = () => {
const [selectedInterval, setSelectedInterval] = useState<ChartIntervals>('1M');
Expand All @@ -52,7 +52,7 @@ export const TlcChart = () => {
tlcDailySnapshots(orderBy: timestamp, orderDirection: desc) {
timestamp
utilRatio
interestRate
interestYield
}
}`
);
Expand All @@ -66,7 +66,7 @@ export const TlcChart = () => {
const formattedData = formatDailyDataPoints(metrics, CHART_INTERVALS, new Date().getTime(), (metric) => ({
timestamp: metric.timestamp * 1000,
utilRatio: metric.utilRatio * 100,
interestRate: metric.interestRate * 100,
interestYield: metric.interestYield * 100,
}));

return (
Expand All @@ -83,11 +83,11 @@ export const TlcChart = () => {
chartData={formattedData[selectedInterval].reverse()}
xDataKey="timestamp"
lines={[
{ series: 'interestRate', color: theme.palette.brand },
{ series: 'interestYield', color: theme.palette.brand },
{ series: 'utilRatio', color: theme.palette.light },
]}
xTickFormatter={tickFormatters[selectedInterval]}
yTickFormatter={(val, i) => formatNumberAbbreviated(val).string + '%'}
yTickFormatter={(val, i) => formatNumberAbbreviated(val).number.toFixed(2) + '%'}
tooltipLabelFormatter={tooltipLabelFormatters[selectedInterval]}
yDomain={yDomain}
legendFormatter={(name) => (name === 'utilRatio' ? 'Utilization Rate' : 'Interest Rate')}
Expand Down
70 changes: 50 additions & 20 deletions apps/dapp/src/components/Pages/Core/DappPages/Borrow/TLC/Borrow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ import {
TlcInfo,
Warning,
} from '../index';
import { fromAtto } from 'utils/bigNumber';
import { fromAtto, toAtto } from 'utils/bigNumber';
import styled from 'styled-components';
import { ReactNode, useState } from 'react';
import { ReactNode, useEffect, useMemo, useState } from 'react';

interface IProps {
accountPosition: ITlcDataTypes.AccountPositionStructOutput | undefined;
Expand All @@ -34,19 +34,46 @@ interface IProps {
borrow: () => void;
}

export const Borrow: React.FC<IProps> = ({ accountPosition, state, tlcInfo, liquidationInfo, setState, borrow }) => {
export const Borrow: React.FC<IProps> = ({
accountPosition,
state,
tlcInfo,
liquidationInfo,
setState,
borrow,
prices,
}) => {
const [checkbox, setCheckbox] = useState(false);

const getEstimatedLTV = (): string => {
const tpi = prices.tpi;
return accountPosition
? (
((fromAtto(accountPosition.currentDebt) + Number(state.borrowValue)) /
fromAtto(accountPosition?.collateral)) *
(fromAtto(accountPosition?.collateral) * tpi)) *
100
).toFixed(2)
: '0.00';
};

const maxBorrowValueWithCircuitBreaker = useMemo((): { value: number; isCircuitBreakerActive: boolean } => {
const userMaxBorrow = accountPosition
? fromAtto(accountPosition.collateral) * prices.tpi * (MAX_LTV / 100) - fromAtto(accountPosition.currentDebt)
: 0;

const userMaxBorrowBigNumber = toAtto(userMaxBorrow);

if (!tlcInfo) {
return { value: userMaxBorrow, isCircuitBreakerActive: false };
}

if (tlcInfo.daiCircuitBreakerRemaining.lt(userMaxBorrowBigNumber)) {
return { value: fromAtto(tlcInfo.daiCircuitBreakerRemaining), isCircuitBreakerActive: true };
}

return { value: userMaxBorrow, isCircuitBreakerActive: false };
}, [tlcInfo, accountPosition, prices.tpi]);

return (
<>
<RemoveMargin />
Expand All @@ -63,22 +90,11 @@ export const Borrow: React.FC<IProps> = ({ accountPosition, state, tlcInfo, liqu
onHintClick={() => {
setState({
...state,
borrowValue: accountPosition
? (
fromAtto(accountPosition.collateral) * (MAX_LTV / 100) -
fromAtto(accountPosition.currentDebt)
).toFixed(2)
: '0',
borrowValue: maxBorrowValueWithCircuitBreaker.value.toFixed(2),
});
}}
min={1000}
hint={`Max: ${
accountPosition
? (fromAtto(accountPosition.collateral) * (MAX_LTV / 100) - fromAtto(accountPosition.currentDebt)).toFixed(
2
)
: 0
}`}
hint={`Max: ${maxBorrowValueWithCircuitBreaker.value.toFixed(2)}`}
width="100%"
/>

Expand All @@ -92,6 +108,17 @@ export const Borrow: React.FC<IProps> = ({ accountPosition, state, tlcInfo, liqu
</p>
</Warning>
)}
{tlcInfo && tlcInfo.minBorrow < Number(state.borrowValue) && (
<Warning>
<InfoCircle>
<p>i</p>
</InfoCircle>
<p>
The maximum borrow amount is subject to the supplied collateral and the Daily Borrow Limit for across all
users.
</p>
</Warning>
)}
{tlcInfo && tlcInfo.strategyBalance < Number(state.borrowValue) && (
<Warning>
<InfoCircle>
Expand All @@ -100,7 +127,7 @@ export const Borrow: React.FC<IProps> = ({ accountPosition, state, tlcInfo, liqu
<p>
Amount exceeds available DAI.
<br />
Current max borrow: {tlcInfo.strategyBalance.toFixed(4)} DAI
Current max borrow: {tlcInfo.strategyBalance ? Number(tlcInfo.strategyBalance).toFixed(4) : 0} DAI
</p>
</Warning>
)}
Expand All @@ -115,7 +142,7 @@ export const Borrow: React.FC<IProps> = ({ accountPosition, state, tlcInfo, liqu
if (ltvPercent < minLtv) ltvPercent = minLtv;
// Compute the DAI value for the input element based on the LTV change
const daiValue = (
fromAtto(accountPosition.collateral) * ltvPercent -
fromAtto(accountPosition.collateral) * prices.tpi * ltvPercent -
fromAtto(accountPosition.currentDebt)
).toFixed(2);
setState({ ...state, borrowValue: `${Number(daiValue) > 0 ? daiValue : '0'}` });
Expand Down Expand Up @@ -150,7 +177,10 @@ export const Borrow: React.FC<IProps> = ({ accountPosition, state, tlcInfo, liqu
!checkbox ||
(accountPosition && fromAtto(accountPosition.maxBorrow) < Number(state.borrowValue)) ||
(tlcInfo && tlcInfo.minBorrow > Number(state.borrowValue)) ||
(tlcInfo && tlcInfo.strategyBalance < Number(state.borrowValue))
(tlcInfo && tlcInfo.strategyBalance < Number(state.borrowValue)) ||
Number(getEstimatedLTV()) > MAX_LTV ||
(maxBorrowValueWithCircuitBreaker.isCircuitBreakerActive &&
Number(state.borrowValue) > maxBorrowValueWithCircuitBreaker.value)
}
>
Borrow
Expand Down
93 changes: 54 additions & 39 deletions apps/dapp/src/components/Pages/Core/DappPages/Borrow/TLC/Repay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,65 @@ import { Input } from '../../../NewUI/HomeInput';
import { formatToken } from 'utils/formatter';
import { ITlcDataTypes } from 'types/typechain/contracts/interfaces/v2/templeLineOfCredit/ITempleLineOfCredit';
import {
Copy,
FlexBetween,
FlexColCenter,
InfoCircle,
MAX_LTV,
MarginTop,
RangeLabel,
RangeSlider,
RemoveMargin,
State,
Title,
Warning,
Prices,
} from '../index';
import { ZERO, fromAtto } from 'utils/bigNumber';
import { useMemo } from 'react';

interface IProps {
accountPosition: ITlcDataTypes.AccountPositionStructOutput | undefined;
state: State;
setState: React.Dispatch<React.SetStateAction<State>>;
repay: () => void;
repayAll: () => void;
prices: Prices;
}

export const Repay: React.FC<IProps> = ({ accountPosition, state, setState, repay, repayAll }) => {
export const Repay: React.FC<IProps> = ({ accountPosition, state, setState, repay, repayAll, prices }) => {
// used for the range slider label
const maxPossibleLTV = useMemo(() => {
if (!accountPosition) return 0;

const newDebt = fromAtto(accountPosition.currentDebt);
const adjustedNewDebt = Math.max(newDebt, 0);
const estimatedLTV = ((adjustedNewDebt / (fromAtto(accountPosition.collateral) * prices.tpi)) * 100).toFixed(2);

return Number(estimatedLTV);
}, [prices.tpi, accountPosition]);

// used for the estimated LTV label
const getEstimatedLTV = (): string => {
return accountPosition
? (
((fromAtto(accountPosition.currentDebt) - Number(state.repayValue)) / fromAtto(accountPosition.collateral)) *
100
).toFixed(2)
: '0.00';
if (!accountPosition) return '0.00';

// Calculate the new debt after repayment.
const newDebt = fromAtto(accountPosition.currentDebt) - Number(state.repayValue);

// Ensure newDebt does not become negative, which could happen with incorrect repayValue.
const adjustedNewDebt = Math.max(newDebt, 0);

// Calculate the estimated LTV after repayment.
const estimatedLTV = ((adjustedNewDebt / (fromAtto(accountPosition.collateral) * prices.tpi)) * 100).toFixed(2);

return estimatedLTV;
};

const shouldShowRepayAll = useMemo(() => {
return (
parseFloat(state.repayValue) ===
parseFloat(formatToken(accountPosition ? accountPosition.currentDebt : ZERO, state.outputToken))
);
}, [accountPosition, state.outputToken, state.repayValue]);

return (
<>
<RemoveMargin />
Expand Down Expand Up @@ -73,47 +99,36 @@ export const Repay: React.FC<IProps> = ({ accountPosition, state, setState, repa
<RangeSlider
onChange={(e) => {
if (!accountPosition) return;
let ltvPercent = ((Number(e.target.value) / 100) * MAX_LTV) / 100;
// Max LTV is the current LTV
const maxLtv = fromAtto(accountPosition.currentDebt) / fromAtto(accountPosition.collateral);
if (ltvPercent > maxLtv) ltvPercent = maxLtv;
const repayAmount = (
-1 * (ltvPercent * fromAtto(accountPosition.collateral)) +
fromAtto(accountPosition.currentDebt)
).toFixed(2);
console.log(repayAmount);
setState({ ...state, repayValue: `${Number(repayAmount) > 0 ? repayAmount : '0'}` });

const sliderValue = Number(e.target.value); // This is between 0 and 100
const maxRepayable = fromAtto(accountPosition.currentDebt); // Maximum that can be repaid
const repayAmount = (sliderValue / 100) * maxRepayable; // Direct mapping of slider to repay amount

setState({ ...state, repayValue: repayAmount.toFixed(2) });
}}
min={0}
max={100}
value={(Number(getEstimatedLTV()) / MAX_LTV) * 100}
progress={(Number(getEstimatedLTV()) / MAX_LTV) * 100}
value={(Number(state.repayValue) / fromAtto(accountPosition ? accountPosition.currentDebt : ZERO)) * 100}
progress={(Number(state.repayValue) / fromAtto(accountPosition ? accountPosition.currentDebt : ZERO)) * 100}
/>
<FlexBetween>
<RangeLabel>{maxPossibleLTV}%</RangeLabel>
<RangeLabel>0%</RangeLabel>
<RangeLabel>{MAX_LTV}%</RangeLabel>
</FlexBetween>
<FlexColCenter>
<TradeButton
onClick={() => repay()}
// Disable if repay amount is lte zero, gt wallet balance, or gt current debt
disabled={
Number(state.repayValue) <= 0 ||
fromAtto(state.outputTokenBalance) < Number(state.repayValue) ||
(accountPosition && Number(state.repayValue) >= fromAtto(accountPosition.currentDebt))
}
onClick={() => {
if (shouldShowRepayAll) {
return repayAll();
} else {
return repay();
}
}}
// Disable if repay amount is lte zero, or gt wallet balance
disabled={Number(state.repayValue) <= 0 || fromAtto(state.outputTokenBalance) < Number(state.repayValue)}
style={{ width: 'auto' }}
>
Repay {state.repayValue} DAI
</TradeButton>
<Copy>- or -</Copy>
<TradeButton
onClick={() => repayAll()}
// Disable if the amount is greater than the wallet balance
disabled={accountPosition && fromAtto(accountPosition.currentDebt) > fromAtto(state.outputTokenBalance)}
style={{ width: 'auto', marginTop: '0' }}
>
Repay Total
{shouldShowRepayAll ? 'Repay All' : `Repay ${state.repayValue} DAI`}
</TradeButton>
</FlexColCenter>
</>
Expand Down
Loading

0 comments on commit 924250a

Please sign in to comment.