fix(connectkit): payin detection reliability, checkout appId resolution, and wallet auto-connect gate#44
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 833a9294d4
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
shawnmuggle
left a comment
There was a problem hiding this comment.
LGTM — no P0/P1 blockers. Two-pass review (local deep review + codex second opinion).
Scope note: the PR body describes only the useAutoConnectGate readiness gate, but this PR also adds the WaitingDepositAddress Pusher→polling 60s payin fallback (new usePayinPolling hook). Worth adding to the description for future auditability.
Verified OK: payin fallback run-once guard / double-unsubscribe idempotency / polling cleanup are all correct — no leak, no duplicate polling; order === error routes to ERROR (not treated as ready); solana/stellarPaymentEligible dropping the order gate is semantically safe (SELECT_TOKEN has its own loading state).
P2 (non-blocking, follow-up):
useAutoConnectGate— during the wallet reconnect window (connecting/reconnectingbutconnectedstill false),anyWalletConnectedis false →gateState="pass"→ SelectMethod briefly shows tiles instead of the spinner. Not a regression (original code flashed tiles here too; this PR improved the "connected-but-order-pending" window). Could hoistwalletSettlingabove theanyWalletConnectedcheck to close it fully.orderReadygates onpaymentState !== idle/errorrather than the stricterpay.order != null; a theoretical "non-idle but order undefined" state would navigate. Practically unreachable and SELECT_TOKEN only shows loading, doesn't crash.
shawnmuggle
left a comment
There was a problem hiding this comment.
LGTM ✅ — reviewed the full diff (1650+/118-, 6 source files) plus both design specs, cross-checked every changed hook/component against `master`, and ran an independent codex pass. No P0, no P1. Money-path is safe: the new `usePayinPolling` fires on `source.txHash` (exact parity with the Pusher path and `usePayoutPolling`), `handlePayinDetected` is run-once guarded, Pusher is unsubscribed before polling is enabled, and the appId fix (`bridge-utils.ts` copying top-level `order.appId` into `metadata.appId` → recovered via `resolveOrderAppId`/`stableAppId`) correctly fixes `missingAppId` in payId mode. Fee fetches reading `store.getState()` instead of a stale closure is correct. Concurrency/cleanup (60s fallback, reset-on-id-change, `isActive` guards, `clearTimeout`) all check out.
Non-blocking follow-ups (P2):
-
Auto-connect gate misses the reconnect-while-disconnected window — `useAutoConnectGate.ts:44`: `anyWalletConnected` is checked before `walletSettling`, so during wagmi `reconnecting`/`connecting` (when `isConnected` is still false) or Solana `connecting`, the gate returns `pass` and `SelectMethod` renders method tiles — the in-app-browser flash this PR targets still occurs in exactly that window. Not a regression (master behaved the same), but it's an incomplete fix of the spec's "never a SELECT_METHOD flash" goal. Fix: check `walletSettling` before the no-wallet `pass` branch, or fold settling into `waiting`. Caveat: that makes the no-wallet desktop case flash a spinner during wagmi's transient mount `reconnecting` — a real tradeoff the spec scoped out, so either address it or explicitly accept the tradeoff in the spec. (This is the same item the codex bot flagged — confirmed valid, correctly P2.)
-
Fee-quote `amount` vs `destToken` snapshot mix — `WaitingDepositAddress/index.tsx`: `amount` still derives from the closure `order` while `destToken`/`destReceiverAddress` now come from `store.getState()`. In payId mode the order loads once and is stable, so no real-world impact — but for full consistency `amount` should also derive from `currentOrder`.
-
Polled payin with `selectedDepositAddressOption == null` can strand the user — `WaitingDepositAddress/index.tsx` `handlePayinDetected` early-returns without routing on the underpayment/tron-underpay retry path, and polling has already stopped, so it won't re-fire. Pre-existing (master's Pusher callback had the identical guard), out of scope for this PR — worth a follow-up.
All three are non-blocking. Nice, well-specified change.
Summary
Three independent payment-reliability fixes bundled on this branch:
SELECT_METHODinstead of auto-navigating toSELECT_TOKENwhen a wallet was already connected.WaitingDepositAddressrelied solely on Pusher push events with no fallback if Pusher missed the event.missingAppIdin checkout mode — payId-based checkout (noappIdinpayParams) hitgetFee/deeplink failures because several call sites readpayParams?.appIddirectly instead of falling back toorder.metadata.appId.Changes Made
Auto-connect readiness gate
useAutoConnectGatecomposes wallet-connection status + FSM state intogateState: "pass" | "waiting" | "ready" | "error"."waiting", routes to Error page on"error"(new safety net), navigates on"ready", leaves tiles on"pass".idle, non-errorFSM state — coversunhydrated(publicsetPayIdresume) andpayout_completed.SelectMethodshows the existing spinner while"waiting"— no tile flash.Payin poll fallback
usePayinPollinghook: 1s-interval poll ofgetPayment(...).data.source.txHash, parity with Pusher'ssource_txhashpayload.WaitingDepositAddressstarts on Pusher; after 60s without detection, flips to poll fallback. Detection from either path runs through onehandlePayinDetected, guarded by a ref so it fires once.Checkout-mode
appIdresolutionresolveOrderAppIdfallback (payParams.appId ?? order.metadata.appId) at fee-calculation and deeplink-generation call sites that readpayParams?.appIddirectly:PayWithToken,PayWithSolanaToken,PayWithStellarToken,WaitingDepositAddress, and invoice deeplink generation inusePaymentState.orderreference (stale-state pattern, CLAUDE.md §5).Releases bundled on this branch
origin, retroactively created on1511be69and pushed).appId/fresh-order-state fixes.How to Test
SELECT_TOKEN, no flash, no hang.appIdinpayParams) with Stellar USDC, confirm fee calculation succeeds and wallet deeplink includes resolvedappId.appId-based flows (EVM/Solana/Stellar) still resolve fees correctly.Reviewer Notes
showSolanaPaymentMethod/showStellarPaymentMethodstill gate onpay.order != nullfor the tile-tap path (not auto-navigate), so a flash ofSELECT_METHODcan still occur if wallet reconnect resolves before the preview order does.packages/connectkit/package.jsoncurrently at0.1.33onmaster; a further uncommitted bump/mismatch (0.1.33vs example app's0.1.33-beta.1) was seen locally but intentionally left out of this PR.