stabilize connection state of the ghost connect

Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
This commit is contained in:
Uncle Fatso 2026-04-09 14:30:55 +03:00
parent fe71618369
commit c2d81bc229
Signed by: f4ts0
GPG Key ID: 565F4F2860226EBB
3 changed files with 52 additions and 41 deletions

View File

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

View File

@ -92,7 +92,7 @@ function SelectNetwork({ chainId, wrongNetworkToastId, setWrongNetworkToastId, s
return (
<MenuItem key={chain.name} value={chain.id}>
<Box gap="10px" display="flex" flexDirection="row" alignItems="center">
<SvgIcon component={parseKnownToken(chain?.nativeCurrency?.symbol)} inheritViewBox />
<SvgIcon sx={{ width: 22 }} component={parseKnownToken(chain?.nativeCurrency?.symbol)} inheritViewBox />
{!small && <Typography>{chain.name}</Typography>}
</Box>
</MenuItem>

View File

@ -1,14 +1,19 @@
import { createContext, useEffect, useContext, useState, useMemo, useCallback } from "react"
import { createContext, useEffect, useContext, useState, useMemo, useCallback, useRef } from "react"
import { Unstable } from "@substrate/connect-discovery"
import { createClient } from "@polkadot-api/substrate-client"
import { getObservableClient } from "@polkadot-api/observable-client"
import useSWR from "swr"
const MAX_BLOCK_TIMEOUT = 15000
const DEFAULT_CHAIN_ID = "0x475e48fab52f3d0587b6b03101d224560c549e984d1dee197b7d8b55830e7da3"
const UnstableProvider = createContext(null)
export const useUnstableProvider = () => useContext(UnstableProvider)
export const UnstableProviderProvider = ({ children }) => {
const [chainId, setChainId] = useState(DEFAULT_CHAIN_ID);
const [isConnected, setIsConnected] = useState(false);
const [reconnectTicket, setReconnectTicket] = useState(0);
const { data: providerDetails } = useSWR("getGhostProviders", () =>
Unstable.getSubstrateConnectExtensionProviders()
);
@ -19,60 +24,66 @@ export const UnstableProviderProvider = ({ children }) => {
() => providerDetail ? providerDetail.provider : null
);
const [chainId, setChainId] = useState(DEFAULT_CHAIN_ID);
const [isConnected, setIsConnected] = useState(false);
const [reconnectTicket, setReconnectTicket] = useState(0);
const reconnect = () => setReconnectTicket(prev => prev + 1);
const createConnectWithStatus = (originalConnect, onConnect) => {
return (observer) => {
onConnect(true);
return originalConnect(observer);
};
};
const client = useMemo(() => {
if (!provider || !chainId) return undefined;
const chain = provider.getChains()[chainId];
if (!chain) return undefined;
const wrappedConnect = createConnectWithStatus(chain.connect, setIsConnected);
return createClient(wrappedConnect);
return createClient(chain.connect)
}, [provider, chainId, reconnectTicket]);
const observableClient = useMemo(() => {
return client ? getObservableClient(client) : undefined;
}, [client]);
const observableClient = useMemo(() => client ? getObservableClient(client) : undefined, [client]);
const chainHead$ = useMemo(() => observableClient?.chainHead$(), [observableClient]);
const chainHead$ = useMemo(() => {
return observableClient ? observableClient.chainHead$() : undefined;
}, [observableClient]);
const lastBlockNumber = useRef(0);
useEffect(() => {
if (!chainHead$) return;
const sub = chainHead$.runtime$.subscribe({
next: () => setIsConnected(true),
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(reconnect, 3000);
setTimeout(() => setReconnectTicket(t => t + 1), 1000);
}
});
return () => sub.unsubscribe();
}, [chainHead$, reconnect]);
return () => {
sub.unsubscribe();
clearTimeout(timeoutId);
};
}, [chainHead$]);
const value = useMemo(() => ({
isConnected,
providerDetails,
providerDetail,
connectProviderDetail: setProviderDetail,
chainId,
client,
setChainId,
chainHead$
}), [isConnected, providerDetails, providerDetail, chainId, client, chainHead$]);
return (
<UnstableProvider.Provider
value={{
isConnected,
providerDetails,
providerDetail,
connectProviderDetail: setProviderDetail,
provider,
chainId,
client,
setChainId,
chainHead$
}}
>
<UnstableProvider.Provider value={value}>
{children}
</UnstableProvider.Provider>
);