Skip to content

fix(chat): Solana and Base wallets get mixed up in the connect UI - #25

Merged
VickyXAI merged 2 commits into
masterfrom
fix/wallet-chain-confusion
Aug 26, 2026
Merged

fix(chat): Solana and Base wallets get mixed up in the connect UI#25
VickyXAI merged 2 commits into
masterfrom
fix/wallet-chain-confusion

Conversation

@VickyXAI

Copy link
Copy Markdown
Contributor

Reported from production: Solana and Base get confused in the wallet UI. Two separate causes, both in the wallet facade.

1. An EVM wallet silently masked a connected Solana one

The active chain resolved as evmConnected ? "evm" : solanaConnected ? "solana" : null — EVM wins, unconditionally. And nothing ever enforced the "one active wallet" invariant that the same comment described: connectSolana never disconnected the EVM wallet, connectEvm never disconnected the Solana one.

Both stacks auto-reconnect on mount. So for anyone who had ever connected MetaMask, wagmi restored it, and connecting Phantom afterwards did nothing visible: the pill kept showing Base, the EVM address and the Base balance, and payments kept routing to blockrun.ai. The user explicitly chose Solana and the UI said otherwise.

The stated rationale — "EVM wins the tie because it is the payable chain" — also stopped being true when Solana payments shipped.

  • connectEvm / connectSolana now disconnect each other, but only after the wallet says yes, so a declined prompt leaves the previous wallet alone.
  • The chain the user last deliberately connected on is persisted and decides the tie, so re-authorizing a wallet from inside an extension can't override a deliberate choice.
  • Switching chains clears the server session up front. Sign-in is best-effort, so without this a declined SIWS left the previous wallet's cookie serving its history next to the new wallet's address.

2. The pill flashed the wrong chain on every reload

wagmi has settled by first paint while the Kit plugin is still restoring a persisted wallet. So a returning Phantom user watched the pill resolve to their EVM wallet and only then flip to Phantom.

isReady existed for precisely this, and was plumbed all the way through to useAuth without a single consumer. Now, while Solana is still warming and Solana is the remembered choice, the facade reports "not connected yet" rather than the other chain, and ConnectWallet holds its existing loading shell until isReady.

The remembered chain also moved from an effect to the first client render — it is needed the moment the warm-up resolves, not a commit later. Hydration is unaffected: it only changes the outcome when both wallets are connected, which cannot be true on the first render.

Solana is now the default

It leads the network chooser and wins the untouched tie. That case is only reached when both wallets auto-reconnected without the user picking either, where the tie should fall to the chain we want people on. It is also the cheaper rail — Base adds a $0.001/call transaction fee that Solana's facilitator absorbs.

Also

Renames two flags that now lie: onBase in the connected pill and isOnBase from useUsdcBalance are both true for a connected Solana wallet. They mean "on the network we can transact on", and a name that says Base invites the exact mix-up being reported.

Verified

  • All six (evmConnected × solanaConnected × remembered) combinations resolve to the user's last deliberate choice; the two that were wrong before are the two reported symptoms.
  • Browser: connect button settles to enabled after warm-up (gating on isReady would otherwise be an excellent way to disable it forever), chooser lists Solana first, Solana → wallet-list flow intact, no console errors.
  • typecheck / eslint src / build clean.

Not covered

The real two-wallet case still needs a human with both MetaMask and Phantom installed: connect one, connect the other, confirm the pill, balance and payment routing all follow the wallet you just approved, and that history does not leak across the switch.

1bcMax added 2 commits August 25, 2026 23:00
Reported from production: Solana and Base get mixed up in the wallet UI.

Root cause is the tie-break in use-wallet.ts. It resolved the active chain
as `evmConnected ? "evm" : solanaConnected ? "solana" : null` — EVM wins,
unconditionally. Nothing ever enforced the "one active wallet" invariant
its own comment described: connectSolana never disconnected the EVM
wallet, and connectEvm never disconnected the Solana one.

Both stacks auto-reconnect on mount. So for anyone who had ever connected
MetaMask, wagmi restored it, and connecting Phantom afterwards did
nothing visible: the pill kept showing Base, their EVM address and their
Base balance, and payments kept routing to blockrun.ai. The user had
explicitly chosen Solana and the UI silently said otherwise.

The stated rationale — "EVM wins the tie because it is the payable
chain" — also stopped being true when Solana payments shipped.

Now:
- connectEvm/connectSolana each disconnect the other, but only after the
  wallet says yes, so a declined prompt leaves the previous wallet alone.
- The chain the user last deliberately connected on is persisted, and it
  decides the tie if both are somehow connected — a re-authorization from
  inside the extension can no longer override a deliberate choice.
- Switching chains clears the server session up front. Sign-in is
  best-effort, so without this a declined SIWS left the previous wallet's
  cookie serving its history next to the new wallet's address.

Also renames two flags that now lie: `onBase` in the connected pill and
`isOnBase` from useUsdcBalance are both true for a connected Solana
wallet. They mean "on the network we can transact on", and a name that
says Base invites the exact mix-up being reported.
…rong chain

Two follow-ups to the tie-break fix.

Solana is now the preferred chain. It leads the network chooser, and it
wins the tie when both wallets are connected and the user has not chosen
— which is reached only when both auto-reconnected on their own, where
the tie should fall to the chain we want people on rather than to
whichever extension happened to restore itself. It is also the cheaper
rail: Base adds a $0.001 transaction fee per call that Solana's
facilitator absorbs.

The second half of the reported Base/Solana mix-up was a warm-up race.
wagmi has settled by first paint while the Kit plugin is still restoring
a persisted wallet, so a returning Phantom user watched the pill resolve
to their EVM wallet and only then flip to Phantom. `isReady` existed for
exactly this and was plumbed all the way to useAuth without a single
consumer.

Now, while Solana is still warming AND Solana is the remembered choice,
the facade reports "not connected yet" instead of the other chain, and
ConnectWallet holds its existing loading shell until isReady — so the
window is rendered as neither disconnected nor wrong. The remembered
chain also moved from an effect to the first client render, since it is
needed the moment the warm-up resolves rather than one commit later;
hydration is unaffected because it only changes the outcome when both
wallets are connected, which cannot be true on the first render.

Verified in a browser that the connect button still settles to enabled —
gating on isReady would otherwise be a good way to disable it forever.
@VickyXAI
VickyXAI merged commit 6d98bd4 into master Aug 26, 2026
1 check passed
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.

1 participant