diff --git a/package.json b/package.json
index 1fdba16..a7093be 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "ghost-dao-interface",
"private": true,
- "version": "0.7.23",
+ "version": "0.7.24",
"type": "module",
"scripts": {
"dev": "vite",
diff --git a/src/App.jsx b/src/App.jsx
index 442b940..84e1bd9 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -15,11 +15,13 @@ import {
useSwitchChain,
injected
} from "wagmi";
+import { watchChainId } from '@wagmi/core'
import Messages from "./components/Messages/Messages";
import NavDrawer from "./components/Sidebar/NavDrawer";
import Sidebar from "./components/Sidebar/Sidebar";
import TopBar from "./components/TopBar/TopBar";
+import BreakoutModal from "./containers/Breakout/BreakoutModal";
import { shouldTriggerSafetyCheck } from "./helpers";
import { isNetworkAvailable } from "./constants";
@@ -150,15 +152,15 @@ function App() {
useEffect(() => {
if (isConnected && chainId !== addressChainId) {
- const toastId = toast.loading("You are connected to wrong network. Use one of the deployed networks please.", {
- position: 'bottom-right'
- });
- setWrongNetworkToastId(toastId);
- } else {
- if (wrongNetworkToastId) {
- toast.dismiss(wrongNetworkToastId);
- setWrongNetworkToastId(null);
+ if (wrongNetworkToastId === null) {
+ const toastId = toast.loading("You are connected to wrong network. Use one of the deployed networks please.", {
+ position: 'bottom-right'
+ });
+ setWrongNetworkToastId(toastId);
}
+ } else {
+ toast.dismiss(wrongNetworkToastId);
+ setWrongNetworkToastId(null);
}
}, [chainId, addressChainId, isConnected, wrongNetworkToastId])
@@ -209,6 +211,7 @@ function App() {
}>
+
} />
{chainExists &&
diff --git a/src/components/Token/Token.jsx b/src/components/Token/Token.jsx
index 3f95823..073bd67 100644
--- a/src/components/Token/Token.jsx
+++ b/src/components/Token/Token.jsx
@@ -86,8 +86,8 @@ const Token = ({ chainTokenName, name, viewBox = "0 0 260 260", fontSize = "larg
position: "absolute",
marginLeft: "70%",
marginTop: "45%",
- width: "65%",
- height: "65%",
+ width: "45%",
+ height: "45%",
border: "1px solid #fff",
borderRadius: "100%"
}}
diff --git a/src/components/TopBar/Wallet/Token.tsx b/src/components/TopBar/Wallet/Token.tsx
index 802eb56..ccc85d9 100644
--- a/src/components/TopBar/Wallet/Token.tsx
+++ b/src/components/TopBar/Wallet/Token.tsx
@@ -205,7 +205,10 @@ export const useWallet = (chainId, userAddress) => {
const config = useConfig();
- const nativeSymbol = config?.getClient()?.chain?.nativeCurrency?.symbol;
+ const nativeSymbol = useMemo(() => {
+ return config?.getClient()?.chain?.nativeCurrency?.symbol;
+ }, [config]);
+
const { symbol: reserveSymbol } = useTokenSymbol(chainId, "RESERVE");
const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
diff --git a/src/containers/Bond/components/ClaimBonds.jsx b/src/containers/Bond/components/ClaimBonds.jsx
index bf8b4cb..0e3eeb3 100644
--- a/src/containers/Bond/components/ClaimBonds.jsx
+++ b/src/containers/Bond/components/ClaimBonds.jsx
@@ -13,14 +13,16 @@ import { PrimaryButton, TertiaryButton } from "../../../components/Button";
import { useScreenSize } from "../../../hooks/useScreenSize";
import { BOND_DEPOSITORY_ADDRESSES } from "../../../constants/addresses";
+import { isNetworkLegacy } from "../../../constants";
import { DecimalBigNumber } from "../../../helpers/DecimalBigNumber";
import { formatCurrency } from "../../../helpers";
import { useCurrentIndex, useEpoch, useWarmupLength, useWarmupInfo } from "../../../hooks/staking";
-import { useNotes, redeem } from "../../../hooks/bonds";
+import { useNotes, redeem, forceRedeem } from "../../../hooks/bonds";
import { useTokenSymbol } from "../../../hooks/tokens";
import { useGhstPrice } from "../../../hooks/prices";
+import { useBreakoutModal } from "../../../hooks/breakoutModal";
export const ClaimBonds = ({ chainId, address, secondsTo }) => {
const isSmallScreen = useScreenSize("md");
@@ -30,6 +32,7 @@ export const ClaimBonds = ({ chainId, address, secondsTo }) => {
const [isPayoutGhst, _] = useState(true);
const ghstPrice = useGhstPrice(chainId);
+ const { breakoutFromBonding } = useBreakoutModal();
const { epoch } = useEpoch(chainId);
const { warmupExists } = useWarmupLength(chainId);
const { warmupInfo } = useWarmupInfo(chainId, BOND_DEPOSITORY_ADDRESSES[chainId]);
@@ -51,20 +54,35 @@ export const ClaimBonds = ({ chainId, address, secondsTo }) => {
);
const onSubmit = async (indexes) => {
- const isFundsInWarmup = warmupInfo.deposit._value > 0n;
- if (warmupExists && isFundsInWarmup && !isPreClaimConfirmed) {
- setIsWapmup(true);
- } else {
- setIsPending(true);
- await redeem({
- chainId,
- user: address,
- isGhst: isPayoutGhst,
- indexes
- });
+ setIsPending(true);
+
+ const defaultFunction = async () => {
+ await redeem({ chainId, user: address, isGhst: isPayoutGhst, indexes });
await notesRefetch();
- setIsPending(false);
+ };
+
+ if (isNetworkLegacy(chainId)) {
+ await defaultFunction();
+ // const isFundsInWarmup = warmupInfo.deposit._value > 0n;
+ // if (warmupExists && isFundsInWarmup && !isPreClaimConfirmed) {
+ // setIsWapmup(true);
+ // } else {
+ // await defaultFunction();
+ // }
+ } else {
+ const warmupLeft = warmupInfo.expiry - epoch.number;
+ const amount = notes
+ .filter(note => indexes.includes(note.id))
+ .reduce((sum, note) => sum.add(note.payout), new DecimalBigNumber(0, 0));
+
+ const toExecute = (receiver) => {
+ forceRedeem({ chainId, user: address, receiver, indexes });
+ notesRefetch();
+ }
+
+ breakoutFromBonding({ defaultFunction, toExecute, amount, warmupLeft })
}
+ setIsPending(false);
}
return (
diff --git a/src/containers/Breakout/BreakoutModal.jsx b/src/containers/Breakout/BreakoutModal.jsx
new file mode 100644
index 0000000..dc28c64
--- /dev/null
+++ b/src/containers/Breakout/BreakoutModal.jsx
@@ -0,0 +1,475 @@
+import { useMemo, useState, useCallback, useEffect } from "react";
+import { Box, Typography, Link, Checkbox, FormControlLabel, useTheme } from "@mui/material";
+import { useNavigate } from 'react-router-dom';
+import { getBlockNumber } from "@wagmi/core";
+import { useConfig } from "wagmi";
+import { ss58Decode } from "@polkadot-labs/hdkd-helpers";
+import { toHex } from "@polkadot-api/utils";
+import CheckCircleIcon from '@mui/icons-material/CheckCircle';
+import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
+import { CheckBoxOutlineBlank, CheckBoxOutlined } from "@mui/icons-material";
+
+import Metric from "../../components/Metric/Metric";
+import Modal from "../../components/Modal/Modal";
+import SwapCard from "../../components/Swap/SwapCard";
+import Token from "../../components/Token/Token";
+import GhostStyledIcon from "../../components/Icon/GhostIcon";
+import { PrimaryButton, SecondaryButton } from "../../components/Button";
+import { GATEKEEPER_ADDRESSES, EMPTY_ADDRESS } from "../../constants/addresses";
+
+import { useLocalStorage } from "../../hooks/localstorage";
+import { useBreakoutModal } from "../../hooks/breakoutModal";
+import { useTokenSymbol, useCirculatingSupply } from "../../hooks/tokens";
+import { useEpoch, useGatekeeperApy, useGatekeeperAddress } from "../../hooks/staking";
+import { useEvmNetwork, useCurrentIndex } from "../../hooks/ghost";
+import { formatNumber, shorten } from "../../helpers";
+import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
+
+const BreakoutModal = ({ chainId, address }) => {
+ const [step, setStep] = useState(0);
+ const [receiver, setReceiver] = useState("");
+
+ const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
+ const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
+
+ const evmNetwork = useEvmNetwork({ evmChainId: chainId });
+
+ const {
+ isOpened,
+ closeModal: closeModalInner,
+ isStakingOpened,
+ isClaimBondOpened,
+ warmupPeriod,
+ setActiveTxIndex,
+ defaultFunction,
+ executableFunction,
+ estimatedAmount
+ } = useBreakoutModal();
+
+ const incomingFee = useMemo(() => {
+ return new DecimalBigNumber(
+ evmNetwork ? evmNetwork.incoming_fee : 100000000,
+ 7
+ );
+ }, [evmNetwork]);
+
+ const closeModal = () => {
+ setActiveTxIndex(-1);
+ closeModalPure();
+ }
+
+ const closeModalPure = () => {
+ setStep(0);
+ setReceiver("");
+ closeModalInner();
+ }
+
+ const header = useMemo(() => {
+ if (isStakingOpened && warmupPeriod <= 0) return "Stake Warmed-up"
+ if (isClaimBondOpened && warmupPeriod <= 0) return "Bond Warmed-up"
+ if (isStakingOpened && warmupPeriod > 0) return "Stake in Warmup"
+ if (isClaimBondOpened && warmupPeriod > 0) return "Bond in Warmup"
+ }, [isStakingOpened, isClaimBondOpened, warmupPeriod]);
+
+ const bridgeNumbers = useMemo(() => {
+ const connectedNetworks = Object.keys(GATEKEEPER_ADDRESSES).length;
+ const number = 1 + connectedNetworks * 3;
+ return `(${number}, ${number})`;
+ }, [chainId]);
+
+ return (
+
+ {step === 0 ? header : step === 1 ? `Start ${bridgeNumbers} ${"Stake\u00B2"}` : "Bridge Confirmation"}
+
+ }
+ open={isOpened}
+ onClose={closeModal}
+ maxWidth="380px"
+ minHeight="200px"
+ >
+
+ {step === 0
+ ? setStep(1)}
+ closeModal={closeModal}
+ />
+ : step === 1
+ ? setStep(2)}
+ />
+ :
+ }
+
+
+ )
+}
+
+const BridgeView = ({
+ chainId,
+ receiver,
+ setReceiver,
+ bridgeNumbers,
+ ghstSymbol,
+ estimatedAmount,
+ goNext,
+ incomingFee
+}) => {
+ const theme = useTheme();
+ const [convertedReceiver, setConvertedReceiver] = useState(undefined);
+
+ const config = useConfig();
+ const { gatekeeperAddress } = useGatekeeperAddress(chainId);
+
+ const chainExplorerUrl = useMemo(() => {
+ const client = config?.getClient();
+ return client?.chain?.blockExplorers?.default?.url;
+ }, [config]);
+
+ useEffect(() => {
+ try {
+ const [publicKey, prefix] = ss58Decode(receiver);
+ if (prefix !== 1995 && prefix !== 1996) {
+ throw new Error("bad prefix");
+ }
+ setConvertedReceiver(toHex(publicKey));
+ } catch {
+ setConvertedReceiver(undefined);
+ }
+ }, [receiver]);
+
+ return (
+ <>
+ Bridge to start earning {bridgeNumbers} {"Stake\u00B2"} on your {ghstSymbol} balance:
+
+
+ {formatNumber(estimatedAmount, 5)} {ghstSymbol}
+
+
+
+ Generate a unique address for per tx with GHOST connect for privacy.
+
+
+ setReceiver(convertedReceiver ? "" : event.currentTarget.value)}
+ inputProps={{ "data-testid": "fromInput" }}
+ placeholder="GHOST address (sf prefixed)"
+ endString={convertedReceiver
+ ?
+ : undefined
+ }
+ type="text"
+ maxWidth="100%"
+ />
+
+
+
+ Gatekeeper
+
+
+ {shorten(gatekeeperAddress, 10, -8)}
+
+
+
+
+ Bridge Fee
+ {formatNumber(incomingFee, 4)}%
+
+
+ Est. Time
+ 20 mins
+
+
+
+
+ Proceed
+
+ >
+ )
+}
+
+const WelcomeView = ({
+ bridgeNumbers,
+ goNext,
+ isStakingOpened,
+ chainId,
+ warmupPeriod,
+ ghstSymbol,
+ ftsoSymbol,
+ defaultFunction,
+ closeModal
+}) => {
+ const [isPending, setIsPending] = useState(false);
+
+ const { epoch } = useEpoch(chainId);
+ const { gatekeeperAddress } = useGatekeeperAddress(chainId);
+ const circulatingSupply = useCirculatingSupply(chainId, "STNK");
+ const gatekeepedApy = useGatekeeperApy(chainId);
+
+ const apyInner = useMemo(() => {
+ let apy = Infinity;
+ if (circulatingSupply._value > 0n) {
+ const value = epoch.distribute.div(circulatingSupply);
+ apy = 100 * (Math.pow(1 + parseFloat(value.toString()), 1095) - 1);
+ if (apy === 0) apy = Infinity;
+ }
+ return apy;
+ }, [circulatingSupply, epoch]);
+
+ const callDefaultFunction = useCallback(async () => {
+ setIsPending(true);
+ await defaultFunction()();
+ setIsPending(false);
+ closeModal();
+ }, [defaultFunction]);
+
+ return (
+ <>
+ {warmupPeriod <= 0
+ ? `You've succesfully warmed-up your ${isStakingOpened ? " " : "bonded "}${ftsoSymbol} staked at:`
+ : `${isStakingOpened ? "Stake" : "Bond"} is in warm-up${isStakingOpened ? "" : ", which extends with each purchase"}. Your ${ftsoSymbol} is staked at:`
+ }
+
+
+ {formatNumber(apyInner, 2)}% APY
+
+
+ {warmupPeriod <= 0 && callDefaultFunction()}
+ disabled={isPending || warmupPeriod > 0}
+ fullWidth
+ >
+ Claim {isStakingOpened ? "(3, 3) Stake" : "(1, 1) Bond"}
+ }
+
+
+
+ OR
+
+
+
+
+ Skip the Warm-up Now!
+ {`Bridge your ${ghstSymbol} to GHOST Chain and stake at:`}
+
+
+
+ {formatNumber(apyInner * gatekeepedApy, 2)}% APY
+
+
+
+ {`Start ${bridgeNumbers} ${"Stake\u00B2"}`}
+
+ >
+ )
+}
+
+const ConfirmStep = ({
+ chainId,
+ address,
+ receiver,
+ executableFunction,
+ ghstSymbol,
+ bridgeNumbers,
+ estimatedAmount,
+ bridgingRisk,
+ incomingFee,
+ setActiveTxIndex,
+ closeModal,
+ evmNetwork
+}) => {
+ const config = useConfig();
+ const navigate = useNavigate();
+
+ const currentSession = useCurrentIndex();
+ const { getStorageValue, setStorageValue } = useLocalStorage();
+
+ const [blockNumber, setBlockNumber] = useState(0n);
+ const [isPending, setIsPending] = useState(false);
+ const [acknowledgeBridgingRisk, setAcknowledgeBridgingRisk] = useState(false);
+ const [acknowledgeWalletCustody, setAcknowledgeWalletCustody] = useState(false);
+
+ getBlockNumber(config).then(block => setBlockNumber(block));
+
+ const nativeSymbol = useMemo(() => config?.getClient()?.chain?.nativeCurrency?.symbol, [config]);
+ const networkName= useMemo(() => config?.getClient()?.chain?.name.toLowerCase(), [config]);
+
+ const receivedEstimation = useMemo(() => {
+ const decimals = incomingFee._decimals + 2;
+ const afterFee = new DecimalBigNumber(
+ Math.pow(10, decimals) - incomingFee._value,
+ decimals
+ );
+ return estimatedAmount.mul(afterFee);
+ }, [incomingFee, estimatedAmount]);
+
+ const execute = useCallback(async () => {
+ setIsPending(true);
+ try {
+ const txHash = await executableFunction()(receiver);
+ if (txHash) {
+ const expectedSessionIndex = (currentSession ?? 0) + (evmNetwork
+ ? Number((evmNetwork.avg_block_speed * evmNetwork.finality_delay) / (1000n * 14400n))
+ : 0);
+
+ const transaction = {
+ sessionIndex: expectedSessionIndex,
+ transactionHash: txHash,
+ receiverAddress: receiver,
+ amount: estimatedAmount._value.toString(),
+ chainId: chainId,
+ blockNumber: Number(blockNumber),
+ bridgeStability: 69, // TODO: avoid stability
+ timestamp: Date.now()
+ }
+
+ const storedTransactions = getStorageValue(chainId, address, "bridge-txs", []);
+ const newStoredTransactions = [transaction, ...storedTransactions];
+ setStorageValue(chainId, address, "bridge-txs", newStoredTransactions);
+
+ setActiveTxIndex(0);
+ navigate(`${networkName}/bridge`);
+ }
+ } finally {
+ setIsPending(false);
+ closeModal();
+ }
+ }, [executableFunction, receiver, networkName, chainId, address, blockNumber, evmNetwork, currentSession]);
+
+ return (
+ <>
+
+
+
+
+
+ {ghstSymbol}
+
+
+
+
+
+
+
+ {ghstSymbol}
+
+
+
+
+ {`You are bridging to GHOST Chain now to claim ${bridgeNumbers} ${"Stake\u00B2"} rewards.`}
+
+
+
+
+ setAcknowledgeBridgingRisk(event.target.checked)}
+ icon={}
+ checkedIcon={}
+ />
+ }
+ label={
+
+ {`I acknowledge decentralized bridging risk.`}
+
+ Learn more.
+
+
+ }
+ sx={{ '& .MuiFormControlLabel-label': { textAlign: "justify" } }}
+ />
+ setAcknowledgeWalletCustody(event.target.checked)}
+ icon={}
+ checkedIcon={}
+ />
+ }
+ label={
+
+ I confirm that recipient address is a self-custodial wallet, not an exchange, third party service, or smart-contract.
+
+ }
+ sx={{ '& .MuiFormControlLabel-label': { textAlign: "justify" } }}
+ />
+
+
+ execute()}
+ disabled={isPending || !acknowledgeWalletCustody || !acknowledgeBridgingRisk}
+ fullWidth
+ >
+ I Confirm
+
+ >
+ )
+}
+
+export default BreakoutModal;
diff --git a/src/containers/Bridge/Bridge.jsx b/src/containers/Bridge/Bridge.jsx
index a03b17e..2b73e2b 100644
--- a/src/containers/Bridge/Bridge.jsx
+++ b/src/containers/Bridge/Bridge.jsx
@@ -47,6 +47,7 @@ import {
useEraIndex,
} from "../../hooks/ghost";
import { useLocalStorage } from "../../hooks/localstorage";
+import { useBreakoutModal } from "../../hooks/breakoutModal";
import { ValidatorTable } from "./ValidatorTable";
import { BridgeModal, BridgeConfirmModal } from "./BridgeModal";
@@ -61,12 +62,12 @@ const Bridge = ({ chainId, address, config, connect }) => {
const [bridgeModalOpen, setBridgeModalOpen] = useState(false);
const [isConfirmed, setIsConfirmed] = useState(false);
- const [activeTxIndex, setActiveTxIndex] = useState(-1);
const [blockNumber, setBlockNumber] = useState(0n);
const [bridgeAction, setBridgeAction] = useState(true);
const [currentTime, setCurrentTime] = useState(Date.now());
const { getStorageValue, setStorageValue } = useLocalStorage();
+ const { activeTxIndex, setActiveTxIndex } = useBreakoutModal();
useEffect(() => {
const interval = setInterval(() => setCurrentTime(Date.now()), 1000);
diff --git a/src/containers/Dex/Dex.jsx b/src/containers/Dex/Dex.jsx
index 9826fe5..923ae86 100644
--- a/src/containers/Dex/Dex.jsx
+++ b/src/containers/Dex/Dex.jsx
@@ -74,7 +74,7 @@ const Dex = ({ chainId, address, connect, config }) => {
const chainSymbol = config?.getClient()?.chain?.nativeCurrency?.symbol;
if (chainSymbol) return chainSymbol;
return "WTF";
- }, [config])
+ }, [config, chainId])
const tokenNameTop = useMemo(() => {
if (chainSymbol && tokenAddressTop === EMPTY_ADDRESS) {
diff --git a/src/containers/Stake/components/ClaimConfirmationModal.jsx b/src/containers/Stake/components/ClaimConfirmationModal.jsx
index dc2653b..4a57c06 100644
--- a/src/containers/Stake/components/ClaimConfirmationModal.jsx
+++ b/src/containers/Stake/components/ClaimConfirmationModal.jsx
@@ -30,8 +30,6 @@ const ClaimConfirmationModal = (props) => {
props.ghstSymbol
);
break;
- default:
- console.log("Unknown action")
}
setIsPending(false);
diff --git a/src/containers/Stake/components/ClaimsArea.jsx b/src/containers/Stake/components/ClaimsArea.jsx
index 310b907..c270860 100644
--- a/src/containers/Stake/components/ClaimsArea.jsx
+++ b/src/containers/Stake/components/ClaimsArea.jsx
@@ -9,7 +9,7 @@ import {
Skeleton,
} from "@mui/material";
import { styled } from "@mui/material/styles";
-import { useState, useMemo } from "react";
+import { useState, useMemo, useCallback } from "react";
import useMediaQuery from "@mui/material/useMediaQuery";
@@ -26,9 +26,10 @@ import { DecimalBigNumber } from "../../../helpers/DecimalBigNumber";
import { prettifySecondsInDays } from "../../../helpers/timeUtil";
import { formatNumber, formatCurrency } from "../../../helpers";
import { STAKING_ADDRESSES } from "../../../constants/addresses";
-import { useCurrentIndex, useWarmupInfo } from "../../../hooks/staking";
+import { useCurrentIndex, useWarmupInfo, claim, breakout } from "../../../hooks/staking";
import { useBalanceForShares, useTokenSymbol } from "../../../hooks/tokens";
import { useGhstPrice, useStnkPrice } from "../../../hooks/prices";
+import { useBreakoutModal } from "../../../hooks/breakoutModal";
import { isNetworkLegacy } from "../../../constants";
import ClaimConfirmationModal from "./ClaimConfirmationModal";
@@ -52,7 +53,8 @@ const StyledTableHeader = styled(TableHead)(({ theme }) => ({
export const ClaimsArea = ({ chainId, address, epoch }) => {
const isSmallScreen = useMediaQuery("(max-width: 745px)");
- const [confirmationModalOpen, setConfirmationModalOpen] = useState(false);
+ const { breakoutFromStaking } = useBreakoutModal();
+ const [confirmationModalOpen, setConfirmationModalOpenInner] = useState(false);
const [isPayoutGhst, _] = useState(true);
const ghstPrice = useGhstPrice(chainId);
@@ -74,6 +76,23 @@ export const ClaimsArea = ({ chainId, address, epoch }) => {
return isPayoutGhst ? toClaim : toClaim.mul(currentIndex);
}, [chainId, claim, currentIndex, balanceForShares]);
+ const setConfirmationModalOpen = useCallback(async (value) => {
+ if (isNetworkLegacy(chainId) || claim.expiry > epoch.number) {
+ setConfirmationModalOpenInner(value);
+ } else {
+ const defaultFunction = async () => {
+ await claim(chainId, address, false, stnkSymbol, ghstSymbol);
+ await claimRefetch();
+ }
+ const warmupLeft = claim.expiry - epoch.number;
+ const toExecute = async (receiver) => {
+ await breakout(chainId, address, receiver, claimableBalance);
+ await claimRefetch();
+ }
+ breakoutFromStaking({ defaultFunction, toExecute, amount: claimableBalance, warmupLeft })
+ }
+ }, [claim, epoch, address, chainId, ghstSymbol]);
+
const closeConfirmationModal = () => {
setConfirmationModalOpen(false);
claimRefetch();
@@ -89,7 +108,6 @@ export const ClaimsArea = ({ chainId, address, epoch }) => {
closeConfirmationModal()}
- chainid={chainId}
receiver={address}
receiveAmount={claim.expiry > epoch.number ? claim.deposit : claimableBalance}
outputToken={claim.expiry > epoch.number ? ftsoSymbol : isPayoutGhst ? ghstSymbol : stnkSymbol}
@@ -257,7 +275,7 @@ const ActionButtons = ({ setConfirmationModalOpen, isSmallScreen = false, isClai
fullWidth={isSmallScreen}
sx={{ flexGrow: 1 }}
onClick={() => setConfirmationModalOpen(true)}
- disabled={!isClaimable}
+ disabled={isClaimable}
>
Emergency Withdrawal
diff --git a/src/helpers/index.js b/src/helpers/index.js
index 373b812..df52466 100644
--- a/src/helpers/index.js
+++ b/src/helpers/index.js
@@ -1,6 +1,6 @@
-export function shorten(str) {
+export function shorten(str, first = 6, second = -4) {
if (str.length < 10) return str;
- return `${str.slice(0, 6)}...${str.slice(str.length - 4)}`;
+ return `${str.slice(0, first)}...${str.slice(second)}`;
}
export function capitalize(str) {
diff --git a/src/main.jsx b/src/main.jsx
index 73536b4..6212fa0 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -10,6 +10,7 @@ import { WagmiProvider } from "wagmi";
import { config } from "./config";
import { UnstableProviderProvider, MetadataProviderProvider } from "./hooks/ghost"
import { LocalStorageProvider } from "./hooks/localstorage";
+import { BreakoutModalProvider } from "./hooks/breakoutModal";
import ReactGA from "react-ga4";
const queryClient = new QueryClient();
@@ -26,7 +27,9 @@ ReactDOM.createRoot(document.getElementById('root')).render(
-
+
+
+