From 7c2043c15ac5b0a63d2194c8ab15fd5a3e1418a6 Mon Sep 17 00:00:00 2001 From: Matthew Pereira Date: Wed, 11 Dec 2024 17:04:59 -0800 Subject: [PATCH] handle disconnect during pending create pool tx --- .../app/v3/_components/PoolConfiguration.tsx | 7 ++- .../nextjs/hooks/v3/useBoostableWhitelist.ts | 2 - packages/nextjs/hooks/v3/useCreatePool.ts | 62 +++++++++++++------ .../nextjs/hooks/v3/usePoolCreationStore.ts | 6 +- 4 files changed, 50 insertions(+), 27 deletions(-) diff --git a/packages/nextjs/app/v3/_components/PoolConfiguration.tsx b/packages/nextjs/app/v3/_components/PoolConfiguration.tsx index c6fd9c8f..2d83e314 100644 --- a/packages/nextjs/app/v3/_components/PoolConfiguration.tsx +++ b/packages/nextjs/app/v3/_components/PoolConfiguration.tsx @@ -9,7 +9,7 @@ import { TABS, type TabType, usePoolCreationStore, useValidatePoolCreationInput import { bgBeigeGradient } from "~~/utils"; export function PoolConfiguration() { - const { selectedTab, updatePool, step } = usePoolCreationStore(); + const { selectedTab, updatePool, createPoolTxHash } = usePoolCreationStore(); const { targetNetwork } = useTargetNetwork(); const [isPoolCreationModalOpen, setIsPoolCreationModalOpen] = useState(false); const { prev, next } = getAdjacentTabs(selectedTab); @@ -44,9 +44,10 @@ export function PoolConfiguration() { }; } + // Force modal to open if user has already sent "Deploy Pool" transaction (always step 1) useEffect(() => { - if (step > 1) setIsPoolCreationModalOpen(true); - }, [step]); + if (createPoolTxHash) setIsPoolCreationModalOpen(true); + }, [createPoolTxHash]); return ( <> diff --git a/packages/nextjs/hooks/v3/useBoostableWhitelist.ts b/packages/nextjs/hooks/v3/useBoostableWhitelist.ts index d1b55ed0..85ea97ab 100644 --- a/packages/nextjs/hooks/v3/useBoostableWhitelist.ts +++ b/packages/nextjs/hooks/v3/useBoostableWhitelist.ts @@ -68,8 +68,6 @@ export const useBoostableWhitelist = () => { const data = json.data.tokenGetTokens; - console.log("data", data); - // Create map of underlying token address to matching boosted variant info const boostableTokensMap = data.reduce((acc: Record, token: Token) => { if (token.underlyingTokenAddress) acc[token.underlyingTokenAddress] = token; diff --git a/packages/nextjs/hooks/v3/useCreatePool.ts b/packages/nextjs/hooks/v3/useCreatePool.ts index 5f7ecfde..e4bdfec9 100644 --- a/packages/nextjs/hooks/v3/useCreatePool.ts +++ b/packages/nextjs/hooks/v3/useCreatePool.ts @@ -1,3 +1,4 @@ +import { useEffect } from "react"; import { CreatePool, CreatePoolV3BaseInput, @@ -10,7 +11,7 @@ import { import { useMutation } from "@tanstack/react-query"; import { parseEventLogs, parseUnits, zeroAddress } from "viem"; import { usePublicClient, useWalletClient } from "wagmi"; -import { useTransactor } from "~~/hooks/scaffold-eth"; +// import { useTransactor } from "~~/hooks/scaffold-eth"; import { useBoostableWhitelist, usePoolCreationStore } from "~~/hooks/v3"; const poolFactoryAbi = { @@ -24,7 +25,8 @@ const TOKEN_WEIGHT_DECIMALS = 16; export const useCreatePool = () => { const { data: walletClient } = useWalletClient(); const publicClient = usePublicClient(); - const writeTx = useTransactor(); + // const writeTx = useTransactor(); + const { tokenConfigs, name, @@ -38,8 +40,34 @@ export const useCreatePool = () => { disableUnbalancedLiquidity, amplificationParameter, updatePool, + createPoolTxHash, + step, } = usePoolCreationStore(); + const { data: boostableWhitelist } = useBoostableWhitelist(); + + // If user disconnects during pending tx state, this will look up tx receipt based on tx hash saved in local storage immediately after tx is sent (i.e. right after button is clicked) + useEffect(() => { + async function getTxReceipt() { + if (!publicClient || !createPoolTxHash || poolType === undefined || step !== 1) return; + + const txReceipt = await publicClient.waitForTransactionReceipt({ hash: createPoolTxHash }); + + const logs = parseEventLogs({ + abi: poolFactoryAbi[poolType], + logs: txReceipt.logs, + }); + + if (logs.length > 0 && "args" in logs[0] && "pool" in logs[0].args) { + const newPool = logs[0].args.pool; + updatePool({ poolAddress: newPool, step: 2 }); + } else { + throw new Error("Expected pool address not found in event logs"); + } + } + getTxReceipt(); + }, [createPoolTxHash, publicClient, poolType, updatePool, step]); + function createPoolInput(poolType: PoolType): CreatePoolV3StableInput | CreatePoolV3WeightedInput { if (poolType === undefined) throw new Error("No pool type provided!"); if (!publicClient) throw new Error("Public client must be available!"); @@ -88,30 +116,26 @@ export const useCreatePool = () => { const input = createPoolInput(poolType); const call = createPool.buildCall(input); - const hash = await writeTx( - () => - walletClient.sendTransaction({ - account: walletClient.account, - data: call.callData, - to: call.to, - }), - { - blockConfirmations: 1, - onBlockConfirmation: () => { - console.log("Successfully deployed and registered a balancer v3 pool!"); - }, - }, - ); + // Not using transactor here because we need to immediately save tx hash to local storage for zen dragon edge case + // He sends transactions with low gas limit which means they stay pending for hours + const hash = await walletClient.sendTransaction({ + account: walletClient.account, + data: call.callData, + to: call.to, + }); + if (!hash) throw new Error("Failed to generate pool creation transaction hash"); + + updatePool({ createPoolTxHash: hash }); - if (!hash) throw new Error("No pool creation transaction hash"); - const txReceipt = await publicClient.getTransactionReceipt({ hash }); + const txReceipt = await publicClient.waitForTransactionReceipt({ hash }); const logs = parseEventLogs({ abi: poolFactoryAbi[poolType], logs: txReceipt.logs, }); + if (logs.length > 0 && "args" in logs[0] && "pool" in logs[0].args) { const newPool = logs[0].args.pool; - updatePool({ poolAddress: newPool, createPoolTxHash: hash, step: 2 }); + updatePool({ poolAddress: newPool, step: 2 }); } else { throw new Error("Expected pool address not found in event logs"); } diff --git a/packages/nextjs/hooks/v3/usePoolCreationStore.ts b/packages/nextjs/hooks/v3/usePoolCreationStore.ts index 8878c3df..94c45f85 100644 --- a/packages/nextjs/hooks/v3/usePoolCreationStore.ts +++ b/packages/nextjs/hooks/v3/usePoolCreationStore.ts @@ -45,9 +45,9 @@ export interface PoolCreationStore { disableUnbalancedLiquidity: boolean; enableDonation: boolean; amplificationParameter: string; - createPoolTxHash: string | undefined; - swapTxHash: string | undefined; - initPoolTxHash: string | undefined; + createPoolTxHash: `0x${string}` | undefined; + swapTxHash: `0x${string}` | undefined; + initPoolTxHash: `0x${string}` | undefined; updatePool: (updates: Partial) => void; updateTokenConfig: (index: number, updates: Partial) => void; clearPoolStore: () => void;