make connection state more explicit

Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
This commit is contained in:
Uncle Fatso 2026-05-03 20:02:32 +03:00
parent c38628c107
commit bc76372897
Signed by: f4ts0
GPG Key ID: 565F4F2860226EBB
5 changed files with 58 additions and 100 deletions

View File

@ -1,7 +1,7 @@
{ {
"name": "ghost-dao-interface", "name": "ghost-dao-interface",
"private": true, "private": true,
"version": "0.7.35", "version": "0.7.36",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@ -26,7 +26,6 @@ import BreakoutModal from "./containers/Breakout/BreakoutModal";
import { shouldTriggerSafetyCheck } from "./helpers"; import { shouldTriggerSafetyCheck } from "./helpers";
import { isNetworkAvailable } from "./constants"; import { isNetworkAvailable } from "./constants";
import useTheme from "./hooks/useTheme"; import useTheme from "./hooks/useTheme";
import { useUnstableProvider } from "./hooks/ghost";
import { dark as darkTheme } from "./themes/dark.js"; import { dark as darkTheme } from "./themes/dark.js";
import { girth as gTheme } from "./themes/girth.js"; import { girth as gTheme } from "./themes/girth.js";
import { light as lightTheme } from "./themes/light.js"; import { light as lightTheme } from "./themes/light.js";
@ -126,24 +125,6 @@ function App() {
const isSmallerScreen = useMediaQuery("(max-width: 1047px)"); const isSmallerScreen = useMediaQuery("(max-width: 1047px)");
const isSmallScreen = useMediaQuery("(max-width: 600px)"); 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(() => { useEffect(() => {
if (shouldTriggerSafetyCheck()) { if (shouldTriggerSafetyCheck()) {
toast.success("Safety Check: Always verify you're on app.dao.ghostchain.io!", { duration: 5000 }); toast.success("Safety Check: Always verify you're on app.dao.ghostchain.io!", { duration: 5000 });

View File

@ -22,7 +22,7 @@ import { useLocalStorage } from "../../hooks/localstorage";
import { useBreakoutModal } from "../../hooks/breakoutModal"; import { useBreakoutModal } from "../../hooks/breakoutModal";
import { useTokenSymbol, useCirculatingSupply } from "../../hooks/tokens"; import { useTokenSymbol, useCirculatingSupply } from "../../hooks/tokens";
import { useEpoch, useGatekeeperApy, useGatekeeperAddress } from "../../hooks/staking"; 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 { formatNumber, shorten } from "../../helpers";
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber"; import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
@ -248,6 +248,13 @@ const WelcomeView = ({
const circulatingSupply = useCirculatingSupply(chainId, "STNK"); const circulatingSupply = useCirculatingSupply(chainId, "STNK");
const gatekeepedApy = useGatekeeperApy(chainId); const gatekeepedApy = useGatekeeperApy(chainId);
const { isExtensionMissing } = useUnstableProvider();
const getConnect = () => {
window.open(GHOST_CONNECT, '_blank', 'noopener,noreferrer');
closeModal();
}
const apyInner = useMemo(() => { const apyInner = useMemo(() => {
let apy = Infinity; let apy = Infinity;
if (circulatingSupply._value > 0n) { if (circulatingSupply._value > 0n) {
@ -268,8 +275,8 @@ const WelcomeView = ({
return ( return (
<> <>
<Typography>{warmupPeriod <= 0 <Typography>{warmupPeriod <= 0
? `You've succesfully warmed-up your ${isStakingOpened ? " " : "bonded "}${ftsoSymbol} ${isStakingOpened ? "(3, 3)" : "(1, 1)"} 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:` : `${isStakingOpened ? "Stake" : "Bond"} is in warm-up${isStakingOpened ? "" : ", which extends with each purchase"}. Your ${ftsoSymbol} ${isStakingOpened ? "(3, 3)" : "(1, 1)"} is Staked at:`
}</Typography> }</Typography>
<Box display="flex" justifyContent="center"> <Box display="flex" justifyContent="center">
@ -293,7 +300,7 @@ const WelcomeView = ({
<Box display="flex" flexDirection="column" justifyContent="space-between" gap="10px"> <Box display="flex" flexDirection="column" justifyContent="space-between" gap="10px">
<Typography fontWeight="bold">Skip the Warm-up Now!</Typography> <Typography fontWeight="bold">Skip the Warm-up Now!</Typography>
<Typography>{`Bridge your ${ghstSymbol} to GHOST Chain and start ${bridgeNumbers} ${"stake\u00B2"} at:`}</Typography> <Typography>{`Bridge your ${ghstSymbol} to GHOST Chain and start ${bridgeNumbers} ${"Stake\u00B2"} at:`}</Typography>
</Box> </Box>
<Box display="flex" justifyContent="center" flexDirection="column" alignItems="center"> <Box display="flex" justifyContent="center" flexDirection="column" alignItems="center">
@ -302,10 +309,10 @@ const WelcomeView = ({
<PrimaryButton <PrimaryButton
disabled={isPending || gatekeeperAddress === EMPTY_ADDRESS} disabled={isPending || gatekeeperAddress === EMPTY_ADDRESS}
onClick={goNext} onClick={isExtensionMissing ? getConnect : goNext}
fullWidth fullWidth
> >
{`Start ${bridgeNumbers} ${"Stake\u00B2"}`} {isExtensionMissing ? "Get GHOST Connect" : `Start ${bridgeNumbers} ${"Stake\u00B2"}`}
</PrimaryButton> </PrimaryButton>
</> </>
) )
@ -344,7 +351,7 @@ const ConfirmStep = ({
const receivedEstimation = useMemo(() => { const receivedEstimation = useMemo(() => {
const decimals = incomingFee._decimals + 2; const decimals = incomingFee._decimals + 2;
const afterFee = new DecimalBigNumber( const afterFee = new DecimalBigNumber(
Math.pow(10, decimals) - incomingFee._value, BigInt(Math.pow(10, decimals) - incomingFee._value),
decimals decimals
); );
return estimatedAmount.mul(afterFee); return estimatedAmount.mul(afterFee);

View File

@ -8,7 +8,7 @@ export const useBreakoutModal = () => useContext(BreakoutModalContext);
export const BreakoutModalProvider = ({ children }) => { export const BreakoutModalProvider = ({ children }) => {
const [isStakingOpened, setIsStakingOpened] = useState(false); const [isStakingOpened, setIsStakingOpened] = useState(false);
const [isClaimBondOpened, setIsClaimBondOpened] = useState(false); const [isClaimBondOpened, setIsClaimBondOpened] = useState(false);
const [activeTxIndex, setActiveTxIndexInner] = useState(-1); const [activeTxIndex, setActiveTxIndex] = useState(-1);
const [warmupPeriod, setWarmupPeriod] = useState(0); const [warmupPeriod, setWarmupPeriod] = useState(0);
const [estimatedAmount, setEstimatedAmount] = useState(0); const [estimatedAmount, setEstimatedAmount] = useState(0);
const [defaultFunction, setDefaultFunction] = useState(emptyFunction); const [defaultFunction, setDefaultFunction] = useState(emptyFunction);
@ -42,11 +42,6 @@ export const BreakoutModalProvider = ({ children }) => {
setExecutableFunction(emptyFunction); setExecutableFunction(emptyFunction);
} }
const setActiveTxIndex = (v) => {
console.log("here", v)
setActiveTxIndexInner(v)
}
return ( return (
<BreakoutModalContext.Provider value={{ <BreakoutModalContext.Provider value={{
isStakingOpened, isStakingOpened,

View File

@ -11,19 +11,29 @@ export const useUnstableProvider = () => useContext(UnstableProvider)
export const UnstableProviderProvider = ({ children }) => { export const UnstableProviderProvider = ({ children }) => {
const [chainId, setChainId] = useState(DEFAULT_CHAIN_ID); const [chainId, setChainId] = useState(DEFAULT_CHAIN_ID);
const [isConnected, setIsConnected] = useState(false); const [providerIndex, setProviderIndex] = useState(0);
const [reconnectTicket, setReconnectTicket] = useState(0);
const { data: providerDetails } = useSWR("getGhostProviders", () => const { data: providerDetails } = useSWR("getGhostProviders", () =>
Unstable.getSubstrateConnectExtensionProviders() Unstable.getSubstrateConnectExtensionProviders()
); );
const [providerDetail, setProviderDetail] = useState(); const providerDetail = useMemo(() => providerDetails?.at(providerIndex), [providerDetails, providerIndex]);
const { data: provider } = useSWR( const { data: provider } = useSWR(
() => providerDetail ? `ghostProviderDetail.${providerDetail.info.uuid}.provider` : null, () => providerDetail ? `ghostProviderDetail.${providerDetail.info.uuid}.provider` : null,
() => providerDetail ? providerDetail.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(() => { const client = useMemo(() => {
if (!provider || !chainId) return undefined; if (!provider || !chainId) return undefined;
@ -31,56 +41,21 @@ export const UnstableProviderProvider = ({ children }) => {
if (!chain) return undefined; if (!chain) return undefined;
return createClient(chain.connect) return createClient(chain.connect)
}, [provider, chainId, reconnectTicket]); }, [provider, chainId]);
const observableClient = useMemo(() => client ? getObservableClient(client) : undefined, [client]); const observableClient = useMemo(() => client ? getObservableClient(client) : undefined, [client]);
const chainHead$ = useMemo(() => observableClient?.chainHead$(), [observableClient]); 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(() => ({ const value = useMemo(() => ({
isConnected, isExtensionMissing: connectionState === "no-extension",
providerDetails, providerDetails,
providerDetail, providerDetail,
connectProviderDetail: setProviderDetail, connectProviderByIndex: setProviderIndex,
chainId, chainId,
client, client,
setChainId, setChainId,
chainHead$ chainHead$
}), [isConnected, providerDetails, providerDetail, chainId, client, chainHead$]); }), [providerDetails, providerDetail, chainId, client, chainHead$]);
return ( return (
<UnstableProvider.Provider value={value}> <UnstableProvider.Provider value={value}>