Skip to content

feat: link external wallet#2437

Open
lwin-kyaw wants to merge 16 commits intomasterfrom
feat/link-ext-wallet
Open

feat: link external wallet#2437
lwin-kyaw wants to merge 16 commits intomasterfrom
feat/link-ext-wallet

Conversation

@lwin-kyaw
Copy link
Copy Markdown
Contributor

@lwin-kyaw lwin-kyaw commented Apr 2, 2026

Jira Link

https://consensyssoftware.atlassian.net/browse/EMBED-85?atlOrigin=eyJpIjoiM2UxZDY3YTZlOGFkNGU2Nzg0YjFjYjliOTc5N2I1MjAiLCJwIjoiaiJ9

Description

This PR adds external wallet account linking to Web3Auth.

Users authenticated through the AUTH connector can now link and unlink external wallets, retrieve connected account metadata from user info, and access framework-level React/Vue helpers for the flow. The change also updates the demo apps to showcase the new linking UX.

What Changed

  • Added linkAccount(params) and unlinkAccount(address) to Web3AuthNoModal.
  • Introduced account-linking types and REST helpers for Citadel-backed /v1/link/wallet and /v1/unlink/wallet requests.
  • Added dedicated AccountLinkingError error codes and analytics events for linking/unlinking start, success, and failure.
  • Extended connector interfaces with generateChallengeAndSign() so external wallets can produce proof-of-ownership signatures for linking.
  • Refactored EVM, Solana, and WalletConnect v2 connectors to support reusable challenge/sign flows.
  • Implemented isolated connector creation during linking so external wallet proof generation does not mutate the main SDK session state.
  • Updated AuthConnector.getUserInfo() to include connectedAccounts fetched from Citadel /v1/user.
  • Added and exported useLinkAccount hooks/composables for:
    • @web3auth/modal/react
    • @web3auth/modal/vue
    • @web3auth/no-modal/react
    • @web3auth/no-modal/vue
  • Updated the Vue and Wagmi React demo apps to:
    • display connected wallets from user info
    • link external wallets
    • unlink linked wallets
    • show success/error state for the flow

User-Facing Features

  • Authenticated users can link an external wallet to their Web3Auth account.
  • Linked wallets can be unlinked later by address.
  • User info now includes connected account metadata, including primary account state and linked wallet details.
  • React and Vue consumers get a simplified useLinkAccount API with loading, error, and linked account state.

Notes

  • Account linking/unlinking is only supported when the active session is connected with the AUTH connector.
  • Automatic wallet linking currently supports METAMASK and WALLET_CONNECT_V2.
  • Linking uses signed wallet challenges and refreshed identity tokens returned from Citadel.

How has this been tested?

  • Authenticate with the AUTH connector.
  • Call getUserInfo() and verify connectedAccounts is returned.
  • Link a MetaMask wallet and confirm the linked account appears in the response.
  • Link a WalletConnect wallet and confirm the linked account appears in the response.
  • Unlink a previously linked wallet and confirm it is removed from the returned linked accounts.
  • Verify React/Vue demo flows show loading, success, and error states correctly.

Screenshots (if appropriate)

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Checklist

  • My code follows the code style of this project. (run lint)
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

Note

High Risk
High risk because it adds new account-linking/unlinking flows tied to authentication tokens and introduces account switching that mutates the active connection/provider state, which can impact session integrity and downstream integrations (e.g. Wagmi).

Overview
Adds account linking/unlinking support to @web3auth/no-modal via new account-linking types + REST helpers and exposes web3Auth.linkAccount() / web3Auth.unlinkAccount() APIs, alongside analytics events and dedicated AccountLinkingError codes.

Introduces active connected-wallet switching (web3Auth.switchAccount() and useSwitchAccount React/Vue helpers) and updates user info to include connectedAccounts, with provider/integration resync logic to handle connection updates.

Updates demo apps (notably demo/vue-app-new/AppDashboard.vue) to display connected wallets, link/unlink wallets, and switch the active wallet; also bumps Torus controllers and refreshes lockfile registry resolutions and related dependencies.

Reviewed by Cursor Bugbot for commit 37bdd8e. Bugbot is set up for automated code reviews on this repo. Configure here.

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 2, 2026

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

Project Deployment Actions Updated (UTC)
web3auth-web Error Error Apr 8, 2026 8:01pm

Request Review

@lwin-kyaw lwin-kyaw changed the base branch from master to feat/External-wallet-session-management April 2, 2026 12:50
Base automatically changed from feat/External-wallet-session-management to master April 6, 2026 08:21
@lwin-kyaw lwin-kyaw marked this pull request as ready for review April 7, 2026 08:39
@lwin-kyaw lwin-kyaw requested review from a team as code owners April 7, 2026 08:39
@@ -0,0 +1,2 @@
registry=https://registry.npmjs.org/

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

.npmrc committed despite being in .gitignore

Medium Severity

The .npmrc file is listed in .gitignore (line 115), indicating it's intended to be a local-only configuration file. It was force-committed with registry=https://registry.npmjs.org/, which can override private registry configurations for other contributors and CI environments that rely on consensys.jfrog.io (as seen in the lockfile resolved URLs).

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 24591ca. Configure here.

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7506233. Configure here.

</Button>
<Button
v-if="canUnlinkConnectedWallet(account)"
:loading="accountLinkingLoading && pendingUnlinkAddress === account.address"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Unlink button loading state uses wrong property

Medium Severity

The unlink button's :loading binding compares pendingUnlinkAddress === account.address, but pendingUnlinkAddress is set to account.eoaAddress (via onUnlinkAccount(account.eoaAddress) on the click handler). address (from LinkedAccountInfo, nullable) and eoaAddress (from ConnectedAccountInfo) are distinct fields, so the loading spinner will never display for the unlink button when the two values differ.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7506233. Configure here.

const lastUnlinkedAddress = ref<string | null>(null);
const pendingUnlinkAddress = ref<string | null>(null);
const connectedWallets = computed(() => userInfo.value?.connectedAccounts ?? []);
console.log("connectedWallets", connectedWallets.value);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Debug console.log left in component setup

Low Severity

A console.log("connectedWallets", connectedWallets.value) statement sits at the top level of <script setup>, so it runs on every component mount. This looks like leftover debug output that wasn't intended for the final commit.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7506233. Configure here.

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