177 lines
6.8 KiB
JavaScript
177 lines
6.8 KiB
JavaScript
import { useState, useEffect } from "react";
|
||
import { Box, Typography, Checkbox, FormControlLabel } from "@mui/material";
|
||
import { CheckBoxOutlineBlank, CheckBoxOutlined } from "@mui/icons-material";
|
||
import { styled, useTheme } from "@mui/material/styles";
|
||
import SettingsIcon from '@mui/icons-material/Settings';
|
||
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
|
||
import toast from "react-hot-toast";
|
||
|
||
import GhostStyledIcon from "../../../components/Icon/GhostIcon";
|
||
import Metric from "../../../components/Metric/Metric";
|
||
import Modal from "../../../components/Modal/Modal";
|
||
import TokenStack from "../../../components/TokenStack/TokenStack";
|
||
import DataRow from "../../../components/DataRow/DataRow";
|
||
import { PrimaryButton, SecondaryButton } from "../../../components/Button";
|
||
|
||
import BondDiscount from "./BondDiscount";
|
||
import BondVesting from "./BondVesting";
|
||
import BondSlippage from "./BondSlippage";
|
||
|
||
import { purchaseBond } from "../../../hooks/bonds";
|
||
import { useWarmupLength } from "../../../hooks/staking";
|
||
|
||
const StyledBox = styled(Box, {
|
||
shouldForwardProp: prop => prop !== "template",
|
||
})(({ theme }) => {
|
||
return {
|
||
root: {},
|
||
};
|
||
});
|
||
|
||
const BondConfirmModal = ({
|
||
chainId,
|
||
bond,
|
||
slippage,
|
||
recipientAddress,
|
||
spendAmountValue,
|
||
spendAmount,
|
||
receiveAmount,
|
||
sender,
|
||
handleSettingsOpen,
|
||
isOpen,
|
||
isNative,
|
||
bondQuoteTokenName,
|
||
bondQuoteTokenIcons,
|
||
handleConfirmClose
|
||
}) => {
|
||
const theme = useTheme();
|
||
|
||
const { warmupLength, warmupExists: needsWarmup } = useWarmupLength(chainId);
|
||
const [acknowledgedWarmup, setAcknowledgedWarmup] = useState(false);
|
||
const [isPending, setIsPending] = useState(false);
|
||
|
||
useEffect(() => setAcknowledgedWarmup(acknowledgedWarmup || !needsWarmup), [acknowledgedWarmup, needsWarmup]);
|
||
|
||
const AcknowledgeWarmupCheckbox = () => {
|
||
if (!needsWarmup) return <></>;
|
||
return (
|
||
<Box sx={{ marginBottom: "1rem" }}>
|
||
<FormControlLabel
|
||
control={
|
||
<Checkbox
|
||
data-testid="acknowledge-bond-warm-up"
|
||
checked={acknowledgedWarmup}
|
||
onChange={event => setAcknowledgedWarmup(event.target.checked)}
|
||
icon={<CheckBoxOutlineBlank viewBox="0 0 24 24" />}
|
||
checkedIcon={<CheckBoxOutlined viewBox="0 0 24 24" />}
|
||
/>
|
||
}
|
||
label={
|
||
<Typography variant="body2">
|
||
{`I understand the ${bondQuoteTokenName} I’m bonding will only be available to claim ${warmupLength.toString()} epochs after my transaction is confirmed, and the warm-up extends with each bond purchase`}
|
||
</Typography>
|
||
}
|
||
/>
|
||
</Box>
|
||
);
|
||
};
|
||
|
||
const NeedsWarmupDetails = () => {
|
||
if (!needsWarmup) return <></>;
|
||
return (
|
||
<>
|
||
<AcknowledgeWarmupCheckbox />
|
||
<SecondaryButton
|
||
fullWidth
|
||
href="https://ghostchain.io/ghostdao_litepaper"
|
||
>
|
||
Why is there a warm-up?
|
||
</SecondaryButton>
|
||
</>
|
||
);
|
||
};
|
||
|
||
const handleConfirmCloseMaster = () => {
|
||
setAcknowledgedWarmup(false);
|
||
handleConfirmClose()
|
||
}
|
||
|
||
const onSubmit = async () => {
|
||
setIsPending(true);
|
||
|
||
const shares = 100000;
|
||
const one = BigInt(shares * 100);
|
||
const floatSlippage = slippage === "" ? 0 : parseFloat(slippage);
|
||
const bigIntSlippage = one + BigInt(Math.round(floatSlippage * shares));
|
||
|
||
const maxPrice = bond.price.inBaseToken._value * bigIntSlippage / one;
|
||
const referral = import.meta.env.VITE_APP_REFERRAL_ADDRESS;
|
||
|
||
await purchaseBond({
|
||
chainId,
|
||
bondId: bond.id,
|
||
amount: spendAmountValue._value.toBigInt(),
|
||
maxPrice,
|
||
user: recipientAddress,
|
||
sender,
|
||
referral,
|
||
isNative
|
||
});
|
||
|
||
setIsPending(false);
|
||
handleConfirmCloseMaster();
|
||
}
|
||
|
||
return (
|
||
<Modal
|
||
maxWidth="476px"
|
||
minHeight="200px"
|
||
open={isOpen}
|
||
headerContent={
|
||
<Box display="flex" flexDirection="row">
|
||
<TokenStack tokens={bondQuoteTokenIcons} sx={{ fontSize: "27px" }} />
|
||
<Typography variant="h4" sx={{ marginLeft: "6px" }}>
|
||
{bondQuoteTokenName}
|
||
</Typography>
|
||
</Box>
|
||
}
|
||
onClose={!isPending && handleConfirmCloseMaster}
|
||
topLeft={<GhostStyledIcon viewBox="0 0 23 23" component={SettingsIcon} style={{ cursor: "pointer" }} onClick={handleSettingsOpen} />}
|
||
>
|
||
<>
|
||
<Box display="flex" flexDirection="row" justifyContent="space-between" alignItems="center">
|
||
<Box display="flex" flexDirection="column">
|
||
<Metric
|
||
label="Assets to Bond"
|
||
metric={spendAmount}
|
||
/>
|
||
<Box display="flex" flexDirection="row" justifyContent="center">
|
||
<Typography>{bondQuoteTokenName}</Typography>
|
||
</Box>
|
||
</Box>
|
||
<GhostStyledIcon sx={{ transform: "rotate(-90deg)" }} component={ArrowDropDownIcon} />
|
||
<Box display="flex" flexDirection="column">
|
||
<Metric label="Assets to Receive" metric={receiveAmount} />
|
||
<Box display="flex" flexDirection="row" justifyContent="center">
|
||
<Typography>{bond.baseToken.name}</Typography>
|
||
</Box>
|
||
</Box>
|
||
</Box>
|
||
<Box mt="21px" mb="21px" borderTop={`1px solid ${theme.colors.gray[500]}`}></Box>
|
||
<DataRow title="ROI" balance={<BondDiscount discount={bond.discount} textOnly />} />
|
||
<DataRow title="Bond Slippage" balance={<BondSlippage slippage={slippage} textOnly />} />
|
||
<DataRow title="Vesting Term" balance={<BondVesting vesting={bond.vesting} />} />
|
||
{!acknowledgedWarmup && <Box>
|
||
<Box mt="21px" mb="21px" borderTop={`1px solid ${theme.colors.gray[500]}`}></Box>
|
||
<NeedsWarmupDetails />
|
||
</Box>}
|
||
{acknowledgedWarmup && <PrimaryButton fullWidth onClick={onSubmit} disabled={isPending} loading={isPending}>
|
||
{isPending ? "Bonding..." : "Confirm Bond Purchase"}
|
||
</PrimaryButton>}
|
||
</>
|
||
</Modal>
|
||
);
|
||
};
|
||
|
||
export default BondConfirmModal;
|