diff --git a/src/App.tsx b/src/App.tsx index b3295ce..9c2f7b8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -9,6 +9,7 @@ import { WagmiProvider } from 'wagmi'; import { queryClient } from '@api/client'; import { Alert } from '@components/Alert'; +import { SquidHeightProvider } from '@hooks/useSquidNetworkHeightHooks'; import { wagmiConfig } from '@network/config'; import { AppRoutes } from './AppRoutes'; @@ -33,10 +34,12 @@ function App() { }} anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }} > - - - - + + + + + + diff --git a/src/api/contracts/claim.ts b/src/api/contracts/claim.ts index b5db77e..2cff9a9 100644 --- a/src/api/contracts/claim.ts +++ b/src/api/contracts/claim.ts @@ -7,7 +7,7 @@ import { useWriteContract, useClient } from 'wagmi'; import { REWARD_TREASURY_CONTRACT_ABI } from '@api/contracts/reaward-treasury.abi'; import { VESTING_CONTRACT_ABI } from '@api/contracts/vesting.abi'; import { AccountType, SourceWallet } from '@api/subsquid-network-squid'; -import { useSquidNetworkHeightHooks } from '@hooks/useSquidNetworkHeightHooks.ts'; +import { useSquidNetworkHeight } from '@hooks/useSquidNetworkHeightHooks'; import { useAccount } from '@network/useAccount.ts'; import { useContracts } from '@network/useContracts.ts'; @@ -67,7 +67,7 @@ function useClaimFromVestingContract() { export function useClaim() { const client = useClient(); - const { setWaitHeight } = useSquidNetworkHeightHooks(); + const { setWaitHeight } = useSquidNetworkHeight(); const [isLoading, setLoading] = useState(false); const [error, setError] = useState(null); diff --git a/src/api/contracts/gateway-registration/useRegisterGateway.ts b/src/api/contracts/gateway-registration/useRegisterGateway.ts index e1e5462..24a89ab 100644 --- a/src/api/contracts/gateway-registration/useRegisterGateway.ts +++ b/src/api/contracts/gateway-registration/useRegisterGateway.ts @@ -6,7 +6,7 @@ import { encodeFunctionData } from 'viem'; import { usePublicClient, useWriteContract } from 'wagmi'; import { AccountType } from '@api/subsquid-network-squid'; -import { useSquidNetworkHeightHooks } from '@hooks/useSquidNetworkHeightHooks.ts'; +import { useSquidNetworkHeight } from '@hooks/useSquidNetworkHeightHooks'; import { useAccount } from '@network/useAccount'; import { useContracts } from '@network/useContracts.ts'; @@ -82,7 +82,7 @@ export function useRegisterGateway() { const [error, setError] = useState(null); const [isLoading, setLoading] = useState(false); - const { setWaitHeight } = useSquidNetworkHeightHooks(); + const { setWaitHeight } = useSquidNetworkHeight(); const registerGatewayFromWallet = useRegisterGatewayFromWallet(); const registerGatewayFromVestingContract = useRegisterGatewayFromVestingContract(); diff --git a/src/api/contracts/gateway-registration/useStakeGateway.ts b/src/api/contracts/gateway-registration/useStakeGateway.ts index c719f3e..e80d8c5 100644 --- a/src/api/contracts/gateway-registration/useStakeGateway.ts +++ b/src/api/contracts/gateway-registration/useStakeGateway.ts @@ -5,7 +5,7 @@ import { encodeFunctionData } from 'viem'; import { usePublicClient, useWriteContract } from 'wagmi'; import { AccountType, SourceWallet } from '@api/subsquid-network-squid'; -import { useSquidNetworkHeightHooks } from '@hooks/useSquidNetworkHeightHooks.ts'; +import { useSquidNetworkHeight } from '@hooks/useSquidNetworkHeightHooks'; import { useAccount } from '@network/useAccount'; import { useContracts } from '@network/useContracts.ts'; @@ -105,7 +105,7 @@ function useStakeFromVestingContract() { export function useStakeGateway() { const client = usePublicClient(); - const { setWaitHeight } = useSquidNetworkHeightHooks(); + const { setWaitHeight } = useSquidNetworkHeight(); const [isLoading, setLoading] = useState(false); const [error, setError] = useState(null); diff --git a/src/api/contracts/gateway-registration/useUnregisterGateway.ts b/src/api/contracts/gateway-registration/useUnregisterGateway.ts index 30e4391..4549036 100644 --- a/src/api/contracts/gateway-registration/useUnregisterGateway.ts +++ b/src/api/contracts/gateway-registration/useUnregisterGateway.ts @@ -7,7 +7,7 @@ import { useWriteContract, usePublicClient } from 'wagmi'; import { AccountType } from '@api/subsquid-network-squid'; import { BlockchainGateway } from '@api/subsquid-network-squid/gateways-graphql'; -import { useSquidNetworkHeightHooks } from '@hooks/useSquidNetworkHeightHooks.ts'; +import { useSquidNetworkHeight } from '@hooks/useSquidNetworkHeightHooks'; import { useAccount } from '@network/useAccount'; import { useContracts } from '@network/useContracts.ts'; @@ -78,7 +78,7 @@ export function useUnregisterGateway() { const [error, setError] = useState(null); const [isLoading, setLoading] = useState(false); - const { setWaitHeight } = useSquidNetworkHeightHooks(); + const { setWaitHeight } = useSquidNetworkHeight(); const unregisterGatewayFromWallet = useUnregisterGatewayFromWallet(); const unregisterGatewayFromVestingContract = useUnregisterGatewayFromVestingContract(); diff --git a/src/api/contracts/gateway-registration/useUnstakeGateway.ts b/src/api/contracts/gateway-registration/useUnstakeGateway.ts index a6adb16..d08aba5 100644 --- a/src/api/contracts/gateway-registration/useUnstakeGateway.ts +++ b/src/api/contracts/gateway-registration/useUnstakeGateway.ts @@ -4,7 +4,7 @@ import { encodeFunctionData } from 'viem'; import { useWriteContract, usePublicClient } from 'wagmi'; import { AccountType, GatewayStakeFragmentFragment } from '@api/subsquid-network-squid'; -import { useSquidNetworkHeightHooks } from '@hooks/useSquidNetworkHeightHooks.ts'; +import { useSquidNetworkHeight } from '@hooks/useSquidNetworkHeightHooks'; import { useAccount } from '@network/useAccount'; import { useContracts } from '@network/useContracts.ts'; @@ -65,7 +65,7 @@ function useUnstakeFromVestingContract() { export function useUnstakeGateway() { const client = usePublicClient(); - const { setWaitHeight } = useSquidNetworkHeightHooks(); + const { setWaitHeight } = useSquidNetworkHeight(); const [isLoading, setLoading] = useState(false); const [error, setError] = useState(null); diff --git a/src/api/contracts/staking.ts b/src/api/contracts/staking.ts index e5f7aab..de69206 100644 --- a/src/api/contracts/staking.ts +++ b/src/api/contracts/staking.ts @@ -16,7 +16,7 @@ import { import { useApproveSqd } from '@api/contracts/sqd'; import { VESTING_CONTRACT_ABI } from '@api/contracts/vesting.abi'; import { AccountType, Worker, SourceWallet } from '@api/subsquid-network-squid'; -import { useSquidNetworkHeightHooks } from '@hooks/useSquidNetworkHeightHooks.ts'; +import { useSquidNetworkHeight } from '@hooks/useSquidNetworkHeightHooks'; import { useAccount } from '@network/useAccount'; import { useContracts } from '@network/useContracts.ts'; @@ -104,7 +104,7 @@ function useDepositFromVestingContract() { export function useWorkerDelegate() { const client = useClient(); - const { setWaitHeight } = useSquidNetworkHeightHooks(); + const { setWaitHeight } = useSquidNetworkHeight(); const [isLoading, setLoading] = useState(false); const [error, setError] = useState(null); @@ -195,7 +195,7 @@ function useUndelegateFromVestingContract() { export function useWorkerUndelegate() { const client = usePublicClient(); - const { setWaitHeight } = useSquidNetworkHeightHooks(); + const { setWaitHeight } = useSquidNetworkHeight(); const [isLoading, setLoading] = useState(false); const [error, setError] = useState(null); @@ -238,7 +238,7 @@ export function useWorkerUndelegate() { export function useCapedStake({ workerId }: { workerId?: string }) { const contracts = useContracts(); - const { currentHeight, isLoading: isHeightLoading } = useSquidNetworkHeightHooks(); + const { currentHeight, isLoading: isHeightLoading } = useSquidNetworkHeight(); const { data, isLoading } = useReadContract({ address: contracts.SOFT_CAP, diff --git a/src/api/contracts/vesting.ts b/src/api/contracts/vesting.ts index 415a611..cefb60f 100644 --- a/src/api/contracts/vesting.ts +++ b/src/api/contracts/vesting.ts @@ -5,7 +5,7 @@ import { erc20Abi, MulticallResponse } from 'viem'; import { waitForTransactionReceipt } from 'viem/actions'; import { useReadContracts, useWriteContract, useClient } from 'wagmi'; -import { useSquidNetworkHeightHooks } from '@hooks/useSquidNetworkHeightHooks'; +import { useSquidNetworkHeight } from '@hooks/useSquidNetworkHeightHooks'; import { useContracts } from '@network/useContracts'; import { errorMessage, WriteContractRes } from './utils'; @@ -13,7 +13,7 @@ import { VESTING_CONTRACT_ABI } from './vesting.abi'; export function useVestingContracts({ addresses }: { addresses: `0x${string}`[] }) { const contracts = useContracts(); - const { currentHeight, isLoading: isSquidHeightLoading } = useSquidNetworkHeightHooks(); + const { currentHeight, isLoading: isSquidHeightLoading } = useSquidNetworkHeight(); const { data, isLoading } = useReadContracts({ contracts: addresses.flatMap(address => { @@ -119,7 +119,7 @@ function unwrapResult(result?: MulticallResponse): T | undefined { export function useVestingContractRelease() { const client = useClient(); - const { setWaitHeight } = useSquidNetworkHeightHooks(); + const { setWaitHeight } = useSquidNetworkHeight(); const [isLoading, setLoading] = useState(false); const [error, setError] = useState(null); const { SQD } = useContracts(); diff --git a/src/api/contracts/worker-registration/useRegisterWorker.ts b/src/api/contracts/worker-registration/useRegisterWorker.ts index 06d44b1..457bae0 100644 --- a/src/api/contracts/worker-registration/useRegisterWorker.ts +++ b/src/api/contracts/worker-registration/useRegisterWorker.ts @@ -9,7 +9,7 @@ import { useWriteContract, usePublicClient, useClient } from 'wagmi'; import { useApproveSqd } from '@api/contracts/sqd'; import { VESTING_CONTRACT_ABI } from '@api/contracts/vesting.abi'; import { AccountType, SourceWallet } from '@api/subsquid-network-squid'; -import { useSquidNetworkHeightHooks } from '@hooks/useSquidNetworkHeightHooks.ts'; +import { useSquidNetworkHeight } from '@hooks/useSquidNetworkHeightHooks'; import { useAccount } from '@network/useAccount'; import { useContracts } from '@network/useContracts.ts'; @@ -120,7 +120,7 @@ export function useRegisterWorker() { const [error, setError] = useState(null); const [isLoading, setLoading] = useState(false); - const { setWaitHeight } = useSquidNetworkHeightHooks(); + const { setWaitHeight } = useSquidNetworkHeight(); const registerWorkerContract = useRegisterFromWallet(); const registerVestingContract = useRegisterWorkerFromVestingContract(); diff --git a/src/api/contracts/worker-registration/useUnregisterWorker.ts b/src/api/contracts/worker-registration/useUnregisterWorker.ts index adda864..bea5a0a 100644 --- a/src/api/contracts/worker-registration/useUnregisterWorker.ts +++ b/src/api/contracts/worker-registration/useUnregisterWorker.ts @@ -8,7 +8,7 @@ import { useWriteContract, useClient } from 'wagmi'; import { VESTING_CONTRACT_ABI } from '@api/contracts/vesting.abi'; import { AccountType } from '@api/subsquid-network-squid'; -import { useSquidNetworkHeightHooks } from '@hooks/useSquidNetworkHeightHooks.ts'; +import { useSquidNetworkHeight } from '@hooks/useSquidNetworkHeightHooks'; import { useAccount } from '@network/useAccount'; import { useContracts } from '@network/useContracts.ts'; @@ -76,7 +76,7 @@ export function useUnregisterWorker() { const client = useClient(); const { address } = useAccount(); const [isLoading, setLoading] = useState(false); - const { setWaitHeight } = useSquidNetworkHeightHooks(); + const { setWaitHeight } = useSquidNetworkHeight(); const [error, setError] = useState(null); const unregisterWorkerFromWallet = useUnregisterWorkerFromWallet(); diff --git a/src/api/contracts/worker-registration/useUpdateWorker.ts b/src/api/contracts/worker-registration/useUpdateWorker.ts index 8e63707..5f3581f 100644 --- a/src/api/contracts/worker-registration/useUpdateWorker.ts +++ b/src/api/contracts/worker-registration/useUpdateWorker.ts @@ -7,7 +7,7 @@ import { waitForTransactionReceipt } from 'viem/actions'; import { useWriteContract, useClient } from 'wagmi'; import { AccountType } from '@api/subsquid-network-squid'; -import { useSquidNetworkHeightHooks } from '@hooks/useSquidNetworkHeightHooks.ts'; +import { useSquidNetworkHeight } from '@hooks/useSquidNetworkHeightHooks'; import { useAccount } from '@network/useAccount'; import { useContracts } from '@network/useContracts.ts'; @@ -79,7 +79,7 @@ export function useUpdateWorker() { const [error, setError] = useState(null); const [isLoading, setLoading] = useState(false); - const { setWaitHeight } = useSquidNetworkHeightHooks(); + const { setWaitHeight } = useSquidNetworkHeight(); const updateWorkerFromWallet = useUpdateWorkerFromWallet(); const updateWorkerFromVestingContract = useUpdateWorkerFromVestingContract(); diff --git a/src/api/contracts/worker-registration/useWithdrawWorker.ts b/src/api/contracts/worker-registration/useWithdrawWorker.ts index fed6b80..c72ac25 100644 --- a/src/api/contracts/worker-registration/useWithdrawWorker.ts +++ b/src/api/contracts/worker-registration/useWithdrawWorker.ts @@ -9,7 +9,7 @@ import { useWriteContract, useClient } from 'wagmi'; import { VESTING_CONTRACT_ABI } from '@api/contracts/vesting.abi'; import { UnregisterWorkerRequest } from '@api/contracts/worker-registration/useUnregisterWorker'; import { AccountType } from '@api/subsquid-network-squid'; -import { useSquidNetworkHeightHooks } from '@hooks/useSquidNetworkHeightHooks.ts'; +import { useSquidNetworkHeight } from '@hooks/useSquidNetworkHeightHooks'; import { useAccount } from '@network/useAccount'; import { useContracts } from '@network/useContracts.ts'; @@ -69,7 +69,7 @@ export function useWithdrawWorker() { const client = useClient(); const { address } = useAccount(); const [isLoading, setLoading] = useState(false); - const { setWaitHeight } = useSquidNetworkHeightHooks(); + const { setWaitHeight } = useSquidNetworkHeight(); const [error, setError] = useState(null); const withdrawWorkerFromWallet = useWithdrawWorkerFromWallet(); diff --git a/src/hooks/useSquidNetworkHeightHooks.ts b/src/hooks/useSquidNetworkHeightHooks.tsx similarity index 53% rename from src/hooks/useSquidNetworkHeightHooks.ts rename to src/hooks/useSquidNetworkHeightHooks.tsx index 1a26ec8..978056c 100644 --- a/src/hooks/useSquidNetworkHeightHooks.ts +++ b/src/hooks/useSquidNetworkHeightHooks.tsx @@ -1,15 +1,49 @@ -import { useEffect, useMemo } from 'react'; +import { + createContext, + PropsWithChildren, + useCallback, + useContext, + useEffect, + useMemo, +} from 'react'; import { logger } from '@logger'; import { useQueryClient } from '@tanstack/react-query'; import { max, partition } from 'lodash-es'; +import { useBlockNumber } from 'wagmi'; import { useSquidDataSource, useSquidNetworkHeightQuery } from '@api/subsquid-network-squid'; import { localStorageStringSerializer, useLocalStorageState } from '@hooks/useLocalStorageState'; type HeightHook = { height: number; invalidateQueries: unknown[] }; -export function useSquidNetworkHeightHooks() { +const SquidHeightContext = createContext<{ + currentHeight: number; + waitHeight: number; + heightHooks: HeightHook[]; + isLoading: boolean; + setWaitHeight: (height: bigint | string, invalidateQueries?: unknown[]) => void; +}>({ + currentHeight: 0, + waitHeight: 0, + isLoading: false, + heightHooks: [], + setWaitHeight: () => {}, +}); + +export function useSquidNetworkHeight() { + const { isLoading, currentHeight, waitHeight, setWaitHeight } = useContext(SquidHeightContext); + + return { + isLoading, + isWaiting: currentHeight < waitHeight, + currentHeight, + waitHeight, + setWaitHeight, + }; +} + +export function SquidHeightProvider({ children }: PropsWithChildren) { const queryClient = useQueryClient(); const dataSource = useSquidDataSource(); const [heightHooksRaw, setHeightHooksRaw] = useLocalStorageState('squid_height_hooks', { @@ -30,28 +64,14 @@ export function useSquidNetworkHeightHooks() { const heightHooks: HeightHook[] = useMemo(() => { try { return JSON.parse(heightHooksRaw); - } catch (e: any) { - logger.error(`Cant parse json form squid_height_hooks: ${e.message}`); + } catch (e: unknown) { + logger.error( + `Cant parse json form squid_height_hooks: ${e instanceof Error ? e.message : e}`, + ); return []; } }, [heightHooksRaw]); - const maxWaitedHook = useMemo(() => { - return max(heightHooks.map(h => h.height)) || 0; - }, [heightHooks]); - - const setWaitHeight = useMemo(() => { - return (height: bigint | string, invalidateQueries: unknown[] = []) => { - heightHooks.push({ - height: Number(height), - invalidateQueries: invalidateQueries, - }); - heightHooks.splice(0, heightHooks.length - 10); - - setHeightHooksRaw(JSON.stringify(heightHooks)); - }; - }, [heightHooks, setHeightHooksRaw]); - useEffect(() => { const [notReady, ready] = partition(heightHooks, hook => hook.height > currentHeight); if (!ready.length) return; @@ -69,11 +89,43 @@ export function useSquidNetworkHeightHooks() { }); }, [currentHeight, heightHooks, queryClient, setHeightHooksRaw]); - return { - isLoading, - isWaiting: heightHooks.length > 0, - waitHeight: maxWaitedHook, - currentHeight: currentHeight ? String(currentHeight) : '0', - setWaitHeight, - }; + const setWaitHeight = useCallback( + (height: bigint | string, invalidateQueries: unknown[] = []) => { + heightHooks.push({ + height: Number(height), + invalidateQueries: invalidateQueries, + }); + heightHooks.splice(0, heightHooks.length - 10); + + setHeightHooksRaw(JSON.stringify(heightHooks)); + }, + [heightHooks, setHeightHooksRaw], + ); + + const maxWaitHeight = useMemo(() => { + return max(heightHooks.map(h => h.height)) || 0; + }, [heightHooks]); + + const { data: chainHeight } = useBlockNumber(); + useEffect(() => { + if (isLoading) return; + + if (chainHeight && BigInt(currentHeight) < chainHeight && maxWaitHeight < chainHeight) { + setWaitHeight(chainHeight); + } + }, [chainHeight, currentHeight, heightHooks, isLoading, maxWaitHeight, setWaitHeight]); + + return ( + + {children} + + ); } diff --git a/src/layouts/NetworkLayout/NetworkLayout.tsx b/src/layouts/NetworkLayout/NetworkLayout.tsx index 38a1960..f6ece59 100644 --- a/src/layouts/NetworkLayout/NetworkLayout.tsx +++ b/src/layouts/NetworkLayout/NetworkLayout.tsx @@ -14,12 +14,11 @@ import { import { alpha } from '@mui/system/colorManipulator'; import classnames from 'classnames'; import { Outlet } from 'react-router-dom'; -import { useDisconnect, useWalletClient, useBlockNumber } from 'wagmi'; +import { useDisconnect, useWalletClient } from 'wagmi'; import { Logo } from '@components/Logo'; // import { NetworkSwitcher } from '@components/NetworkSwitcher'; import { TopBanner, useBannerHeight } from '@components/TopBanner'; -import { useSquidNetworkHeightHooks } from '@hooks/useSquidNetworkHeightHooks'; import { MenuIcon } from '@icons/MenuIcon'; import { useAccount } from '@network/useAccount'; import { getChainId, getSubsquidNetwork } from '@network/useSubsquidNetwork'; @@ -269,14 +268,6 @@ export const NetworkLayout = ({ const { disconnect } = useDisconnect(); const network = getSubsquidNetwork(); - const { data: chainHeight } = useBlockNumber(); - const { - currentHeight: squidHeight, - waitHeight: waitSquidHeight, - setWaitHeight, - isLoading, - } = useSquidNetworkHeightHooks(); - useEffect(() => { if (!isConnected || walletClient.isLoading) return; if (chain?.id === getChainId(network)) return; @@ -284,13 +275,6 @@ export const NetworkLayout = ({ disconnect(); }, [isConnected, chain, disconnect, walletClient, network]); - useEffect(() => { - if (isLoading) return; - if (chainHeight && BigInt(squidHeight) < chainHeight && waitSquidHeight < chainHeight) { - setWaitHeight(chainHeight); - } - }, [chainHeight, isLoading, setWaitHeight, squidHeight, waitSquidHeight]); - const centeredSx = { alignSelf: stretchContent ? 'stretch' : 'flex-start', }; diff --git a/src/layouts/NetworkLayout/SyncSquidSnackbar.tsx b/src/layouts/NetworkLayout/SyncSquidSnackbar.tsx index b9d1ec5..bba1a08 100644 --- a/src/layouts/NetworkLayout/SyncSquidSnackbar.tsx +++ b/src/layouts/NetworkLayout/SyncSquidSnackbar.tsx @@ -2,10 +2,10 @@ import React from 'react'; import { Box, CircularProgress, Paper, Stack } from '@mui/material'; -import { useSquidNetworkHeightHooks } from '@hooks/useSquidNetworkHeightHooks'; +import { useSquidNetworkHeight } from '@hooks/useSquidNetworkHeightHooks'; export const SyncSquidSnackbar = () => { - const { isWaiting, waitHeight, currentHeight } = useSquidNetworkHeightHooks(); + const { isWaiting, waitHeight, currentHeight } = useSquidNetworkHeight(); if (!isWaiting) return null;