-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Change
useEffect
to useEvent
to change on swaps
but maintain a …
…stable reference to `props.data.symbol` and `queryClient` Move grace period message to the top of the file Put the `canTrade` logic into a `useMemo` Add `numSwaps` to the `SwapButton` props so it re-renders properly when the # of swaps changes ready Clean up and consolidate hook logic, decouple the fetch logic from display interval logic Disable `useQuery` hook from fetching once the market is not in grace period
- Loading branch information
Showing
4 changed files
with
122 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 107 additions & 10 deletions
117
src/typescript/frontend/src/lib/hooks/queries/use-grace-period.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,115 @@ | ||
import { getRegistrationGracePeriodFlag } from "@sdk/markets"; | ||
import { getRegistrationGracePeriodFlag } from "@sdk/markets/utils"; | ||
import { standardizeAddress } from "@sdk/utils/account-address"; | ||
import { useQuery } from "@tanstack/react-query"; | ||
import { useEventStore } from "context/event-store-context"; | ||
import { useAptos } from "context/wallet-context/AptosContextProvider"; | ||
import { useEffect, useMemo, useState } from "react"; | ||
|
||
export const useGracePeriod = (symbol: string) => { | ||
// ------------------------------------------------------------------------------------------------- | ||
// | ||
// Utilities for calculating the number of seconds left. | ||
// | ||
// ------------------------------------------------------------------------------------------------- | ||
const nowSeconds = () => Math.floor(new Date().getTime() / 1000); | ||
|
||
const calculateSecondsLeft = (marketRegistrationTime: bigint) => { | ||
const registrationTime = marketRegistrationTime; | ||
const asSeconds = Math.floor(Number(registrationTime / 1_000_000n)); | ||
const plusFiveMinutes = asSeconds + 300; | ||
return Math.max(plusFiveMinutes - nowSeconds(), 0); | ||
}; | ||
|
||
const formattedTimeLeft = (secondsRemaining: number) => { | ||
const remainder = secondsRemaining % 60; | ||
const minutes = Math.floor(secondsRemaining / 60); | ||
return `${minutes.toString().padStart(2, "0")}:${remainder.toString().padStart(2, "0")}` as const; | ||
}; | ||
|
||
// ------------------------------------------------------------------------------------------------- | ||
// | ||
// Hook to force the component to re-render on an interval basis. | ||
// | ||
// ------------------------------------------------------------------------------------------------- | ||
const useDisplayTimeLeft = (marketRegistrationTime?: bigint) => { | ||
const [timeLeft, setTimeLeft] = useState<ReturnType<typeof formattedTimeLeft>>(); | ||
|
||
useEffect(() => { | ||
const interval = setInterval(() => { | ||
if (typeof marketRegistrationTime === "undefined") { | ||
setTimeLeft(undefined); | ||
return; | ||
} | ||
const secondsLeft = calculateSecondsLeft(marketRegistrationTime); | ||
const formatted = formattedTimeLeft(secondsLeft); | ||
setTimeLeft(formatted); | ||
}, 100); | ||
|
||
return () => clearInterval(interval); | ||
}, [marketRegistrationTime]); | ||
|
||
return timeLeft; | ||
}; | ||
|
||
// ------------------------------------------------------------------------------------------------- | ||
// | ||
// `useQuery` hook that fetches the grace period status on an interval basis. | ||
// | ||
// ------------------------------------------------------------------------------------------------- | ||
const useGracePeriod = (symbol: string, hasSwaps: boolean) => { | ||
const { aptos } = useAptos(); | ||
const [keepFetching, setKeepFetching] = useState(true); | ||
|
||
return useQuery({ | ||
// Include the seconds left in the query result to trigger re-renders upon each fetch. | ||
const query = useQuery({ | ||
queryKey: ["grace-period", symbol], | ||
queryFn: () => { | ||
return getRegistrationGracePeriodFlag({ | ||
aptos, | ||
symbol, | ||
}); | ||
}, | ||
staleTime: 2000, | ||
refetchInterval: 2000, | ||
refetchIntervalInBackground: true, | ||
enabled: keepFetching, | ||
queryFn: async () => getRegistrationGracePeriodFlag({ aptos, symbol }), | ||
}); | ||
|
||
// Stop fetching once the market has clearly been registered. | ||
useEffect(() => { | ||
const notInGracePeriod = query.data?.gracePeriodOver || hasSwaps; | ||
if (notInGracePeriod) { | ||
setKeepFetching(false); | ||
} | ||
}, [query.data?.gracePeriodOver, hasSwaps]); | ||
|
||
return query; | ||
}; | ||
|
||
// ------------------------------------------------------------------------------------------------- | ||
// | ||
// The actual hook to be used in a component to display the amount of seconds left. | ||
// | ||
// ------------------------------------------------------------------------------------------------- | ||
export const useCanTradeMarket = (symbol: string) => { | ||
const { account } = useAptos(); | ||
const hasSwaps = useEventStore((s) => (s.markets.get(symbol)?.swapEvents.length ?? 0) > 0); | ||
const { isLoading, data } = useGracePeriod(symbol, hasSwaps); | ||
|
||
const { canTrade, marketRegistrationTime } = useMemo(() => { | ||
const notInGracePeriod = data?.gracePeriodOver; | ||
const userAddress = account?.address && standardizeAddress(account.address); | ||
// Assume the user is the market registrant while the query is fetching in order to prevent | ||
// disallowing the actual registrant from trading while the query result is being fetched. | ||
const userIsRegistrant = data?.flag?.marketRegistrant === userAddress; | ||
return { | ||
canTrade: isLoading || userIsRegistrant || notInGracePeriod || hasSwaps, | ||
marketRegistrationTime: data?.flag?.marketRegistrationTime, | ||
}; | ||
}, [isLoading, data, account?.address, hasSwaps]); | ||
|
||
const displayTimeLeft = useDisplayTimeLeft(marketRegistrationTime); | ||
|
||
return typeof displayTimeLeft === "undefined" || canTrade | ||
? { | ||
canTrade: true as const, | ||
displayTimeLeft: undefined, | ||
} | ||
: { | ||
canTrade: false as const, | ||
displayTimeLeft, | ||
}; | ||
}; |