230 lines
11 KiB
JavaScript
230 lines
11 KiB
JavaScript
import { CheckBoxOutlineBlank, CheckBoxOutlined } from "@mui/icons-material";
|
|
import { Box, Checkbox, FormControlLabel } from "@mui/material";
|
|
import { useState, useMemo } from "react";
|
|
import { useLocation } from "react-router-dom";
|
|
|
|
import { BOND_DEPOSITORY_ADDRESSES } from "../../../constants/addresses";
|
|
import { shorten, formatNumber, formatCurrency } from "../../../helpers";
|
|
import { DecimalBigNumber } from "../../../helpers/DecimalBigNumber";
|
|
|
|
import BondDiscount from "./BondDiscount";
|
|
import BondVesting from "./BondVesting";
|
|
import BondConfirmModal from "./BondConfirmModal";
|
|
|
|
import { TokenAllowanceGuard } from "../../../components/TokenAllowanceGuard/TokenAllowanceGuard";
|
|
import { PrimaryButton } from "../../../components/Button";
|
|
import SwapCard from "../../../components/Swap/SwapCard";
|
|
import SwapCollection from "../../../components/Swap/SwapCollection";
|
|
import TokenStack from "../../../components/TokenStack/TokenStack";
|
|
import DataRow from "../../../components/DataRow/DataRow";
|
|
import Paper from "../../../components/Paper/Paper";
|
|
|
|
import { useCurrentIndex } from "../../../hooks/staking";
|
|
import { useBalance } from "../../../hooks/tokens";
|
|
|
|
const BondInputArea = ({
|
|
bond,
|
|
chainId,
|
|
slippage,
|
|
recipientAddress,
|
|
formatDecimals,
|
|
handleSettingsOpen,
|
|
address,
|
|
connect
|
|
}) => {
|
|
const { pathname } = useLocation();
|
|
|
|
const { currentIndex } = useCurrentIndex(chainId);
|
|
const { balance } = useBalance(chainId, bond.quoteToken.quoteTokenAddress, address);
|
|
|
|
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
|
|
const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
|
|
|
|
const [amount, setAmount] = useState("");
|
|
const [checked, setChecked] = useState(false);
|
|
const [confirmOpen, setConfirmOpen] = useState(false);
|
|
|
|
const parsedAmount = useMemo(() => {
|
|
return new DecimalBigNumber(amount, bond.quoteToken.decimals);
|
|
}, [bond, amount])
|
|
|
|
const amountInBaseToken = useMemo(() => {
|
|
if (bond.price.inBaseToken._value !== 0n) return parsedAmount.div(bond.price.inBaseToken);
|
|
return new DecimalBigNumber(0n, 0);
|
|
}, [parsedAmount]);
|
|
|
|
const showDisclaimer = useMemo(() => {
|
|
return new DecimalBigNumber("0").gt(bond.discount);
|
|
}, [bond]);
|
|
|
|
const handleConfirmClose = () => {
|
|
setAmount("");
|
|
setConfirmOpen(false);
|
|
}
|
|
|
|
const setMax = () => {
|
|
if (!balance) return;
|
|
|
|
if (bond.capacity.inQuoteToken.lt(bond.maxPayout.inQuoteToken)) {
|
|
return setAmount(
|
|
bond.capacity.inQuoteToken.lt(balance)
|
|
? bond.capacity.inQuoteToken.toString() // Capacity is the smallest
|
|
: balance.toString(),
|
|
);
|
|
}
|
|
|
|
setAmount(
|
|
bond.maxPayout.inQuoteToken.lt(balance)
|
|
? bond.maxPayout.inQuoteToken.toString() // Payout is the smallest
|
|
: balance.toString(),
|
|
);
|
|
};
|
|
|
|
const baseTokenString = (bond.maxPayout.inBaseToken.lt(bond.capacity.inBaseToken)
|
|
? bond.maxPayout.inBaseToken
|
|
: bond.capacity.inBaseToken
|
|
);
|
|
|
|
return (
|
|
<Box minHeight="calc(100vh - 210px)" display="flex" flexDirection="column" justifyContent="center">
|
|
<Box display="flex" flexDirection="row" width="100%" justifyContent="center" mt="10px">
|
|
<Box display="flex" flexDirection="column" width="100%" maxWidth="476px">
|
|
<Box mb="21px">
|
|
<SwapCollection
|
|
UpperSwapCard={
|
|
<SwapCard
|
|
maxWidth="476px"
|
|
inputWidth="280px"
|
|
id="from"
|
|
token={<TokenStack tokens={bond.quoteToken.icons} sx={{ fontSize: "21px" }} />}
|
|
tokenName={bond.quoteToken.name}
|
|
info={formatCurrency(balance, formatDecimals, bond.quoteToken.name)}
|
|
endString="Max"
|
|
endStringOnClick={setMax}
|
|
value={amount}
|
|
onChange={event => setAmount(event.currentTarget.value)}
|
|
inputProps={{ "data-testid": "fromInput" }}
|
|
/>
|
|
}
|
|
LowerSwapCard={
|
|
<SwapCard
|
|
maxWidth="476px"
|
|
inputWidth="280px"
|
|
id="to"
|
|
token={<TokenStack tokens={bond.baseToken.icons} sx={{ fontSize: "21px" }} />}
|
|
tokenName={bond.baseToken.name}
|
|
value={amountInBaseToken.toString({ decimals: 9 })}
|
|
inputProps={{ "data-testid": "toInput" }}
|
|
/>
|
|
}
|
|
/>
|
|
</Box>
|
|
|
|
<TokenAllowanceGuard
|
|
spendAmount={parsedAmount}
|
|
tokenName={bond.quoteToken.quoteTokenAddress}
|
|
owner={address}
|
|
spender={BOND_DEPOSITORY_ADDRESSES[chainId]}
|
|
decimals={parsedAmount._decimals}
|
|
approvalText={`Approve ${bond.quoteToken.name} to Bond`}
|
|
approvalPendingText={"Approving..."}
|
|
connect={connect}
|
|
width="100%"
|
|
height="60px"
|
|
isVertical
|
|
message={
|
|
<>
|
|
First time bonding <b>{bond.quoteToken.name}</b>? <br /> Please approve ghostDAO to use your{" "}
|
|
<b>{bond.quoteToken.name}</b> for bonding.
|
|
</>
|
|
}
|
|
>
|
|
{showDisclaimer && (
|
|
<FormControlLabel
|
|
control={
|
|
<Checkbox
|
|
checked={checked}
|
|
onChange={event => setChecked(event.target.checked)}
|
|
icon={<CheckBoxOutlineBlank viewBox="0 0 24 24" />}
|
|
checkedIcon={<CheckBoxOutlined viewBox="0 0 24 24" />}
|
|
/>
|
|
}
|
|
label="I understand that I'm buying a negative discount bond"
|
|
/>
|
|
)}
|
|
<PrimaryButton
|
|
fullWidth
|
|
disabled={bond.isSoldOut || (showDisclaimer && !checked)}
|
|
onClick={() => setConfirmOpen(true)}
|
|
>
|
|
Bond
|
|
</PrimaryButton>
|
|
</TokenAllowanceGuard>
|
|
|
|
<Paper style={{ marginBottom: "7px", marginTop: "21px" }} fullWidth enableBackground>
|
|
<Box mt="24px">
|
|
<DataRow
|
|
title={"You Will Get"}
|
|
balance={
|
|
<span>
|
|
{formatCurrency(amountInBaseToken, formatDecimals, ftsoSymbol)}
|
|
{" "}
|
|
{!!currentIndex && (
|
|
<span>
|
|
(≈{formatCurrency(amountInBaseToken.div(currentIndex), formatDecimals, ghstSymbol)})
|
|
</span>
|
|
)}
|
|
</span>
|
|
}
|
|
tooltip={`The total amount of payout asset you will receive from this bond purchase`}
|
|
/>
|
|
|
|
<DataRow
|
|
title="Max You Can Buy"
|
|
tooltip={`The maximum quantity of payout token offered via bonds at this moment in time`}
|
|
balance={
|
|
<span>
|
|
{bond.baseToken.tokenAddress.toUpperCase() === bond.quoteToken.quoteTokenAddress.toUpperCase()
|
|
? `${formatCurrency(baseTokenString, formatDecimals, ftsoSymbol)}`
|
|
: `${formatCurrency(baseTokenString, formatDecimals, ftsoSymbol)} (≈${formatCurrency(baseTokenString.div(currentIndex), formatDecimals, ghstSymbol)})`}
|
|
</span>
|
|
}
|
|
/>
|
|
|
|
<DataRow
|
|
title="Discount"
|
|
balance={<BondDiscount discount={bond.discount} textOnly />}
|
|
tooltip={`The bond discount is the percentage difference between ${ftsoSymbol} market value and the bond's price`}
|
|
/>
|
|
|
|
<DataRow
|
|
title={`Vesting Term`}
|
|
balance={<BondVesting vesting={bond.vesting} />}
|
|
tooltip={"The duration of the Bond whereby the bond can be claimed in its entirety"}
|
|
/>
|
|
|
|
{recipientAddress !== address && (
|
|
<DataRow title={`Recipient`} balance={shorten(recipientAddress)} />
|
|
)}
|
|
</Box>
|
|
</Paper>
|
|
</Box>
|
|
</Box>
|
|
<BondConfirmModal
|
|
chainId={chainId}
|
|
bond={bond}
|
|
slippage={slippage}
|
|
recipientAddress={recipientAddress}
|
|
spendAmountValue={parsedAmount}
|
|
spendAmount={formatNumber(parsedAmount, formatDecimals)}
|
|
receiveAmount={formatNumber(amountInBaseToken, formatDecimals)}
|
|
handleSettingsOpen={handleSettingsOpen}
|
|
isOpen={confirmOpen}
|
|
handleConfirmClose={() => handleConfirmClose()}
|
|
/>
|
|
</Box>
|
|
);
|
|
};
|
|
|
|
export default BondInputArea;
|