diff --git a/apps/cow-amm-deployer/src/app/amm/(components)/CreateAmmForm.tsx b/apps/cow-amm-deployer/src/app/amm/(components)/CreateAmmForm.tsx index 9f39c186d..3bcc7b8de 100644 --- a/apps/cow-amm-deployer/src/app/amm/(components)/CreateAmmForm.tsx +++ b/apps/cow-amm-deployer/src/app/amm/(components)/CreateAmmForm.tsx @@ -78,7 +78,7 @@ export function CreateAmmForm() { await createAMMArgs(data).then((txArgs) => { sendTransactions(txArgs); }); - router.push("/amm"); + router.push("/amm/createtxprocessing"); }; useEffect(() => { diff --git a/apps/cow-amm-deployer/src/app/amm/createtxprocessing/layout.tsx b/apps/cow-amm-deployer/src/app/amm/createtxprocessing/layout.tsx new file mode 100644 index 000000000..c1492b79b --- /dev/null +++ b/apps/cow-amm-deployer/src/app/amm/createtxprocessing/layout.tsx @@ -0,0 +1,3 @@ +export default function Layout({ children }: { children: React.ReactNode }) { + return children; +} diff --git a/apps/cow-amm-deployer/src/app/amm/createtxprocessing/page.tsx b/apps/cow-amm-deployer/src/app/amm/createtxprocessing/page.tsx new file mode 100644 index 000000000..ecae66a49 --- /dev/null +++ b/apps/cow-amm-deployer/src/app/amm/createtxprocessing/page.tsx @@ -0,0 +1,46 @@ +"use client"; + +import { useSafeAppsSDK } from "@gnosis.pm/safe-apps-react-sdk"; +import { useRouter } from "next/navigation"; +import { useEffect } from "react"; +import { Address } from "viem"; + +import { Spinner } from "#/components/Spinner"; +import { checkIsAmmRunning, fetchLastAmmInfo } from "#/hooks/useRunningAmmInfo"; +import { ChainId } from "#/utils/chainsPublicClients"; + +export default function Page() { + const { + safe: { safeAddress, chainId }, + } = useSafeAppsSDK(); + const router = useRouter(); + + async function redirectToHomeIfAmmIsRunningAndIndexed() { + const [isAmmRunning, cowAmmDataIndexed] = await Promise.all([ + checkIsAmmRunning(chainId as ChainId, safeAddress as Address), + fetchLastAmmInfo({ + chainId: chainId as ChainId, + safeAddress: safeAddress as Address, + }), + ]); + if (isAmmRunning && cowAmmDataIndexed) { + router.push("/amm"); + } + } + useEffect(() => { + const intervalId = setInterval( + redirectToHomeIfAmmIsRunningAndIndexed, + 1000, + ); + return () => clearInterval(intervalId); + }, []); + + return ( +
+
+ The transaction is being processed +
+ +
+ ); +} diff --git a/apps/cow-amm-deployer/src/app/amm/page.tsx b/apps/cow-amm-deployer/src/app/amm/page.tsx index bb697f4f6..80e94961d 100644 --- a/apps/cow-amm-deployer/src/app/amm/page.tsx +++ b/apps/cow-amm-deployer/src/app/amm/page.tsx @@ -124,7 +124,7 @@ export default function Page() { chainId: safe.chainId as ChainId, }, ]); - router.refresh(); + router.push("/amm/stoptxprocessing"); }} > Confirm diff --git a/apps/cow-amm-deployer/src/app/amm/stoptxprocessing/layout.tsx b/apps/cow-amm-deployer/src/app/amm/stoptxprocessing/layout.tsx new file mode 100644 index 000000000..c1492b79b --- /dev/null +++ b/apps/cow-amm-deployer/src/app/amm/stoptxprocessing/layout.tsx @@ -0,0 +1,3 @@ +export default function Layout({ children }: { children: React.ReactNode }) { + return children; +} diff --git a/apps/cow-amm-deployer/src/app/amm/stoptxprocessing/page.tsx b/apps/cow-amm-deployer/src/app/amm/stoptxprocessing/page.tsx new file mode 100644 index 000000000..fc3610f1b --- /dev/null +++ b/apps/cow-amm-deployer/src/app/amm/stoptxprocessing/page.tsx @@ -0,0 +1,40 @@ +"use client"; + +import { useSafeAppsSDK } from "@gnosis.pm/safe-apps-react-sdk"; +import { useRouter } from "next/navigation"; +import { useEffect } from "react"; +import { Address } from "viem"; + +import { Spinner } from "#/components/Spinner"; +import { checkIsAmmRunning } from "#/hooks/useRunningAmmInfo"; +import { ChainId } from "#/utils/chainsPublicClients"; + +export default function Page() { + const { + safe: { safeAddress, chainId }, + } = useSafeAppsSDK(); + const router = useRouter(); + + async function redirectToHomeIfAmmIsNotRunning() { + const isAmmRunning = await checkIsAmmRunning( + chainId as ChainId, + safeAddress as Address, + ); + if (!isAmmRunning) { + router.push("/amm"); + } + } + useEffect(() => { + const intervalId = setInterval(redirectToHomeIfAmmIsNotRunning, 1000); + return () => clearInterval(intervalId); + }, []); + + return ( +
+
+ The transaction is being processed +
+ +
+ ); +} diff --git a/apps/cow-amm-deployer/src/hooks/useRunningAmmInfo.ts b/apps/cow-amm-deployer/src/hooks/useRunningAmmInfo.ts index 6161e52ad..e970f8e13 100644 --- a/apps/cow-amm-deployer/src/hooks/useRunningAmmInfo.ts +++ b/apps/cow-amm-deployer/src/hooks/useRunningAmmInfo.ts @@ -21,7 +21,7 @@ gql(` where: {user: $userId, handler: $handler} limit: 1 orderBy: "blockNumber" - orderDirection: "asc" + orderDirection: "desc" ) { items { id @@ -55,7 +55,7 @@ gql(` } `); -const NULL_ACTIVE_ORDER = +export const NULL_ACTIVE_ORDER = "0x0000000000000000000000000000000000000000000000000000000000000000" as const; export async function fetchLastAmmInfo({ @@ -70,7 +70,7 @@ export async function fetchLastAmmInfo({ handler: COW_AMM_HANDLER_ADDRESS[chainId as ChainId], }); - const order = orders.items[0]; + const order = orders?.items?.[0]; if (!order || !order.decodedSuccess) return; return decodePriceOracle({ cowAmmParameters: order.cowAmmParameters }); @@ -85,6 +85,7 @@ export const ADDRESSES_PRICE_ORACLES = { export async function decodePriceOracle({ cowAmmParameters, }: { + // @ts-ignore cowAmmParameters: UserCurrentAmmQuery["orders"]["items"][0]["cowAmmParameters"]; }) { const priceOracle = @@ -127,7 +128,10 @@ export function decodePriceOracleData({ throw new Error("Unknown price oracle"); } -export async function checkAmmRunning(chainId: ChainId, safeAddress: Address) { +export async function checkIsAmmRunning( + chainId: ChainId, + safeAddress: Address, +) { const publicClient = publicClientsFromIds[chainId]; return publicClient .readContract({ @@ -146,6 +150,7 @@ export function useRunningAMM(): { loaded: boolean; isAmmRunning: boolean; error: boolean; + updateAmmInfo: () => Promise; } { const { safe: { safeAddress, chainId }, @@ -157,53 +162,60 @@ export function useRunningAMM(): { const [error, setError] = useState(false); const { assets } = useSafeBalances(); - useEffect(() => { - async function loadCowAmm() { - try { - const [gqlInfo, newIsAmmRunning] = await Promise.all([ - fetchLastAmmInfo({ - chainId: chainId as ChainId, - safeAddress: safeAddress as Address, - }), - checkAmmRunning(chainId as ChainId, safeAddress as Address), - ]); - - const token0 = assets.find( - (asset) => - asset.tokenInfo.address.toLowerCase() === - gqlInfo?.token0?.address.toLowerCase(), - ); - const token1 = assets.find( - (asset) => - asset.tokenInfo.address.toLowerCase() === - gqlInfo?.token1?.address.toLowerCase(), - ); - - if (!token0 || !token1) { - setLoaded(true); - return; - } + async function loadCoWAmmRunning() { + const newIsAmmRunning = await checkIsAmmRunning( + chainId as ChainId, + safeAddress as Address, + ); + setIsAmmRunning(newIsAmmRunning); + } - const totalUsdValue = - (Number(token0.fiatBalance) || 0) + (Number(token1.fiatBalance) || 0); - - setCowAmm({ - token0, - token1, - totalUsdValue, - minTradedToken0: gqlInfo?.minTradedToken0 as number, - priceOracle: gqlInfo?.priceOracleType as PRICE_ORACLES, - priceOracleData: gqlInfo?.priceOracleDataDecoded as PriceOracleData, - }); - setIsAmmRunning(newIsAmmRunning); - } catch (e) { - setError(true); - } - setLoaded(true); + async function loadCowAmm() { + const gqlInfo = await fetchLastAmmInfo({ + chainId: chainId as ChainId, + safeAddress: safeAddress as Address, + }); + + const token0 = assets.find( + (asset) => + asset.tokenInfo.address.toLowerCase() === + gqlInfo?.token0?.address.toLowerCase(), + ); + const token1 = assets.find( + (asset) => + asset.tokenInfo.address.toLowerCase() === + gqlInfo?.token1?.address.toLowerCase(), + ); + + if (!token0 || !token1) { + return; } - loadCowAmm(); + const totalUsdValue = + (Number(token0.fiatBalance) || 0) + (Number(token1.fiatBalance) || 0); + + setCowAmm({ + token0, + token1, + totalUsdValue, + minTradedToken0: gqlInfo?.minTradedToken0 as number, + priceOracle: gqlInfo?.priceOracleType as PRICE_ORACLES, + priceOracleData: gqlInfo?.priceOracleDataDecoded as PriceOracleData, + }); + } + + async function updateAmmInfo(): Promise { + setLoaded(false); + setError(false); + await Promise.all([loadCoWAmmRunning(), loadCowAmm()]).catch(() => { + setError(true); + }); + setLoaded(true); + } + + useEffect(() => { + updateAmmInfo(); }, [safeAddress, chainId, assets]); - return { cowAmm, loaded, isAmmRunning, error }; + return { cowAmm, loaded, isAmmRunning, error, updateAmmInfo }; }