From bc76372897e31104641d3ec1c9ac1f66b78b2ac9 Mon Sep 17 00:00:00 2001 From: Uncle Fatso Date: Sun, 3 May 2026 20:02:32 +0300 Subject: [PATCH] make connection state more explicit Signed-off-by: Uncle Fatso --- package.json | 2 +- src/App.jsx | 19 ------ src/containers/Breakout/BreakoutModal.jsx | 71 +++++++++++++---------- src/hooks/breakoutModal/index.jsx | 7 +-- src/hooks/ghost/UnstableProvider.jsx | 59 ++++++------------- 5 files changed, 58 insertions(+), 100 deletions(-) diff --git a/package.json b/package.json index 3c1f8ac..7e0c8a4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ghost-dao-interface", "private": true, - "version": "0.7.35", + "version": "0.7.36", "type": "module", "scripts": { "dev": "vite", diff --git a/src/App.jsx b/src/App.jsx index cf2c8f1..b146f1b 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -26,7 +26,6 @@ import BreakoutModal from "./containers/Breakout/BreakoutModal"; import { shouldTriggerSafetyCheck } from "./helpers"; import { isNetworkAvailable } from "./constants"; import useTheme from "./hooks/useTheme"; -import { useUnstableProvider } from "./hooks/ghost"; import { dark as darkTheme } from "./themes/dark.js"; import { girth as gTheme } from "./themes/girth.js"; import { light as lightTheme } from "./themes/light.js"; @@ -126,24 +125,6 @@ function App() { const isSmallerScreen = useMediaQuery("(max-width: 1047px)"); const isSmallScreen = useMediaQuery("(max-width: 600px)"); - const { - providerDetail, - providerDetails, - connectProviderDetail - } = useUnstableProvider() - - useEffect(() => { - // TODO: make sure we are using correct extension - const maybeProvider = providerDetails?.find(obj => obj.info.rdns === "io.ghostchain.GhostWalletExtension") - if (maybeProvider && !providerDetail) { - try { - connectProviderDetail(maybeProvider) - } catch (e) { - console.log(e) - } - } - }, [providerDetail, providerDetails, connectProviderDetail]) - useEffect(() => { if (shouldTriggerSafetyCheck()) { toast.success("Safety Check: Always verify you're on app.dao.ghostchain.io!", { duration: 5000 }); diff --git a/src/containers/Breakout/BreakoutModal.jsx b/src/containers/Breakout/BreakoutModal.jsx index 5e5414a..964baa4 100644 --- a/src/containers/Breakout/BreakoutModal.jsx +++ b/src/containers/Breakout/BreakoutModal.jsx @@ -22,7 +22,7 @@ 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 { useEvmNetwork, useCurrentIndex, useUnstableProvider } from "../../hooks/ghost"; import { formatNumber, shorten } from "../../helpers"; import { DecimalBigNumber } from "../../helpers/DecimalBigNumber"; @@ -103,31 +103,31 @@ const BreakoutModal = ({ chainId, address }) => { goNext={() => setStep(1)} closeModal={closeModal} /> - : step === 1 - ? setStep(2)} - /> - : + : step === 1 + ? setStep(2)} + /> + : } @@ -248,6 +248,13 @@ const WelcomeView = ({ const circulatingSupply = useCirculatingSupply(chainId, "STNK"); const gatekeepedApy = useGatekeeperApy(chainId); + const { isExtensionMissing } = useUnstableProvider(); + + const getConnect = () => { + window.open(GHOST_CONNECT, '_blank', 'noopener,noreferrer'); + closeModal(); + } + const apyInner = useMemo(() => { let apy = Infinity; if (circulatingSupply._value > 0n) { @@ -268,8 +275,8 @@ const WelcomeView = ({ return ( <> {warmupPeriod <= 0 - ? `You've succesfully warmed-up your ${isStakingOpened ? " " : "bonded "}${ftsoSymbol} ${isStakingOpened ? "(3, 3)" : "(1, 1)"} staked at:` - : `${isStakingOpened ? "Stake" : "Bond"} is in warm-up${isStakingOpened ? "" : ", which extends with each purchase"}. Your ${ftsoSymbol} ${isStakingOpened ? "(3, 3)" : "(1, 1)"} is staked at:` + ? `You've succesfully warmed-up your ${isStakingOpened ? " " : "bonded "}${ftsoSymbol} ${isStakingOpened ? "(3, 3)" : "(1, 1)"} Staked at:` + : `${isStakingOpened ? "Stake" : "Bond"} is in warm-up${isStakingOpened ? "" : ", which extends with each purchase"}. Your ${ftsoSymbol} ${isStakingOpened ? "(3, 3)" : "(1, 1)"} is Staked at:` } @@ -293,7 +300,7 @@ const WelcomeView = ({ Skip the Warm-up Now! - {`Bridge your ${ghstSymbol} to GHOST Chain and start ${bridgeNumbers} ${"stake\u00B2"} at:`} + {`Bridge your ${ghstSymbol} to GHOST Chain and start ${bridgeNumbers} ${"Stake\u00B2"} at:`} @@ -302,10 +309,10 @@ const WelcomeView = ({ - {`Start ${bridgeNumbers} ${"Stake\u00B2"}`} + {isExtensionMissing ? "Get GHOST Connect" : `Start ${bridgeNumbers} ${"Stake\u00B2"}`} ) @@ -344,7 +351,7 @@ const ConfirmStep = ({ const receivedEstimation = useMemo(() => { const decimals = incomingFee._decimals + 2; const afterFee = new DecimalBigNumber( - Math.pow(10, decimals) - incomingFee._value, + BigInt(Math.pow(10, decimals) - incomingFee._value), decimals ); return estimatedAmount.mul(afterFee); diff --git a/src/hooks/breakoutModal/index.jsx b/src/hooks/breakoutModal/index.jsx index 817293b..6f7ed1b 100644 --- a/src/hooks/breakoutModal/index.jsx +++ b/src/hooks/breakoutModal/index.jsx @@ -8,7 +8,7 @@ export const useBreakoutModal = () => useContext(BreakoutModalContext); export const BreakoutModalProvider = ({ children }) => { const [isStakingOpened, setIsStakingOpened] = useState(false); const [isClaimBondOpened, setIsClaimBondOpened] = useState(false); - const [activeTxIndex, setActiveTxIndexInner] = useState(-1); + const [activeTxIndex, setActiveTxIndex] = useState(-1); const [warmupPeriod, setWarmupPeriod] = useState(0); const [estimatedAmount, setEstimatedAmount] = useState(0); const [defaultFunction, setDefaultFunction] = useState(emptyFunction); @@ -42,11 +42,6 @@ export const BreakoutModalProvider = ({ children }) => { setExecutableFunction(emptyFunction); } - const setActiveTxIndex = (v) => { - console.log("here", v) - setActiveTxIndexInner(v) - } - return ( useContext(UnstableProvider) export const UnstableProviderProvider = ({ children }) => { const [chainId, setChainId] = useState(DEFAULT_CHAIN_ID); - const [isConnected, setIsConnected] = useState(false); - const [reconnectTicket, setReconnectTicket] = useState(0); + const [providerIndex, setProviderIndex] = useState(0); const { data: providerDetails } = useSWR("getGhostProviders", () => Unstable.getSubstrateConnectExtensionProviders() ); - const [providerDetail, setProviderDetail] = useState(); + const providerDetail = useMemo(() => providerDetails?.at(providerIndex), [providerDetails, providerIndex]); + const { data: provider } = useSWR( () => providerDetail ? `ghostProviderDetail.${providerDetail.info.uuid}.provider` : null, () => providerDetail ? providerDetail.provider : null ); + const connectionState = useMemo(() => { + if (!providerDetail) return 'no-extension'; + if (!provider) return 'loading'; + + const chains = provider.getChains(); + if (chains[chainId]) return 'connected'; + + return 'wrong-network'; + }, [providerDetail, provider, chainId]); + const client = useMemo(() => { if (!provider || !chainId) return undefined; @@ -31,56 +41,21 @@ export const UnstableProviderProvider = ({ children }) => { if (!chain) return undefined; return createClient(chain.connect) - }, [provider, chainId, reconnectTicket]); + }, [provider, chainId]); const observableClient = useMemo(() => client ? getObservableClient(client) : undefined, [client]); const chainHead$ = useMemo(() => observableClient?.chainHead$(), [observableClient]); - const lastBlockNumber = useRef(0); - - useEffect(() => { - if (!chainHead$) return; - - lastBlockNumber.current = 0; - let timeoutId; - - const sub = chainHead$.bestBlocks$.subscribe({ - next: (blocks) => { - const currentHeight = blocks.at(0)?.number ?? -1; - - if (currentHeight > lastBlockNumber.current) { - lastBlockNumber.current = currentHeight; - setIsConnected(true); - - clearTimeout(timeoutId); - timeoutId = setTimeout(() => { - setIsConnected(false); - setReconnectTicket(t => t + 1); - }, MAX_BLOCK_TIMEOUT); - } - }, - error: (err) => { - setIsConnected(false); - setTimeout(() => setReconnectTicket(t => t + 1), 1000); - } - }); - - return () => { - sub.unsubscribe(); - clearTimeout(timeoutId); - }; - }, [chainHead$]); - const value = useMemo(() => ({ - isConnected, + isExtensionMissing: connectionState === "no-extension", providerDetails, providerDetail, - connectProviderDetail: setProviderDetail, + connectProviderByIndex: setProviderIndex, chainId, client, setChainId, chainHead$ - }), [isConnected, providerDetails, providerDetail, chainId, client, chainHead$]); + }), [providerDetails, providerDetail, chainId, client, chainHead$]); return (