Skip to content

[SDK] Add required email verification for in-app wallet #7130

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

joaquim-verges
Copy link
Member

@joaquim-verges joaquim-verges commented May 22, 2025


PR-Codex overview

This PR focuses on enhancing wallet connection functionality by adding email linking requirements for certain wallets, introducing a new VerifyEmailPrompt component, and updating various components to manage email linking more effectively.

Detailed summary

  • Added required: ["email"] to wallet configurations.
  • Introduced InAppWalletRequired type to specify required fields.
  • Implemented VerifyEmailPrompt component to handle email verification.
  • Updated ConnectEmbed and ConnectModalContent to manage email linking.
  • Enhanced ConnectWalletSocialOptions to restrict options based on email requirements.
  • Modified logic to defer wallet activation until email is linked.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • New Features

    • Added enforcement of email as a required authentication method for in-app wallets where applicable.
    • Introduced a new flow that prompts users to link their email before completing wallet connection if required by the wallet.
    • Enhanced the wallet connection process with a dedicated email verification prompt and screen when email linking is mandatory.
  • User Interface

    • Updated connection screens to guide users through required email linking and verification.
    • Improved prompts and validation for entering and verifying email addresses during wallet setup.

Copy link

vercel bot commented May 22, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
docs-v2 ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 22, 2025 8:11pm
login ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 22, 2025 8:11pm
thirdweb_playground ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 22, 2025 8:11pm
thirdweb-www ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 22, 2025 8:11pm
wallet-ui ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 22, 2025 8:11pm

Copy link

changeset-bot bot commented May 22, 2025

⚠️ No Changeset found

Latest commit: e5aa4b9

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link

coderabbitai bot commented May 22, 2025

Walkthrough

The changes introduce a new mechanism to enforce email as a required authentication method for in-app wallets. This is achieved by updating wallet configuration types, UI components, and connection flows to check for and require email linking before completing wallet connections when specified in the wallet's configuration.

Changes

File(s) Change Summary
apps/playground-web/src/components/in-app-wallet/connect-button.tsx
apps/playground-web/src/components/in-app-wallet/sponsored-tx.tsx
apps/playground-web/src/lib/constants.ts
Added a required: ["email"] property to the in-app wallet's auth configuration, making email authentication mandatory. Updated UI to use StyledConnectButton and propagate the new requirement.
packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/ConnectEmbed.tsx Integrated useProfiles to fetch user profiles. Added logic to detect if email is required and missing, and updated UI display conditions accordingly.
packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/ConnectModalContent.tsx Enhanced the connection flow to enforce email profile linking before finalizing wallet connection if required. Added async logic, new state management, and a new screen for profile linking.
packages/thirdweb/src/react/web/ui/ConnectWallet/constants.ts Added a new reserved screen identifier, linkProfile, for the profile linking UI.
packages/thirdweb/src/react/web/ui/ConnectWallet/screens/LinkProfileScreen.tsx Extended component props to accept an optional wallet parameter, allowing external wallet context for profile linking.
packages/thirdweb/src/react/web/wallets/shared/ConnectWalletSocialOptions.tsx Introduced a new flow and UI prompt for email verification when linking is required, including validation and restricted options.
packages/thirdweb/src/wallets/in-app/core/wallet/types.ts Added a new type for required auth methods and extended wallet creation options to support a required array in the auth object.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ConnectModal
    participant WalletConfig
    participant Profiles
    participant LinkProfileScreen

    User->>ConnectModal: Initiate wallet connection
    ConnectModal->>WalletConfig: Retrieve wallet config
    WalletConfig-->>ConnectModal: Return config (with auth.required)
    alt Email required in config
        ConnectModal->>Profiles: Fetch user profiles
        Profiles-->>ConnectModal: Return profiles
        alt No email linked
            ConnectModal->>LinkProfileScreen: Show link profile UI
            User->>LinkProfileScreen: Link email
            LinkProfileScreen->>Profiles: Update profiles
            Profiles-->>ConnectModal: Profiles updated (email linked)
            ConnectModal->>WalletConfig: Finalize wallet connection
        else Email already linked
            ConnectModal->>WalletConfig: Finalize wallet connection
        end
    else Email not required
        ConnectModal->>WalletConfig: Finalize wallet connection
    end
Loading

Possibly related PRs

  • thirdweb-dev/js#7120: Introduces a new hook and wallet method for retrieving an auth token from in-app wallets, which is related to in-app wallet authentication and complements the email requirement/enforcement changes in this PR.

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • TEAM-0000: Entity not found: Issue - Could not find referenced Issue.
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot added Playground Changes involving the Playground codebase. packages SDK Involves changes to the thirdweb SDK labels May 22, 2025
Copy link
Member Author


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • merge-queue - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (8)
packages/thirdweb/src/wallets/in-app/core/wallet/types.ts (1)

72-72: Well-integrated property for required authentication

The optional required property fits naturally within the existing authentication configuration structure. This enables fine-grained control over which authentication methods are mandatory for wallet activation.

Consider adding JSDoc comments to explain the behavior when required is specified, similar to the comments on other properties in this type.

+        /**
+         * List of authentication methods that must be completed before wallet activation
+         */
        required?: InAppWalletRequired[];
apps/playground-web/src/components/in-app-wallet/sponsored-tx.tsx (1)

46-46: Email requirement properly implemented

The required: ["email"] configuration correctly implements the requirement for email verification in this sponsored transaction component. This ensures users must verify their email before completing wallet activation.

You might want to consider adding a comment explaining the purpose of this requirement for clarity:

+                // Require email verification for security and user identification
                required: ["email"],
packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/ConnectEmbed.tsx (1)

198-203: Consider improving type safety for wallet config access.

The type casting used here indicates that the Wallet interface might not fully expose the getConfig method with the auth configuration structure.

Consider updating the Wallet interface to include this configuration structure more explicitly, which would eliminate the need for type casting:

- const walletConfig = (
-   activeWallet as unknown as {
-     getConfig?: () => { auth?: { required?: string[] } } | undefined;
-   }
- ).getConfig?.();
+ const walletConfig = activeWallet.getConfig?.();
packages/thirdweb/src/react/web/wallets/shared/ConnectWalletSocialOptions.tsx (2)

142-145: Consider improving type safety for auth configuration access.

The type casting suggests that the wallet's auth configuration structure might not be fully represented in the wallet's type definitions.

Consider updating the wallet interface to better represent the auth configuration structure, including the required field:

- const requiresEmail = (
-   (wallet.getConfig()?.auth as { required?: string[] } | undefined)
-     ?.required || []
- ).includes("email");
+ const requiresEmail = (wallet.getConfig()?.auth?.required || []).includes("email");

582-640: Implemented VerifyEmailPrompt component for email verification.

The new VerifyEmailPrompt component provides a clean UI for email verification with proper validation and error handling.

Consider using localized strings from the locale object for the title "Verify your email" and button text "Continue" to maintain consistency with the rest of the UI:

- <Text size="md" center weight={600} color="primaryText">
-   Verify your email
- </Text>
+ <Text size="md" center weight={600} color="primaryText">
+   {props.locale.verifyEmail || "Verify your email"}
+ </Text>

- <Button
-   variant="accent"
-   fullWidth
-   onClick={handleContinue}
-   disabled={props.disabled}
- >
-   Continue
- </Button>
+ <Button
+   variant="accent"
+   fullWidth
+   onClick={handleContinue}
+   disabled={props.disabled}
+ >
+   {props.locale.continue || "Continue"}
+ </Button>
packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/ConnectModalContent.tsx (3)

139-142: Remove leftover debug console.log statements

These six console.log calls will leak internal state and spam the console in production bundles.

-      console.log("wallet", walletConfig);
-      console.log("requiresEmail", requiresEmail);-          console.log("profiles", profiles);-          console.log("hasEmail", hasEmail);

Please delete or replace them with a proper logger behind a debug flag.

Also applies to: 154-161


143-171: Avoid double fetching – reuse useProfiles instead of direct getProfiles

handleConnected performs its own getProfiles request although the hook useProfiles is already instantiated (lines 95-97).
This triggers an additional network round-trip and duplicates caching logic.

Consider:

-          const profiles = await getProfiles({ client: props.client, ecosystem });
+          const profiles = profilesQuery.data ?? 
+            (await profilesQuery.refetch().then((r) => r.data));

This re-uses the hook’s cache and avoids a second HTTP request when data is already present.


255-257: Wrap awaiting handleConnected in a safety net

handleConnected is awaited but any exception will bubble up to React’s event handler and show an uncaught promise warning.

-      done={async (w) => {
-        await handleConnected(w);
-      }}
+      done={async (w) => {
+        try {
+          await handleConnected(w);
+        } catch (err) {
+          console.error("Wallet connection failed", err);
+          // TODO: surface error to the user
+        }
+      }}

Repeating this guard for the other two done callbacks prevents noisy runtime errors and improves UX.

Also applies to: 307-309, 329-331

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 23029db and e5aa4b9.

📒 Files selected for processing (9)
  • apps/playground-web/src/components/in-app-wallet/connect-button.tsx (2 hunks)
  • apps/playground-web/src/components/in-app-wallet/sponsored-tx.tsx (1 hunks)
  • apps/playground-web/src/lib/constants.ts (1 hunks)
  • packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/ConnectEmbed.tsx (2 hunks)
  • packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/ConnectModalContent.tsx (9 hunks)
  • packages/thirdweb/src/react/web/ui/ConnectWallet/constants.ts (1 hunks)
  • packages/thirdweb/src/react/web/ui/ConnectWallet/screens/LinkProfileScreen.tsx (1 hunks)
  • packages/thirdweb/src/react/web/wallets/shared/ConnectWalletSocialOptions.tsx (4 hunks)
  • packages/thirdweb/src/wallets/in-app/core/wallet/types.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
apps/playground-web/src/components/in-app-wallet/connect-button.tsx (1)
apps/playground-web/src/components/styled-connect-button.tsx (1)
  • StyledConnectButton (17-38)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Size
  • GitHub Check: Unit Tests
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (13)
packages/thirdweb/src/wallets/in-app/core/wallet/types.ts (1)

63-63: Good choice for type definition

Using a string literal type is a clean way to define the required authentication methods. This provides type safety while remaining extensible for future additional required methods.

packages/thirdweb/src/react/web/ui/ConnectWallet/constants.ts (1)

6-6: Logical addition to reserved screens

Adding the linkProfile screen identifier follows the existing pattern and supports the email verification flow. This is a necessary addition to enable the UI flow for linking email profiles when required.

apps/playground-web/src/lib/constants.ts (1)

30-30: Consistent implementation of email requirement

Adding the email requirement here ensures consistent behavior across the application. This aligns with the PR objective to enforce email verification for in-app wallets.

Consider implementing a test to verify that wallets with this configuration properly enforce email verification before activation.

apps/playground-web/src/components/in-app-wallet/connect-button.tsx (3)

4-4: Component import updated to match usage pattern.

This change updates the import from StyledConnectEmbed to StyledConnectButton, which is now used in the component rendering below.


8-8: Using StyledConnectButton instead of StyledConnectEmbed.

The component has been updated to use StyledConnectButton, which wraps the ConnectButton with predefined chains, wallets, client, and theme.


27-27: Added email verification requirement for in-app wallet.

This addition configures the in-app wallet to require email verification before activation, which aligns with the PR objective of enforcing email verification for in-app wallets.

packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/ConnectEmbed.tsx (3)

22-22: Added useProfiles hook for email verification.

The useProfiles hook is imported to fetch user profiles linked to the active wallet, which will be used to check if an email is linked.


188-214: Implemented email verification requirement check.

This block implements the core logic for checking if the wallet requires email verification and if the user has an email linked. The code correctly:

  1. Fetches profiles for the connected wallet
  2. Checks if the wallet configuration requires email verification
  3. Verifies if any of the user's profiles has an email linked
  4. Sets the needsEmailLink flag if email is required but not linked

216-219: Extended UI visibility condition to include email verification requirement.

The show condition has been extended to display the connect UI when email linking is required but missing. This ensures the wallet connection UI remains visible until the email verification is completed.

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/LinkProfileScreen.tsx (2)

31-31: Added optional wallet prop to support external wallet passing.

Adding an optional wallet prop allows the component to accept an externally passed wallet instead of only using internal hooks, supporting the email verification flow.


38-38: Updated wallet assignment to prioritize passed wallet prop.

The wallet variable assignment now prioritizes the passed wallet prop over the hooks (adminWallet or activeWallet), enabling better control over which wallet is being used for the linking process.

packages/thirdweb/src/react/web/wallets/shared/ConnectWalletSocialOptions.tsx (2)

142-146: Added check for required email verification.

This code detects if the wallet requires email verification by checking for "email" in the required array of the auth configuration. This is a crucial part of the email verification enforcement.


330-343: Added conditional rendering for email verification prompt.

When in linking mode and email verification is required, the component now shows a dedicated email verification prompt instead of the regular social login options. This ensures that users must verify their email before connecting their wallet.

Comment on lines +199 to +231
// Effect to watch for email linking completion
useEffect(() => {
if (!pendingWallet) {
return;
}
const profiles = profilesQuery.data;
if (!profiles) {
return;
}
const hasEmail = profiles.some((p) => !!p.details.email);
if (hasEmail) {
// finalize connection now
if (shouldSetActive) {
setActiveWallet(pendingWallet);
} else {
connectionManager.addConnectedWallet(pendingWallet);
}
props.onConnect?.(pendingWallet);
setPendingWallet(undefined);
setScreen(initialScreen);
onClose?.();
}
}, [
profilesQuery.data,
pendingWallet,
shouldSetActive,
setActiveWallet,
connectionManager,
props.onConnect,
setScreen,
initialScreen,
onClose,
]);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consolidate duplicated “finalize connection” logic

handleConnected defines finalizeConnection, but the useEffect block re-implements the same steps (setting active wallet, calling onConnect, etc.).
Duplicating critical flows increases maintenance overhead and risks divergence.

Extract finalizeConnection with useCallback at component scope and invoke it from both places:

const finalizeConnection = useCallback((wallet: Wallet) => {
  if (shouldSetActive) {
    setActiveWallet(wallet);
  } else {
    connectionManager.addConnectedWallet(wallet);
  }
  props.onConnect?.(wallet);
}, [shouldSetActive, setActiveWallet, connectionManager, props.onConnect]);

Then call finalizeConnection(...) inside handleConnected and inside the effect.

🤖 Prompt for AI Agents
In
packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/ConnectModalContent.tsx
around lines 199 to 231, the logic to finalize the wallet connection is
duplicated both in the handleConnected function and inside the useEffect hook.
To fix this, extract the finalize connection steps into a useCallback function
named finalizeConnection at the component scope, which takes a wallet parameter
and performs setting the active wallet or adding the connected wallet, then
calls props.onConnect. Replace the duplicated code in both handleConnected and
the useEffect hook by calling finalizeConnection with the appropriate wallet
argument.

Comment on lines +123 to 138
auth?: {
required?: string[];
};
partnerId?: string;
};

const walletWithConfig = wallet as unknown as {
getConfig?: () => WalletConfig | undefined;
};

const walletConfig = walletWithConfig.getConfig
? walletWithConfig.getConfig()
: undefined;
const required = walletConfig?.auth?.required as string[] | undefined;
const requiresEmail = required?.includes("email");

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Harden the required-field parsing

walletConfig?.auth?.required is cast to string[] | undefined without validation and then used directly. If a malformed wallet config (e.g. required: "email") is returned, the subsequent .includes() will throw or yield unexpected results.

-      const required = walletConfig?.auth?.required as string[] | undefined;
-      const requiresEmail = required?.includes("email");
+      const required = walletConfig?.auth?.required;
+      const requiresEmail =
+        Array.isArray(required) && required.includes("email");

A simple guard prevents runtime errors and removes the need for a type-cast.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
auth?: {
required?: string[];
};
partnerId?: string;
};
const walletWithConfig = wallet as unknown as {
getConfig?: () => WalletConfig | undefined;
};
const walletConfig = walletWithConfig.getConfig
? walletWithConfig.getConfig()
: undefined;
const required = walletConfig?.auth?.required as string[] | undefined;
const requiresEmail = required?.includes("email");
const walletConfig = walletWithConfig.getConfig
? walletWithConfig.getConfig()
: undefined;
const required = walletConfig?.auth?.required;
const requiresEmail =
Array.isArray(required) && required.includes("email");
🤖 Prompt for AI Agents
In
packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/ConnectModalContent.tsx
around lines 123 to 138, the code casts walletConfig?.auth?.required to string[]
without validating its type, which can cause runtime errors if the value is not
an array. Fix this by adding a type guard to check if
walletConfig?.auth?.required is an array before using it, avoiding the unsafe
type cast and preventing errors when calling includes().

Copy link
Contributor

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
thirdweb (esm) 56.62 KB (0%) 1.2 s (0%) 241 ms (+127.09% 🔺) 1.4 s
thirdweb (cjs) 309.13 KB (0%) 6.2 s (0%) 890 ms (+3.67% 🔺) 7.1 s
thirdweb (minimal + tree-shaking) 5.69 KB (0%) 114 ms (0%) 80 ms (+852.28% 🔺) 194 ms
thirdweb/chains (tree-shaking) 531 B (0%) 11 ms (0%) 31 ms (+1377.46% 🔺) 41 ms
thirdweb/react (minimal + tree-shaking) 19.5 KB (0%) 390 ms (0%) 119 ms (+528.12% 🔺) 509 ms

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
DO NOT MERGE This pull request is still in progress and is not ready to be merged. packages Playground Changes involving the Playground codebase. SDK Involves changes to the thirdweb SDK
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant