fix: gate wallet connect button on real provider hydration - #2131
Open
arentant wants to merge 1 commit into
Open
fix: gate wallet connect button on real provider hydration#2131arentant wants to merge 1 commit into
arentant wants to merge 1 commit into
Conversation
The connect button treated a descriptor stub as connect-ready, so clicking one
opened the generic wallet modal instead of the destination's own connectors.
Gate it on real hydration instead, and consolidate the readiness logic that had
accumulated in three places.
Readiness:
- Add `isProviderHydrated` (fails closed) beside `isProviderConnectReady`
(fails open) and document the deliberate polarity difference.
- Collapse `useProvidersConnectReady`, `useConnectorSourcesStatus` and
`useWalletProviderReadiness` into wallet-core, replacing four inline
`isStub || !ready` predicates and three separate 5000ms deadlines with one
`PROVIDER_HYDRATION_TIMEOUT_MS`. The two ui-kit hooks move out of the
presentational layer.
- Split the module so the predicates stay React-free: `lib/providerReadiness.ts`
is importable from service classes (ParadexConnectionService) without pulling
in React or the context graph; the hooks live in `hooks/useProviderReadiness.ts`.
Neither belongs under `lib/walletConnect/` — they are about Layerswap's
WalletConnectionProvider, not the WalletConnect protocol.
connectWallet contract:
- `WalletConnectionProvider.connectWallet` now requires `{ connector }`. It
declared `props?` optional while every implementation needs one, and
`WalletModal.connect()` was the only caller invoking it bare — which threw
inside adapters that destructure the parameter, rejecting before the modal
opened and leaving the button stuck on "Connecting..." forever.
- Drop that call. It could only fire when a provider had zero connectors (with
even one, `hasConnectorPicker` is true), so there was never anything to pass.
Requiring the parameter makes any future bare call a compile error.
Button behavior:
- Wrap `handleConnect` in try/finally so `isLoading` always clears, and report
failures through ErrorHandler instead of an unhandled rejection.
- Key the hydration deadline by provider id so a newly selected provider cannot
inherit the previous one's expiry and render as ready with zero load time.
- Pass the provider to the modal even while it is still a stub;
`awaitLiveProvider` waits for the live provider, keeping the destination's
connectors in scope instead of degrading to the generic list.
- Add `aria-busy` and an `aria-live` status region for the initializing state.
OKX icon:
- starknetkit ships `injectedWalletIcons` for argentX, braavos, keplr, metamask,
fordefi and xverse only, so `okxwallet` fell through to its generic
placeholder. Register the OKX mark in the shared icon map and supply it via
the connector's `icon` option, which takes precedence over that fallback.
Verified: all wallet/ui-kit/widget packages typecheck, wallet-core tests pass,
and the flow was exercised in-browser under CPU/network throttling to reproduce
the initializing state.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The connect button in the address picker treated a descriptor stub as connect-ready. Clicking one opened the generic wallet modal instead of the destination's own connectors, and the readiness logic behind it had accumulated in three places with four copies of the same
isStub || !readypredicate and three separate 5000ms deadlines.Tracing that turned up a latent hard-lock:
WalletConnectionProvider.connectWalletdeclaredprops?as optional while every implementation requires a connector, andWalletModal.connect()was the one caller invoking it bare. Against the six adapters that destructure the parameter (fuel,bitcoin,svm,ton,tron,starknet) that throws at the parameter list — outside their own try/catch — soconnect()rejected beforesetOpen(true). With notry/finallyinhandleConnect,setIsLoading(false)never ran: spinner stuck on "Connecting…" forever, no modal, no error, page reload required.Changes
Readiness consolidation
isProviderHydrated(fails closed) besideisProviderConnectReady(fails open), with the deliberate polarity difference documented —isProviderConnectReady(undefined) === truevsisProviderHydrated(undefined) === false.useProvidersConnectReady,useConnectorSourcesStatusanduseWalletProviderReadinesscollapsed into wallet-core behind onePROVIDER_HYDRATION_TIMEOUT_MS. The two ui-kit hooks move out of the presentational layer.lib/providerReadiness.tsis importable from service classes (ParadexConnectionService) without pulling in React or the context graph; hooks live inhooks/useProviderReadiness.ts. Neither sits underlib/walletConnect/any more — they describe Layerswap'sWalletConnectionProvider, not the WalletConnect protocol.connectWalletcontract{ connector }, and the bare call is deleted. That branch could only fire when a provider had zero connectors (with even one,hasConnectorPickeristrue), so there was never anything to pass — it was a guaranteed no-op or the crash. Removing it also removed thehasConnectorPickercomputation that existed only to gate it.TS2554: Expected 1 arguments, but got 0) with no tsconfig changes, since argument arity is always checked. All eight adapters are untouched.Button behavior
handleConnectwrapped intry/finallysoisLoadingalways clears; failures go throughErrorHandleras aWalletError.awaitLiveProviderwaits for the live provider, keeping the destination's connectors in scope instead of degrading to the generic list.aria-busyand anaria-livestatus region.OKX Wallet icon
injectedWalletIconscoversargentX, braavos, keplr, metamask, fordefi, xverseonly, sookxwalletfell through to its generic placeholder (Fordefi rendered fine right next to it because it is in that map). The OKX mark is now registered in the shared icon map and supplied via the connector'siconoption, which takes precedence over starknetkit's fallback. Artwork extracted from@bigmi/client's OKX connector — already a dependency, and the source of the same icon for OKX on Bitcoin — so it stays consistent across chains with no network fetch.Verification
tsc --noEmitclean across wallet-core, all nine adapters,wallets/all, ui-kit and widget/core.pnpm --filter @layerswap/wallet-core test→ 4/4.distand rendering it.Notes for review
connectWalletcontract change is the one to scrutinize — it tightens a shared type. Every call site is covered:useWalletConnection.ts:77and both paradex sites already passed{ connector }.loadByIdfor stubs is what hydrates them instead.tsconfig.wallet.jsonsetsstrict: false, sostrictFunctionTypes/strictBindCallApplyare off and function-type variance mismatches are invisible. Enabling both surfaces ~9 pre-existing errors (bitcoin 1, evm 4, paradex 2, svm 1, ton 1), noneconnectWallet-related. Worth a focused follow-up.lib/walletConnect/still holds non-protocol machinery (createConnectionStoreFromHook,descriptorStubStore,walletProvidersRegistry,walletDescriptorLoader,connectorSource,mapWallet). Out of scope here, but the same relocation applies.🤖 Generated with Claude Code