Skip to content

Commit

Permalink
Merge pull request #3264 from OlympusDAO/develop
Browse files Browse the repository at this point in the history
[Release] - Cooler Consolidation UX Updates/Balance Checks, Emission Manager Stats
  • Loading branch information
brightiron authored Jan 15, 2025
2 parents e2f95be + 66f6ead commit 4623227
Show file tree
Hide file tree
Showing 4 changed files with 241 additions and 24 deletions.
52 changes: 51 additions & 1 deletion src/views/Emission/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,35 @@ import { useGetEmissionConfig } from "src/views/Emission/hooks/useGetEmissionCon
export const Emission = () => {
const { data: emissionConfig, isLoading } = useGetEmissionConfig();

// Calculate annualized growth rates
const calculateAnnualizedRate = (dailyRate: number) => {
if (dailyRate === 0) {
return 0;
}
return (Math.pow(1 + dailyRate, 365) - 1) * 100;
};

// Parse the percentage strings into decimal numbers
const parsePercentage = (percentStr: string | undefined) => {
if (!percentStr) return undefined;
return Number(percentStr.replace("%", "")) / 100;
};

const emissionRate = parsePercentage(emissionConfig?.currentEmissionRate);
const premium = parsePercentage(emissionConfig?.premium);

const supplyGrowthRate = emissionRate !== undefined ? calculateAnnualizedRate(emissionRate) : undefined;

const treasuryGrowthRate =
emissionRate !== undefined && premium !== undefined
? calculateAnnualizedRate(emissionRate * (1 + premium))
: undefined;

const backingGrowthRate =
emissionRate && premium
? calculateAnnualizedRate((1 + emissionRate * (1 + premium)) / (1 + emissionRate) - 1)
: undefined;

return (
<div id="stake-view">
<PageTitle name={"Emission Manager"} noMargin />
Expand All @@ -20,7 +49,7 @@ export const Emission = () => {
component={RouterLink}
target="_blank"
rel="noopener noreferrer"
to={`https://app.bondprotocol.finance/#/market/1/${emissionConfig.activeMarketId}`}
to={`https://app.bondprotocol.finance/#/market/1/${emissionConfig?.activeMarketId}`}
>
View market details
</Link>
Expand Down Expand Up @@ -52,6 +81,27 @@ export const Emission = () => {
<Grid item xs={12} md={4}>
<Metric label="Next Emission" metric={emissionConfig?.nextSale.emission} isLoading={isLoading} />
</Grid>
<Grid item xs={12} md={4}>
<Metric
label="Supply Growth Rate (Annual)"
metric={supplyGrowthRate ? `${supplyGrowthRate.toFixed(2)}%` : "0%"}
isLoading={isLoading}
/>
</Grid>
<Grid item xs={12} md={4}>
<Metric
label="Treasury Growth Rate (Annual)"
metric={treasuryGrowthRate ? `${treasuryGrowthRate.toFixed(2)}%` : "0%"}
isLoading={isLoading}
/>
</Grid>
<Grid item xs={12} md={4}>
<Metric
label="Backing Growth Rate (Annual)"
metric={backingGrowthRate ? `${backingGrowthRate.toFixed(2)}%` : "0%"}
isLoading={isLoading}
/>
</Grid>
</Grid>
</Paper>

Expand Down
45 changes: 45 additions & 0 deletions src/views/Lending/Cooler/hooks/useGetWalletFundsRequired.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { COOLER_CONSOLIDATION_CONTRACT } from "src/constants/contracts";
import { DecimalBigNumber } from "src/helpers/DecimalBigNumber/DecimalBigNumber";
import { useTestableNetworks } from "src/hooks/useTestableNetworks";
import { CoolerConsolidation__factory } from "src/typechain";
import { useProvider, useQuery } from "wagmi";

export const useGetWalletFundsRequired = ({
clearingHouseAddress,
coolerAddress,
loanIds,
}: {
clearingHouseAddress: string;
coolerAddress: string;
loanIds: number[];
}) => {
const provider = useProvider();
const networks = useTestableNetworks();

const { data, isFetched, isLoading } = useQuery(
["useGetWalletFundsRequired", clearingHouseAddress, coolerAddress],
async () => {
try {
const contractAddress = COOLER_CONSOLIDATION_CONTRACT.addresses[networks.MAINNET];
const contract = CoolerConsolidation__factory.connect(contractAddress, provider);
const requiredDebtInWallet = await contract.fundsRequired(clearingHouseAddress, coolerAddress, loanIds);
const requiredCollateralInWallet = await contract.collateralRequired(
clearingHouseAddress,
coolerAddress,
loanIds,
);
return {
totalDebtNeededInWallet: new DecimalBigNumber(requiredDebtInWallet.interest, 18),
totalCollateralNeededInWallet: new DecimalBigNumber(requiredCollateralInWallet.additionalCollateral, 18),
};
} catch {
return {
totalDebtNeededInWallet: new DecimalBigNumber("0", 18),
totalCollateralNeededInWallet: new DecimalBigNumber("0", 18),
};
}
},
{ enabled: !!coolerAddress },
);
return { data, isFetched, isLoading };
};
154 changes: 135 additions & 19 deletions src/views/Lending/Cooler/positions/ConsolidateLoan.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
import { Box, FormControl, MenuItem, Select, SelectChangeEvent, SvgIcon, Typography } from "@mui/material";
import {
Box,
Divider,
FormControl,
MenuItem,
Select,
SelectChangeEvent,
SvgIcon,
Tooltip,
Typography,
} from "@mui/material";
import { InfoNotification, Modal, PrimaryButton } from "@olympusdao/component-library";
import { BigNumber } from "ethers";
import { formatEther } from "ethers/lib/utils.js";
Expand All @@ -17,6 +27,7 @@ import { useCreateCooler } from "src/views/Lending/Cooler/hooks/useCreateCooler"
import { useGetClearingHouse } from "src/views/Lending/Cooler/hooks/useGetClearingHouse";
import { useGetConsolidationAllowances } from "src/views/Lending/Cooler/hooks/useGetConsolidationAllowances";
import { useGetCoolerLoans } from "src/views/Lending/Cooler/hooks/useGetCoolerLoans";
import { useGetWalletFundsRequired } from "src/views/Lending/Cooler/hooks/useGetWalletFundsRequired";

export const ConsolidateLoans = ({
v3CoolerAddress,
Expand Down Expand Up @@ -107,22 +118,35 @@ export const ConsolidateLoans = ({
loanIds,
});

const { data: walletFundsRequired } = useGetWalletFundsRequired({
clearingHouseAddress: clearingHouseAddresses.v3.clearingHouseAddress,
coolerAddress: coolerAddress || "",
loanIds,
});

const maturityDate = new Date();
maturityDate.setDate(maturityDate.getDate() + Number(duration || 0));
const { data: debtBalance } = useBalance({ [networks.MAINNET]: debtAddress || "" })[networks.MAINNET];
const [insufficientCollateral, setInsufficientCollateral] = useState<boolean | undefined>();
const { data: gOhmBalance } = useBalance(GOHM_ADDRESSES)[networks.MAINNET];
const [insufficientBalances, setInsufficientBalances] = useState<
| {
debt: boolean;
gohm: boolean;
}
| undefined
>();

useEffect(() => {
if (!debtBalance) {
setInsufficientCollateral(undefined);
if (!debtBalance || !gOhmBalance || !walletFundsRequired) {
setInsufficientBalances(undefined);
return;
}

if (Number(debtBalance) < parseFloat(formatEther(totals.interest))) {
setInsufficientCollateral(true);
} else {
setInsufficientCollateral(false);
}
}, [debtBalance, totals.interest]);
setInsufficientBalances({
debt: Number(debtBalance) < Number(walletFundsRequired.totalDebtNeededInWallet.toString()),
gohm: Number(gOhmBalance) < Number(walletFundsRequired.totalCollateralNeededInWallet.toString()),
});
}, [debtBalance, gOhmBalance, walletFundsRequired]);

const handleVersionChange = (event: SelectChangeEvent) => {
setSelectedVersion(event.target.value as "v1" | "v2" | "v3");
Expand Down Expand Up @@ -188,16 +212,106 @@ export const ConsolidateLoans = ({
<>
<InfoNotification>
All existing open loans for this Cooler and Clearinghouse will be repaid and consolidated into a new
loan with a {duration} day duration. You must hold enough {clearingHouseAddresses.v3.debtAssetName} in
your wallet to cover the interest owed at consolidation.
loan with a {duration} day duration. You must hold enough {clearingHouseAddresses.v3.debtAssetName} and
gOHM in your wallet to cover the interest owed at consolidation.
</InfoNotification>
{walletFundsRequired && (
<>
<Typography fontWeight="500">Wallet Balances Required</Typography>
<Box
display="flex"
flexDirection="row"
justifyContent="space-between"
alignItems="center"
mb={"9px"}
mt={"9px"}
>
<Typography sx={{ fontSize: "15px", lineHeight: "21px" }}>
{clearingHouseAddresses.v3.debtAssetName} Balance
</Typography>
<Box display="flex" flexDirection="column" textAlign="right">
<Tooltip title={walletFundsRequired?.totalDebtNeededInWallet.toString()}>
<Typography sx={{ fontSize: "15px", lineHeight: "21px" }}>
{Math.ceil(Number(walletFundsRequired?.totalDebtNeededInWallet.toString()) * 100) / 100}
</Typography>
</Tooltip>
</Box>
</Box>
<Box
display="flex"
flexDirection="row"
justifyContent="space-between"
alignItems="center"
mb={"9px"}
mt={"9px"}
>
<Typography sx={{ fontSize: "15px", lineHeight: "21px" }}>gOHM Balance</Typography>
<Box display="flex" flexDirection="column" textAlign="right">
<Tooltip title={walletFundsRequired?.totalCollateralNeededInWallet.toString()}>
<Typography sx={{ fontSize: "15px", lineHeight: "21px" }}>
{Math.ceil(Number(walletFundsRequired?.totalCollateralNeededInWallet.toString()) * 100000) /
100000}
</Typography>
</Tooltip>
</Box>
</Box>
</>
)}
<Box sx={{ width: "100%", my: "21px" }}>
<Divider />
</Box>
<Typography fontWeight="500" mt="21px">
Required Allowances
</Typography>
<Box
display="flex"
flexDirection="row"
justifyContent="space-between"
alignItems="center"
mb={"9px"}
mt={"9px"}
>
<Typography sx={{ fontSize: "15px", lineHeight: "21px" }}>
{clearingHouseAddresses.v3.debtAssetName}
</Typography>
<Box display="flex" flexDirection="column" textAlign="right">
<Tooltip title={allowances?.totalDebtWithFee.toString()}>
<Typography sx={{ fontSize: "15px", lineHeight: "21px" }}>
{Math.ceil(Number(allowances?.totalDebtWithFee.toString()) * 100) / 100}
</Typography>
</Tooltip>
</Box>
</Box>
<Box
display="flex"
flexDirection="row"
justifyContent="space-between"
alignItems="center"
mb={"9px"}
mt={"9px"}
>
<Typography sx={{ fontSize: "15px", lineHeight: "21px" }}>gOHM</Typography>
<Box display="flex" flexDirection="column" textAlign="right">
<Tooltip title={allowances?.consolidatedLoanCollateral.toString()}>
<Typography sx={{ fontSize: "15px", lineHeight: "21px" }}>
{Math.ceil(Number(allowances?.consolidatedLoanCollateral.toString()) * 100000) / 100000}
</Typography>
</Tooltip>
</Box>
</Box>
<Box sx={{ width: "100%", my: "21px" }}>
<Divider />
</Box>
<Typography fontWeight="500" mt="21px">
Consolidated Loan Details
</Typography>
<Box
display="flex"
flexDirection="row"
justifyContent="space-between"
alignItems="center"
mb={"9px"}
mt={"21px"}
mt={"9px"}
>
<Typography sx={{ fontSize: "15px", lineHeight: "21px" }}>Loans to Consolidate</Typography>
<Box display="flex" flexDirection="column" textAlign="right">
Expand All @@ -210,7 +324,7 @@ export const ConsolidateLoans = ({
justifyContent="space-between"
alignItems="center"
mb={"9px"}
mt={"21px"}
mt={"9px"}
>
<Typography sx={{ fontSize: "15px", lineHeight: "21px" }}>New Principal Amount</Typography>
<Box display="flex" flexDirection="column" textAlign="right">
Expand All @@ -226,7 +340,7 @@ export const ConsolidateLoans = ({
justifyContent="space-between"
alignItems="center"
mb={"9px"}
mt={"21px"}
mt={"9px"}
>
<Typography sx={{ fontSize: "15px", lineHeight: "21px" }}>Interest Owed At Consolidation</Typography>
<Box display="flex" flexDirection="column" textAlign="right">
Expand All @@ -242,7 +356,7 @@ export const ConsolidateLoans = ({
justifyContent="space-between"
alignItems="center"
mb={"9px"}
mt={"21px"}
mt={"9px"}
>
<Typography sx={{ fontSize: "15px", lineHeight: "21px" }}>New Maturity Date</Typography>
<Box display="flex" flexDirection="column" textAlign="right">
Expand All @@ -261,7 +375,7 @@ export const ConsolidateLoans = ({
</Box>
</>
)}
{selectedVersion && !insufficientCollateral ? (
{selectedVersion && !insufficientBalances?.debt && !insufficientBalances?.gohm ? (
<WalletConnectedGuard fullWidth>
{needsCoolerCreation ? (
<PrimaryButton
Expand Down Expand Up @@ -311,9 +425,11 @@ export const ConsolidateLoans = ({
</WalletConnectedGuard>
) : (
<PrimaryButton disabled fullWidth>
{insufficientCollateral
{insufficientBalances?.debt
? `Insufficient ${clearingHouseAddresses.v3.debtAssetName} Balance`
: "Select loans to consolidate"}
: insufficientBalances?.gohm
? "Insufficient gOHM Balance"
: "Select loans to consolidate"}
</PrimaryButton>
)}
</>
Expand Down
14 changes: 10 additions & 4 deletions src/views/Lending/Cooler/positions/Positions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,11 @@ export const CoolerPositions = () => {
...(loansV2 || []).map(loan => ({ ...loan, version: "v2" })),
...(loansV3 || []).map(loan => ({ ...loan, version: "v3" })),
];
return allLoans;
return allLoans.sort((a, b) => {
const expiryA = Number(a.expiry?.toString() || 0);
const expiryB = Number(b.expiry?.toString() || 0);
return expiryA - expiryB;
});
};

const getActiveClearingHouse = () => {
Expand Down Expand Up @@ -132,6 +136,8 @@ export const CoolerPositions = () => {
clearingHouses.v2 &&
clearingHouses.v3);

const allLoansLoaded = isFetchedLoansV1 && isFetchedLoansV2 && isFetchedLoansV3;

return (
<div id="cooler-positions">
<Grid container spacing={2}>
Expand Down Expand Up @@ -160,7 +166,7 @@ export const CoolerPositions = () => {
</Box>
)}

{allLoans.length === 0 && isFetchedLoansV1 && isFetchedLoansV2 && isFetchedLoansV3 && address && (
{allLoans.length === 0 && allLoansLoaded && address && (
<Box display="flex" justifyContent="center">
<Box textAlign="center">
<Box fontWeight={700}>You currently have no Cooler loans</Box>
Expand All @@ -183,13 +189,13 @@ export const CoolerPositions = () => {
</Box>
)}

{address && (!isFetchedLoansV1 || !isFetchedLoansV2 || !isFetchedLoansV3) && (
{address && !allLoansLoaded && (
<Box display="flex" justifyContent="center">
<Typography variant="h4">Loading your positions...</Typography>
</Box>
)}

{allLoans.length > 0 && (
{allLoans.length > 0 && allLoansLoaded && (
<>
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
Expand Down

0 comments on commit 4623227

Please sign in to comment.