Where
examples/widget/src/lib/hooks/useOrderSubmit.ts:
|
await new Promise<void>((resolve) => { |
|
const checkTx = setInterval(() => { |
|
if (!isWaitingForTx) { |
|
clearInterval(checkTx); |
|
resolve(); |
|
} |
|
}, 1000); |
|
}); |
After sending the approval transaction, the hook tries to wait for confirmation before signing/submitting the order:
const { isLoading: isWaitingForTx } = useWaitForTransactionReceipt({ hash: txHash });
...
setTxHash(hash);
// Wait for transaction confirmation
await new Promise<void>((resolve) => {
const checkTx = setInterval(() => {
if (!isWaitingForTx) {
clearInterval(checkTx);
resolve();
}
}, 1000);
});
Problem
isWaitingForTx is captured by the running submit() closure. When submit() is invoked, txHash is still undefined, so the receipt query is disabled and isWaitingForTx is false:
- wagmi
useWaitForTransactionReceipt sets enabled = Boolean(hash && (query.enabled ?? true)), so with hash === undefined the query is disabled.
- For a disabled query, TanStack returns
isLoading = isPending && isFetching, and isFetching is false (fetchStatus is idle), so isLoading (i.e. isWaitingForTx) is false.
The setInterval callback keeps reading that stale false (a later re-render creates a new closure, but the already-running invocation never sees it), so the promise resolves on the very first tick (~1s) regardless of whether the approval tx has been mined. Signing and submitting the order then proceeds before the approval is confirmed on-chain.
(Conversely, if the captured value were ever true, the loop would never resolve and submit() would hang. So the wait is broken either way.) This is standard JS closure behavior and does not depend on the wagmi version.
Suggested fix
Await the receipt directly instead of polling a captured React value, for example with the viem public client:
import { usePublicClient } from "wagmi";
// ...
const publicClient = usePublicClient();
// ...
if (approvalAction) {
setStep("approval");
const hash = await sendTransactionAsync({ /* ... */ });
setTxHash(hash);
await publicClient.waitForTransactionReceipt({ hash }); // actually waits
}
Alternatively, drive the next step from a useEffect on the hook's isSuccess. Either approach removes the stale-closure polling.
Where
examples/widget/src/lib/hooks/useOrderSubmit.ts:trading-engine-api-example/examples/widget/src/lib/hooks/useOrderSubmit.ts
Lines 79 to 86 in 3dcbc58
After sending the approval transaction, the hook tries to wait for confirmation before signing/submitting the order:
Problem
isWaitingForTxis captured by the runningsubmit()closure. Whensubmit()is invoked,txHashis stillundefined, so the receipt query is disabled andisWaitingForTxisfalse:useWaitForTransactionReceiptsetsenabled = Boolean(hash && (query.enabled ?? true)), so withhash === undefinedthe query is disabled.isLoading = isPending && isFetching, andisFetchingisfalse(fetchStatus is idle), soisLoading(i.e.isWaitingForTx) isfalse.The
setIntervalcallback keeps reading that stalefalse(a later re-render creates a new closure, but the already-running invocation never sees it), so the promise resolves on the very first tick (~1s) regardless of whether the approval tx has been mined. Signing and submitting the order then proceeds before the approval is confirmed on-chain.(Conversely, if the captured value were ever
true, the loop would never resolve andsubmit()would hang. So the wait is broken either way.) This is standard JS closure behavior and does not depend on the wagmi version.Suggested fix
Await the receipt directly instead of polling a captured React value, for example with the viem public client:
Alternatively, drive the next step from a
useEffecton the hook'sisSuccess. Either approach removes the stale-closure polling.