add flexibility during bond purchase
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
This commit is contained in:
parent
a4b801efee
commit
421f2cef27
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ghost-dao-interface",
|
||||
"private": true,
|
||||
"version": "0.7.4",
|
||||
"version": "0.7.5",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@ -215,7 +215,7 @@ function App() {
|
||||
<Route path="/:network" element={<AvailableNetworkGuard allowedNetworks={chains.map(chain => chain.name.toLowerCase())} /> }>
|
||||
<Route path="dashboard" element={<TreasuryDashboard chainId={addressChainId ? addressChainId : chainId} />} />
|
||||
<Route path="bonds" element={<Bonds connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
|
||||
<Route path="bonds/:id" element={<BondModalContainer connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
|
||||
<Route path="bonds/:id" element={<BondModalContainer config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
|
||||
<Route path="stake" element={<StakeContainer connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
|
||||
<Route path="bridge" element={<Bridge config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
|
||||
<Route path="dex/:name" element={<Dex config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
|
||||
|
||||
@ -18,24 +18,24 @@ import BondSettingsModal from "./components/BondSettingsModal";
|
||||
import NotFound from "../NotFound/NotFound";
|
||||
|
||||
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
|
||||
import { NetworkId } from "../../constants";
|
||||
import { isNetworkLegacy } from "../../constants";
|
||||
import { formatCurrency } from "../../helpers";
|
||||
|
||||
import { useLocalStorage } from "../../hooks/localstorage";
|
||||
import { useLiveBonds } from "../../hooks/bonds";
|
||||
import { useFtsoPrice } from "../../hooks/prices";
|
||||
|
||||
const BondModalContainer = ({ chainId, address, connect }) => {
|
||||
const BondModalContainer = ({ chainId, address, config, connect }) => {
|
||||
const { id, network } = useParams();
|
||||
const { liveBonds } = useLiveBonds(chainId, network);
|
||||
const bond = liveBonds.find(bond => bond.id === Number(id));
|
||||
|
||||
if (!bond) return <NotFound />;
|
||||
|
||||
return <BondModal chainId={chainId} bond={bond} address={address} connect={connect} />;
|
||||
return <BondModal config={config} chainId={chainId} bond={bond} address={address} connect={connect} />;
|
||||
};
|
||||
|
||||
export const BondModal = ({ bond, chainId, address, connect }) => {
|
||||
export const BondModal = ({ bond, chainId, address, config, connect }) => {
|
||||
const navigate = useNavigate();
|
||||
const { network } = useParams();
|
||||
const { pathname } = useLocation();
|
||||
@ -81,6 +81,23 @@ export const BondModal = ({ bond, chainId, address, connect }) => {
|
||||
return () => window.removeEventListener("keydown", handleKeyDown);
|
||||
}, [network, navigate, isSettingsOpen]);
|
||||
|
||||
const chainSymbol = useMemo(() => {
|
||||
const chainSymbol = config?.getClient()?.chain?.nativeCurrency?.symbol;
|
||||
if (chainSymbol) return chainSymbol;
|
||||
return "WTF";
|
||||
}, [config]);
|
||||
|
||||
const preparedQuoteToken = useMemo(() => {
|
||||
if (isNetworkLegacy(chainId)) {
|
||||
return {
|
||||
address: bond.quoteToken.quoteTokenAddress,
|
||||
icons: bond.quoteToken.icons,
|
||||
name: bond.quoteToken.name,
|
||||
}
|
||||
}
|
||||
return { address: undefined, icons: [chainSymbol], name: chainSymbol };
|
||||
}, [bond, chainSymbol, chainId])
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<PageTitle
|
||||
@ -95,10 +112,10 @@ export const BondModal = ({ bond, chainId, address, connect }) => {
|
||||
</Box>
|
||||
</Link>
|
||||
|
||||
<TokenStack tokens={bond.quoteToken.icons} sx={{ fontSize: "27px" }} />
|
||||
<TokenStack tokens={preparedQuoteToken.icons} sx={{ fontSize: "27px" }} />
|
||||
<Box display="flex" flexDirection="column" ml={1} justifyContent="center" alignItems="center">
|
||||
<Typography variant="h4" fontWeight={500}>
|
||||
{bond.quoteToken.name}
|
||||
{preparedQuoteToken.name}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
@ -144,10 +161,12 @@ export const BondModal = ({ bond, chainId, address, connect }) => {
|
||||
<BondInputArea
|
||||
chainId={chainId}
|
||||
bond={bond}
|
||||
config={config}
|
||||
connect={connect}
|
||||
address={address}
|
||||
slippage={slippage}
|
||||
recipientAddress={recipientAddress}
|
||||
preparedQuoteToken={preparedQuoteToken}
|
||||
handleSettingsOpen={() => setSettingsOpen(true)}
|
||||
formatDecimals={formatDecimals}
|
||||
/>
|
||||
|
||||
@ -37,6 +37,9 @@ const BondConfirmModal = ({
|
||||
sender,
|
||||
handleSettingsOpen,
|
||||
isOpen,
|
||||
isNative,
|
||||
bondQuoteTokenName,
|
||||
bondQuoteTokenIcons,
|
||||
handleConfirmClose
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
@ -53,15 +56,16 @@ const BondConfirmModal = ({
|
||||
const maxPrice = bond.price.inBaseToken._value * bigIntSlippage / one;
|
||||
const referral = import.meta.env.VITE_APP_REFERRAL_ADDRESS;
|
||||
|
||||
await purchaseBond(
|
||||
await purchaseBond({
|
||||
chainId,
|
||||
bond.id,
|
||||
spendAmountValue._value.toBigInt(),
|
||||
bondId: bond.id,
|
||||
amount: spendAmountValue._value.toBigInt(),
|
||||
maxPrice,
|
||||
recipientAddress,
|
||||
user: recipientAddress,
|
||||
sender,
|
||||
referral
|
||||
);
|
||||
referral,
|
||||
isNative
|
||||
});
|
||||
|
||||
setIsPending(false);
|
||||
handleConfirmClose();
|
||||
@ -74,9 +78,9 @@ const BondConfirmModal = ({
|
||||
open={isOpen}
|
||||
headerContent={
|
||||
<Box display="flex" flexDirection="row">
|
||||
<TokenStack tokens={bond.quoteToken.icons} sx={{ fontSize: "27px" }} />
|
||||
<TokenStack tokens={bondQuoteTokenIcons} sx={{ fontSize: "27px" }} />
|
||||
<Typography variant="h4" sx={{ marginLeft: "6px" }}>
|
||||
{bond.quoteToken.name}
|
||||
{bondQuoteTokenName}
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
@ -91,7 +95,7 @@ const BondConfirmModal = ({
|
||||
metric={spendAmount}
|
||||
/>
|
||||
<Box display="flex" flexDirection="row" justifyContent="center">
|
||||
<Typography>{bond.quoteToken.name}</Typography>
|
||||
<Typography>{bondQuoteTokenName}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
<GhostStyledIcon sx={{ transform: "rotate(-90deg)" }} component={ArrowDropDownIcon} />
|
||||
|
||||
@ -30,6 +30,7 @@ const BondInputArea = ({
|
||||
formatDecimals,
|
||||
handleSettingsOpen,
|
||||
address,
|
||||
preparedQuoteToken,
|
||||
connect
|
||||
}) => {
|
||||
const isSemiSmallScreen = useMediaQuery("(max-width: 480px)");
|
||||
@ -37,7 +38,7 @@ const BondInputArea = ({
|
||||
const { pathname } = useLocation();
|
||||
|
||||
const { currentIndex } = useCurrentIndex(chainId);
|
||||
const { balance, refetch } = useBalance(chainId, bond.quoteToken.quoteTokenAddress, address);
|
||||
const { balance, refetch } = useBalance(chainId, preparedQuoteToken.address, address);
|
||||
|
||||
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
|
||||
const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
|
||||
@ -100,15 +101,14 @@ const BondInputArea = ({
|
||||
inputWidth={isVerySmallScreen ? "100px" : isSemiSmallScreen ? "180px" : "250px"}
|
||||
id="from"
|
||||
token={<TokenStack tokens={bond.quoteToken.icons} sx={{ fontSize: "21px" }} />}
|
||||
tokenName={bond.quoteToken.name}
|
||||
info={formatCurrency(balance, formatDecimals, bond.quoteToken.name)}
|
||||
endString="Max"
|
||||
tokenName={preparedQuoteToken.name}
|
||||
info={formatCurrency(balance, formatDecimals, preparedQuoteToken.name)}
|
||||
endString={preparedQuoteToken.address && "Max"}
|
||||
endStringOnClick={setMax}
|
||||
value={amount}
|
||||
onChange={event => setAmount(event.currentTarget.value)}
|
||||
inputProps={{ "data-testid": "fromInput" }}
|
||||
/>
|
||||
}
|
||||
/>}
|
||||
LowerSwapCard={
|
||||
<SwapCard
|
||||
maxWidth="476px"
|
||||
@ -134,6 +134,7 @@ const BondInputArea = ({
|
||||
connect={connect}
|
||||
width="100%"
|
||||
height="60px"
|
||||
isNative={preparedQuoteToken.address === undefined}
|
||||
isVertical
|
||||
message={
|
||||
<>
|
||||
@ -221,6 +222,9 @@ const BondInputArea = ({
|
||||
spendAmountValue={parsedAmount}
|
||||
spendAmount={formatNumber(parsedAmount, formatDecimals)}
|
||||
receiveAmount={formatNumber(amountInBaseToken, formatDecimals)}
|
||||
bondQuoteTokenName={preparedQuoteToken.name}
|
||||
bondQuoteTokenIcons={preparedQuoteToken.icons}
|
||||
isNative={preparedQuoteToken.address === undefined}
|
||||
handleSettingsOpen={handleSettingsOpen}
|
||||
isOpen={confirmOpen}
|
||||
sender={address}
|
||||
|
||||
@ -56,12 +56,12 @@ export const ClaimBonds = ({ chainId, address, secondsTo }) => {
|
||||
setIsWapmup(true);
|
||||
} else {
|
||||
setIsPending(true);
|
||||
await redeem(
|
||||
await redeem({
|
||||
chainId,
|
||||
address,
|
||||
isPayoutGhst,
|
||||
user: address,
|
||||
isGhst: isPayoutGhst,
|
||||
indexes
|
||||
);
|
||||
});
|
||||
await notesRefetch();
|
||||
setIsPending(false);
|
||||
}
|
||||
@ -99,136 +99,137 @@ export const ClaimBonds = ({ chainId, address, secondsTo }) => {
|
||||
? formatCurrency(totalClaimableBalance, 5, ghstSymbol)
|
||||
: formatCurrency(currentIndex.mul(totalClaimableBalance), 5, stnkSymbol)
|
||||
}
|
||||
|
||||
({formatCurrency(totalClaimableBalance * ghstPrice, 2)})
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<PrimaryButton
|
||||
disabled={isPending || totalClaimableBalance._value === 0n}
|
||||
fullWidth
|
||||
className=""
|
||||
onClick={() => onSubmit(notes.filter((note) => secondsTo > note.matured).map(note => note.id))}
|
||||
>
|
||||
Claim All
|
||||
</PrimaryButton>
|
||||
</Typography>
|
||||
<Typography variant="subtitle1" align="center">
|
||||
{formatCurrency(totalClaimableBalance * ghstPrice, 2)}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<PrimaryButton
|
||||
disabled={isPending || totalClaimableBalance._value === 0n}
|
||||
fullWidth
|
||||
className=""
|
||||
onClick={() => onSubmit(notes.filter((note) => secondsTo > note.matured).map(note => note.id))}
|
||||
>
|
||||
Claim All
|
||||
</PrimaryButton>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box mt="48px">
|
||||
{isSmallScreen ? (
|
||||
<>
|
||||
{notes.map((note, index) => (
|
||||
<Box key={index} mt="32px">
|
||||
<Box display="flex" alignItems="center">
|
||||
<TokenStack tokens={note.quoteToken.icons} />
|
||||
<Box ml="8px">
|
||||
<Typography>{note.quoteToken.name}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box display="flex" justifyContent="space-between" mt="16px">
|
||||
<Typography>Duration</Typography>
|
||||
<Typography>
|
||||
<BondVesting vesting={note.vesting} />
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Box display="flex" justifyContent="space-between" mt="8px">
|
||||
<Typography>Remaining</Typography>
|
||||
<Typography>
|
||||
<BondDuration msg="Matured" secondsTo={secondsTo} duration={note.matured} />
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Box display="flex" justifyContent="space-between" mt="8px">
|
||||
<Typography>Payout</Typography>
|
||||
<Box display="flex" flexDirection="column" alignItems="flex-end">
|
||||
<Typography>
|
||||
{isPayoutGhst
|
||||
? formatCurrency(note.payout, 5, ghstSymbol)
|
||||
: formatCurrency(currentIndex.mul(note.payout), 5, stnkSymbol)
|
||||
}
|
||||
</Typography>
|
||||
<Typography>{formatCurrency(note.payout * ghstPrice, 2)}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box mt="16px">
|
||||
<TertiaryButton
|
||||
fullWidth
|
||||
disabled={isPending || secondsTo < note.matured}
|
||||
onClick={() => onSubmit([note.id])}
|
||||
>
|
||||
Claim
|
||||
</TertiaryButton>
|
||||
<Box mt="48px">
|
||||
{isSmallScreen ? (
|
||||
<>
|
||||
{notes.map((note, index) => (
|
||||
<Box key={index} mt="32px">
|
||||
<Box display="flex" alignItems="center">
|
||||
<TokenStack tokens={note.quoteToken.icons} />
|
||||
<Box ml="8px">
|
||||
<Typography>{note.quoteToken.name}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<TableContainer>
|
||||
<Table aria-label="Available bonds" style={{ tableLayout: "fixed" }}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell style={{ width: "180px", padding: "8px 0" }}>Bond</TableCell>
|
||||
<TableCell style={{ padding: "8px 0" }}>Duration</TableCell>
|
||||
<TableCell style={{ padding: "8px 0" }}>Remaining</TableCell>
|
||||
<TableCell style={{ padding: "8px 0" }}>Payout</TableCell>
|
||||
|
||||
<Box display="flex" justifyContent="space-between" mt="16px">
|
||||
<Typography>Duration</Typography>
|
||||
<Typography>
|
||||
<BondVesting vesting={note.vesting} />
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Box display="flex" justifyContent="space-between" mt="8px">
|
||||
<Typography>Remaining</Typography>
|
||||
<Typography>
|
||||
<BondDuration msg="Matured" secondsTo={secondsTo} duration={note.matured} />
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Box display="flex" justifyContent="space-between" mt="8px">
|
||||
<Typography>Payout</Typography>
|
||||
<Box display="flex" flexDirection="column" alignItems="flex-end">
|
||||
<Typography>
|
||||
{isPayoutGhst
|
||||
? formatCurrency(note.payout, 5, ghstSymbol)
|
||||
: formatCurrency(currentIndex.mul(note.payout), 5, stnkSymbol)
|
||||
}
|
||||
</Typography>
|
||||
<Typography>{formatCurrency(note.payout * ghstPrice, 2)}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box mt="16px">
|
||||
<TertiaryButton
|
||||
fullWidth
|
||||
disabled={isPending || secondsTo < note.matured}
|
||||
onClick={() => onSubmit([note.id])}
|
||||
>
|
||||
Claim
|
||||
</TertiaryButton>
|
||||
</Box>
|
||||
</Box>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<TableContainer>
|
||||
<Table aria-label="Available bonds" style={{ tableLayout: "fixed" }}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell style={{ width: "180px", padding: "8px 0" }}>Bond</TableCell>
|
||||
<TableCell style={{ padding: "8px 0" }}>Duration</TableCell>
|
||||
<TableCell style={{ padding: "8px 0" }}>Remaining</TableCell>
|
||||
<TableCell style={{ padding: "8px 0" }}>Payout</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{notes.map((note, index) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell style={{ padding: "8px 0" }}>
|
||||
<Box display="flex" alignItems="center">
|
||||
<TokenStack tokens={note.quoteToken.icons} />
|
||||
<Box display="flex" flexDirection="column" ml="16px">
|
||||
<Typography>{note.quoteToken.name}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</TableCell>
|
||||
|
||||
<TableCell style={{ padding: "8px 0" }}>
|
||||
<Typography>
|
||||
<BondVesting vesting={note.vesting} />
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
<TableCell style={{ padding: "8px 0" }}>
|
||||
<Typography>
|
||||
<BondDuration msg="Matured" secondsTo={secondsTo} duration={note.matured} />
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
<TableCell style={{ padding: "8px 0" }}>
|
||||
<Box display="flex" flexDirection="column" alignItems="flex-start">
|
||||
<Typography>
|
||||
{isPayoutGhst
|
||||
? formatCurrency(note.payout, 5, ghstSymbol)
|
||||
: formatCurrency(currentIndex.mul(note.payout), 5, stnkSymbol)
|
||||
}
|
||||
</Typography>
|
||||
<Typography variant="body2">{formatCurrency(note.payout * ghstPrice, 2)}</Typography>
|
||||
</Box>
|
||||
</TableCell>
|
||||
|
||||
<TableCell style={{ padding: "8px 0" }}>
|
||||
<TertiaryButton
|
||||
fullWidth
|
||||
disabled={isPending || secondsTo < note.matured}
|
||||
onClick={() => onSubmit([note.id])}
|
||||
>
|
||||
Claim
|
||||
</TertiaryButton>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{notes.map((note, index) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell style={{ padding: "8px 0" }}>
|
||||
<Box display="flex" alignItems="center">
|
||||
<TokenStack tokens={note.quoteToken.icons} />
|
||||
<Box display="flex" flexDirection="column" ml="16px">
|
||||
<Typography>{note.quoteToken.name}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</TableCell>
|
||||
|
||||
<TableCell style={{ padding: "8px 0" }}>
|
||||
<Typography>
|
||||
<BondVesting vesting={note.vesting} />
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
<TableCell style={{ padding: "8px 0" }}>
|
||||
<Typography>
|
||||
<BondDuration msg="Matured" secondsTo={secondsTo} duration={note.matured} />
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
<TableCell style={{ padding: "8px 0" }}>
|
||||
<Box display="flex" flexDirection="column" alignItems="flex-start">
|
||||
<Typography>
|
||||
{isPayoutGhst
|
||||
? formatCurrency(note.payout, 5, ghstSymbol)
|
||||
: formatCurrency(currentIndex.mul(note.payout), 5, stnkSymbol)
|
||||
}
|
||||
</Typography>
|
||||
<Typography variant="body2">{formatCurrency(note.payout * ghstPrice, 2)}</Typography>
|
||||
</Box>
|
||||
</TableCell>
|
||||
|
||||
<TableCell style={{ padding: "8px 0" }}>
|
||||
<TertiaryButton
|
||||
fullWidth
|
||||
disabled={isPending || secondsTo < note.matured}
|
||||
onClick={() => onSubmit([note.id])}
|
||||
>
|
||||
Claim
|
||||
</TertiaryButton>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
)}
|
||||
</Box>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
)}
|
||||
</Box>
|
||||
</Paper>
|
||||
</>
|
||||
);
|
||||
|
||||
@ -266,7 +266,7 @@ export const useNotes = (chainId, address) => {
|
||||
return { notes, refetch };
|
||||
}
|
||||
|
||||
export const purchaseBond = async (chainId, bondId, amount, maxPrice, user, sender, referral) => {
|
||||
export const purchaseBond = async ({ chainId, bondId, amount, maxPrice, user, sender, referral, isNative }) => {
|
||||
const args = [
|
||||
bondId,
|
||||
amount,
|
||||
@ -284,11 +284,12 @@ export const purchaseBond = async (chainId, bondId, amount, maxPrice, user, send
|
||||
"deposit",
|
||||
args,
|
||||
sender,
|
||||
messages
|
||||
messages,
|
||||
isNative ? amount : undefined
|
||||
);
|
||||
}
|
||||
|
||||
export const redeem = async (chainId, user, isGhst, indexes) => {
|
||||
export const redeem = async ({ chainId, user, isGhst, indexes }) => {
|
||||
const args = [
|
||||
user,
|
||||
isGhst,
|
||||
@ -313,7 +314,8 @@ const executeOnChainTransaction = async (
|
||||
functionName,
|
||||
args,
|
||||
account,
|
||||
messages
|
||||
messages,
|
||||
value
|
||||
) => {
|
||||
try {
|
||||
const { request } = await simulateContract(config, {
|
||||
@ -324,6 +326,7 @@ const executeOnChainTransaction = async (
|
||||
account,
|
||||
chainId,
|
||||
type: isNetworkLegacyType(chainId) ? 'legacy' : 'eip1559',
|
||||
value: value,
|
||||
});
|
||||
|
||||
const txHash = await writeContract(config, request);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user