Skip to content

feat(dashboard): connect wallet without signing in - #2086

Open
brunod-e wants to merge 3 commits into
devfrom
feat/connect-wallet-without-siwe
Open

feat(dashboard): connect wallet without signing in#2086
brunod-e wants to merge 3 commits into
devfrom
feat/connect-wallet-without-siwe

Conversation

@brunod-e

@brunod-e brunod-e commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Problem

Delegating, voting and publishing a proposal are settled on-chain by the wallet's own transaction signature, so they only ever needed a connected account. They were routed through the sign-in modal instead, which forced a SIWE message on anyone who just wanted to act on-chain.

A harder blocker sat in LoginProvider: an effect that called disconnect() on any connected wallet without a session. Being connected but not signed in was simply not a reachable state.

Applies to both Anticapture and whitelabel.

What changed

Connecting a wallet and signing in are now separate actions.

File Change
shared/services/auth/useWalletPrompt.ts Always opens the wallet picker, never the sign-in modal
shared/services/auth/LoginProvider.tsx Dropped the effect that force-disconnected a session-less wallet; connected without a session is now a valid state
shared/services/auth/LoginProvider.tsx Switching accounts still signs a SIWE session out, but no longer re-opens the sign-in modal on its own
shared/components/wallet/ConnectWallet.tsx Anticapture header button opens the wallet picker
shared/components/wallet/WhitelabelConnectWallet.tsx Same for whitelabel

No copy changes: the sign-in modal keeps its "Connect wallet" button.

Wallet-born sessions stay bound to their wallet: disconnecting or switching accounts still signs them out, it just never prompts again.

The remaining openLogin() call sites are only where a server session is genuinely required: API keys, saving or sharing a draft, and opening the proposal editor. None on the delegate or vote path.

Verification

tsc --noEmit clean and eslint at 0 errors, with no warnings in the touched files (the 83 warnings in the app are pre-existing).

Not verified: the wallet flows in a browser. That needs a real wallet extension plus the full local stack, so please confirm manually that Delegate and Vote open MetaMask without asking for a signature, on both Anticapture and a whitelabel deployment.

Worth a look during review

With the header becoming a pure connect affordance, email and Google lose their visible entry point. They now surface only when the user hits a session-gated action (draft, API key). If that is not the intent, the alternative is two separate affordances ("Connect wallet" and "Sign in"), which needs design.

🤖 Generated with Claude Code

Delegating, voting and publishing a proposal are settled on-chain by the
wallet's own transaction signature, so they only ever needed a connected
account. They were routed through the sign-in modal instead, forcing a
SIWE message on anyone who just wanted to act on-chain.

Connecting and signing in are now separate:

- useWalletPrompt always opens the wallet picker, never the sign-in modal
- LoginProvider no longer force-disconnects a wallet that has no session,
  and no longer re-opens the sign-in modal when the account changes
- the header connect buttons (Anticapture and whitelabel) open the wallet
  picker directly
- the sign-in modal, still raised by the surfaces that need a server
  session (proposal drafts, API keys), labels its wallet option
  "Sign in with wallet"

Wallet-born sessions stay bound to their wallet: disconnecting or
switching accounts still signs them out, it just never prompts again.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 27, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
anticapture-storybook Ready Ready Preview, Comment Jul 27, 2026 6:31pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
anticapture Ignored Ignored Jul 27, 2026 6:31pm

Request Review

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@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: bcd09f1772

ℹ️ 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".

@@ -82,19 +85,8 @@ export function LoginProvider({
address.toLowerCase() !== sessionAddress
) {
void authClient.signOut();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Block gated actions while switching wallet accounts

When a SIWE-authenticated user switches from wallet A to wallet B, this starts signOut() asynchronously but leaves A's session usable while the request is pending—and indefinitely if it fails. During that interval the UI displays wallet B, while useDrafts and ApiKeysManager still treat A as authenticated, so saving a draft or creating/revoking an API key can mutate A's account. Keep the session-gated surfaces blocked or treat the session as invalid as soon as the address mismatch is detected, rather than relying solely on the eventual sign-out response.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator

🎨 UI Review

Automated review · Figma: 🔐 Login & API Keys — V1 screens (found via ClickUp task 86ac8e1y5) · Spec: 🔐 Login & API Keys
⚠️ Figma link found but the Figma MCP is not connected in this environment (configuration error, not attempted-and-failed) — visual/node-level validation was skipped. Review is grounded in the diff, the linked ClickUp spec text, and UX-expert evaluation.
ℹ️ Preview: the anticapture Vercel deployment was Ignored for this PR at review time (only anticapture-storybook built) — regression check is diff-level only, not a live before/after comparison.


Header — Connect Wallet button (Anticapture + Whitelabel)

Question for author — header no longer offers a wallet sign-in path, which the linked spec says it should

  • ConnectWallet.tsx:70-79 and WhitelabelConnectWallet.tsx (same pattern) now open the wallet picker unconditionally, with no SIWE step, in every session state. The linked spec (ClickUp 86ac8e1y5, "🔐 Login & API Keys") states: "Wallet auth = SIWE signature under a 'Connect wallet' label; branch on session state (logged out = login, logged in = link to current account)." The Figma sign-in modal (③.1, node 3315:19919, referenced from that same task) designs wallet-connect as an authentication method, not a connect-only action.
  • After this PR, the header's "Connect Wallet" affordance can never authenticate — the only remaining path to sign in with a wallet is the separate sign-in modal, reached only from a session-gated surface (draft, API key). That's exactly the tension flagged in this PR's own "Worth a look during review" section, just without a citation to the spec it diverges from.
  • Needs a call before merge: either the spec/Figma get updated to reflect "Connect Wallet" becoming a pure connect affordance (with sign-in moved entirely behind gated actions, as the PR's alternative suggests), or the header should keep the branch-on-session-state behavior the spec calls for. [Code-only — cross-checked against ClickUp spec text, Figma nodes not opened per the caveat above]

Component states

Nice-to-have — "connected, no session" now looks identical to "signed in" in the header

  • Once a wallet is connected (regardless of session), ConnectWallet.tsx always renders the same avatar/ENS account button (openAccountModal). Before this PR, a session-less connected wallet was force-disconnected in LoginProvider, so this branch only ever rendered for an actually signed-in user. Now it's reachable while signed out too (e.g. right after voting), and it looks the same. Nothing in the header distinguishes "just connected" from "connected and signed in," so a user could reasonably assume session-gated features (follow/alerts, saved drafts) are available when they aren't.
  • Consider a small visual distinguisher on the account button when !session — a "not signed in" badge or tooltip — so the two states read differently. (apps/dashboard/shared/components/wallet/ConnectWallet.tsx:83-108) [UX-heuristic]

Design-system adherence

No issues — the diff only reconfigures existing Button / ConnectButton.Custom usage and provider logic; no hand-rolled primitives introduced. [Code-only]

Mobile

No mobile-specific surface changed in this diff — the same header components render responsively as before; nothing new to check here.

Scope note

This is a UI-only review (visual fidelity, DS adherence, UX, copy, responsive behavior) — architecture, hook structure, and other code-quality concerns are left to the code reviewer.


Generated by Claude Code

@github-actions

github-actions Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

🔍 Vercel preview: https://anticapture-hp5a75g8u-ful.vercel.app

@railway-app

railway-app Bot commented Jul 27, 2026

Copy link
Copy Markdown

🚅 Deployed to the anticapture-pr-2086 environment in anticapture-infra

Service Status Web Updated (UTC)
ens-indexer-offchain ✅ Success (View Logs) Jul 28, 2026 at 1:34 pm
uniswap-indexer-offchain ✅ Success (View Logs) Jul 28, 2026 at 1:24 pm
compound-indexer-offchain ✅ Success (View Logs) Jul 28, 2026 at 1:22 pm
gitcoin-indexer-offchain ✅ Success (View Logs) Jul 28, 2026 at 1:20 pm
shutter-indexer-offchain ✅ Success (View Logs) Jul 28, 2026 at 1:20 pm
authful ✅ Success (View Logs) Web Jul 27, 2026 at 6:31 pm
grafana ✅ Success (View Logs) Web Jul 27, 2026 at 6:30 pm
tempo ✅ Success (View Logs) Jul 27, 2026 at 6:30 pm
otelcol ✅ Success (View Logs) Jul 27, 2026 at 6:30 pm
alertmanager ✅ Success (View Logs) Jul 27, 2026 at 6:29 pm
loki ✅ Success (View Logs) Jul 27, 2026 at 6:29 pm
prometheus ✅ Success (View Logs) Jul 27, 2026 at 6:29 pm
gateful ✅ Success (View Logs) Web Jul 27, 2026 at 6:29 pm
tornado-indexer ✅ Success (View Logs) Jul 27, 2026 at 2:43 pm
docs ✅ Success (View Logs) Web Jul 27, 2026 at 2:42 pm
mcp ✅ Success (View Logs) Web Jul 27, 2026 at 2:42 pm
fluid-api ✅ Success (View Logs) Jul 27, 2026 at 2:42 pm
aave-api ✅ Success (View Logs) Jul 27, 2026 at 2:42 pm
nouns-api ✅ Success (View Logs) Jul 27, 2026 at 2:42 pm
gitcoin-indexer ✅ Success (View Logs) Jul 27, 2026 at 2:42 pm
ens-indexer ✅ Success (View Logs) Jul 27, 2026 at 2:42 pm
ens-api ✅ Success (View Logs) Jul 27, 2026 at 2:42 pm
gitcoin-api ✅ Success (View Logs) Jul 27, 2026 at 2:41 pm
lil-nouns-indexer ✅ Success (View Logs) Jul 27, 2026 at 2:41 pm
shutter-api ✅ Success (View Logs) Jul 27, 2026 at 2:41 pm
compound-api ✅ Success (View Logs) Jul 27, 2026 at 2:41 pm
nouns-indexer ✅ Success (View Logs) Jul 27, 2026 at 2:41 pm
aave-indexer ✅ Success (View Logs) Jul 27, 2026 at 2:41 pm
tornado-api ✅ Success (View Logs) Jul 27, 2026 at 2:41 pm
obol-indexer ✅ Success (View Logs) Jul 27, 2026 at 2:41 pm
address-enrichment ✅ Success (View Logs) Web Jul 27, 2026 at 2:41 pm
shutter-indexer ✅ Success (View Logs) Jul 27, 2026 at 2:41 pm
fluid-indexer ✅ Success (View Logs) Jul 27, 2026 at 2:41 pm
uniswap-api ✅ Success (View Logs) Jul 27, 2026 at 2:41 pm
uniswap-indexer ✅ Success (View Logs) Jul 27, 2026 at 2:41 pm
lil-nouns-api ✅ Success (View Logs) Jul 27, 2026 at 2:41 pm
obol-api ✅ Success (View Logs) Jul 27, 2026 at 2:41 pm
compound-indexer ✅ Success (View Logs) Jul 27, 2026 at 2:41 pm
scroll-indexer ✅ Success (View Logs) Jul 27, 2026 at 2:41 pm
ens-relayer ✅ Success (View Logs) Jul 27, 2026 at 2:41 pm
erpc ✅ Success (View Logs) Web Jul 27, 2026 at 2:41 pm
nodeful ✅ Success (View Logs) Jul 27, 2026 at 2:41 pm
user-api ✅ Success (View Logs) Web Jul 27, 2026 at 2:39 pm
scroll-api ✅ Success (View Logs) Jul 27, 2026 at 2:39 pm

…anges

Switching accounts on a SIWE session fired signOut() and left the old
session usable while the request was in flight, and indefinitely if it
failed: the header showed wallet B while drafts and API keys still acted
for wallet A.

Sign-out is now the cleanup, not the gate. isWalletSessionStale derives
the broken binding synchronously from wallet state, and useAuthSession
serves the session through it, so a mismatched or disconnected wallet
reads as no session from the render it happens. The API-key create and
delete modals live outside the auth branch, so they close on the account
change instead of submitting against the previous account.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@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: 160230f74a

ℹ️ 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".

setSessionTokens({});
setLastCreated(null);
setCreated(null);
setCreateOpen(false);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Discard previous-account mutation completions

When a user submits an API-key creation and switches or disconnects the wallet before the request completes, this effect clears and closes the current state, but it does not cancel or invalidate the mutation's per-call callback. A successful response can subsequently run onSuccess, repopulate created and sessionTokens, and show wallet A's plaintext key after wallet B has signed in. Associate the mutation with the initiating user ID and ignore late completions after that ID changes.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants