Skip to content

fix(connectkit): payin detection reliability, checkout appId resolution, and wallet auto-connect gate#44

Merged
akbarsaputrait merged 18 commits into
masterfrom
fix/wallet-autoconnect-gate
Jul 7, 2026
Merged

fix(connectkit): payin detection reliability, checkout appId resolution, and wallet auto-connect gate#44
akbarsaputrait merged 18 commits into
masterfrom
fix/wallet-autoconnect-gate

Conversation

@akbarsaputrait

@akbarsaputrait akbarsaputrait commented Jul 4, 2026

Copy link
Copy Markdown
Member

Summary

Three independent payment-reliability fixes bundled on this branch:

  1. Auto-connect race in wallet in-app browsers (Phantom, Base App, MetaMask mobile) — modal flashed/stuck on SELECT_METHOD instead of auto-navigating to SELECT_TOKEN when a wallet was already connected.
  2. Missed deposit-address payinsWaitingDepositAddress relied solely on Pusher push events with no fallback if Pusher missed the event.
  3. missingAppId in checkout mode — payId-based checkout (no appId in payParams) hit getFee/deeplink failures because several call sites read payParams?.appId directly instead of falling back to order.metadata.appId.

Changes Made

Auto-connect readiness gate

  • useAutoConnectGate composes wallet-connection status + FSM state into gateState: "pass" | "waiting" | "ready" | "error".
  • Modal effect waits on "waiting", routes to Error page on "error" (new safety net), navigates on "ready", leaves tiles on "pass".
  • Readiness = any non-idle, non-error FSM state — covers unhydrated (public setPayId resume) and payout_completed.
  • SelectMethod shows the existing spinner while "waiting" — no tile flash.

Payin poll fallback

  • New usePayinPolling hook: 1s-interval poll of getPayment(...).data.source.txHash, parity with Pusher's source_txhash payload.
  • WaitingDepositAddress starts on Pusher; after 60s without detection, flips to poll fallback. Detection from either path runs through one handlePayinDetected, guarded by a ref so it fires once.
  • Poll state resets cleanly when disabled or the active deposit payment id changes, so a stale hash can't leak into a later deposit.

Checkout-mode appId resolution

  • Added resolveOrderAppId fallback (payParams.appId ?? order.metadata.appId) at fee-calculation and deeplink-generation call sites that read payParams?.appId directly: PayWithToken, PayWithSolanaToken, PayWithStellarToken, WaitingDepositAddress, and invoice deeplink generation in usePaymentState.
  • These components now read fresh order state from the store at calculation time instead of a closed-over order reference (stale-state pattern, CLAUDE.md §5).

Releases bundled on this branch

  • v0.1.32 — autoconnect gate + payin poll fallback (tag was missing on origin, retroactively created on 1511be69 and pushed).
  • v0.1.33 — appId/fresh-order-state fixes.

How to Test

  1. Auto-connect: open pay modal inside Phantom/Base App/MetaMask mobile in-app browser with wallet already connected. Should land directly on SELECT_TOKEN, no flash, no hang.
  2. Payin poll fallback: start a deposit-address payment, block/delay the Pusher event, confirm flow still completes via polling within ~60s + poll interval.
  3. Checkout mode appId: run payId-only checkout (no appId in payParams) with Stellar USDC, confirm fee calculation succeeds and wallet deeplink includes resolved appId.
  4. Regression-check direct appId-based flows (EVM/Solana/Stellar) still resolve fees correctly.

Reviewer Notes

  • Residual known gap (documented, not fixed): showSolanaPaymentMethod/showStellarPaymentMethod still gate on pay.order != null for the tile-tap path (not auto-navigate), so a flash of SELECT_METHOD can still occur if wallet reconnect resolves before the preview order does.
  • Release commits (v0.1.32, v0.1.33) are bundled into this branch's history — flagging in case reviewers prefer them split out of feature PRs.
  • packages/connectkit/package.json currently at 0.1.33 on master; a further uncommitted bump/mismatch (0.1.33 vs example app's 0.1.33-beta.1) was seen locally but intentionally left out of this PR.

@vercel

vercel Bot commented Jul 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
intent-example Ready Ready Preview, Comment Jul 7, 2026 8:15am

Request Review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/connectkit/src/hooks/useAutoConnectGate.ts
@akbarsaputrait akbarsaputrait changed the title fix: stabilize wallet auto-connect → token selection with readiness gate Fix - stabilize wallet auto-connect → token selection with readiness gate Jul 5, 2026
shawnmuggle
shawnmuggle previously approved these changes Jul 5, 2026

@shawnmuggle shawnmuggle left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/reconnecting but connected still false), anyWalletConnected is 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 hoist walletSettling above the anyWalletConnected check to close it fully.
  • orderReady gates on paymentState !== idle/error rather than the stricter pay.order != null; a theoretical "non-idle but order undefined" state would navigate. Practically unreachable and SELECT_TOKEN only shows loading, doesn't crash.

@akbarsaputrait akbarsaputrait changed the title Fix - stabilize wallet auto-connect → token selection with readiness gate fix(connectkit): payin detection reliability, checkout appId resolution, and wallet auto-connect gate Jul 7, 2026

@shawnmuggle shawnmuggle left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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):

  1. 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.)

  2. 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`.

  3. 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.

@akbarsaputrait akbarsaputrait merged commit 462b5aa into master Jul 7, 2026
5 checks passed
@akbarsaputrait akbarsaputrait deleted the fix/wallet-autoconnect-gate branch July 7, 2026 14:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants