Overview

Wallet Pregeneration allows you to create wallets for users before they set up a wallet with Capsule. This feature gives you control over when users claim and take ownership of their wallet. This guide will walk you through the process of creating, managing, and claiming pregenerated wallets using Capsule’s SDK.

Core Pregeneration Methods

Capsule provides several methods for handling pregenerated wallets:

getPregenWallets
function

Retrieve pregenerated wallets for a given identifier.

hasPregenWallet
function

Check if a pregenerated wallet exists for an identifier.

claimPregenWallets
function

Claim pregenerated wallets associated with an identifier.

createWalletPreGen
function

Create a new pregenerated wallet.

updateWalletIdentifierPreGen
function

Update the identifier of a pregenerated wallet.

Let’s explore each of these methods in detail.

Creating a Pregenerated Wallet

To create a pregenerated wallet, use the createWalletPreGen method:

const pregenWallet = await capsule.createWalletPreGen(
  pregenIdentifier,
  useSolana,
  pregenIdentifierType
);
pregenIdentifier
string

A string that identifies the user (e.g., email, user ID).

useSolana
boolean

Optional boolean to create a Solana wallet (default is false for EVM or Cosmos wallets).

pregenIdentifierType
enum

Optional enum (EMAIL or PHONE) to specify the identifier type.

Example:

const userEmail = 'user@example.com';
const pregenWallet = await capsule.createWalletPreGen(userEmail);
console.log('Pregenerated Wallet ID:', pregenWallet.id);

It’s important to check if a pregenerated wallet already exists before creating a new one:

const hasWallet = await capsule.hasPregenWallet(userEmail);
if (!hasWallet) {
  const pregenWallet = await capsule.createWalletPreGen(userEmail);
  console.log('New pregenerated wallet created:', pregenWallet.id);
} else {
  console.log('Pregenerated wallet already exists for this user');
}

The identifier doesn’t have to be an email. It can be any string specific to your application, such as a user ID.

Storing and Managing User Share

After creating a pregenerated wallet, it’s crucial to manage the user share so it remains accessible to either you or the user until the claim process. The user share is part of Capsule’s 2/2 MPC that is typically managed by users and protected by their auth+passkey. For pregenerated wallets, you need to handle this share until the wallet is claimed.

To get the user share:

const userShare = await capsule.getUserShare();

To set the user share (important before using the wallet for signing):

await capsule.setUserShare(userShare);

It’s important to safeguard this user share as it’s specific to your application until the wallet is claimed. Store it securely and associate it with the user’s identifier in your backend. If you lose this share, the wallet will no longer be accessible.

Best Practices for Storing the User Share

When temporarily managing the user share, it is critical to have a higher degree of operational excellence around storing this share. In disaster scenarios of widespread data compromise, key rotation is possible in coordination with the Capsule Team. However, Capsule does not store backups of this share in case of data loss.

To mitigate this category of risks, we’ve compiled a few best practices:

  • Encrypt User Shares in-transit and at-rest.
  • Ensure Your database has backups and periodic replicas to mitigate against data deletion risks.
  • Complete a fire drill prior to going live, testing scenarios such as:
    • You are unable to access your DB
    • Your DB is deleted
    • An internal team member’s credentials are compromised

Capsule is happy to offer pre-launch security reviews for teams in the Growth tier or above. Let us know if you need help!

Using a Pregenerated Wallet

To use a pregenerated wallet for signing, first set the user share, then you can sign messages or transactions:

await capsule.setUserShare(userShare);

const messageBase64 = btoa('Hello, World!');
const signature = await capsule.signMessage(walletId, messageBase64);

const rlpEncodedTxBase64 = '...'; // Your RLP encoded transaction
const chainId = '1'; // Ethereum mainnet
const txSignature = await capsule.signTransaction(walletId, rlpEncodedTxBase64, chainId);

You can also sign using popular Ethereum libraries like Ethers or Viem or Solana-Web3.js. These libraries provide a more familiar interface for developers working with transactions and messages.

For more detailed information on signing transactions and messages, please refer to our ecosystem guides. EVM Ecosystem, Solana Ecosystem, and Cosmos Ecosystem

Claiming a Pregenerated Wallet (Optional)

When you want to allow a user to claim their pregenerated wallet, you can use the claimPregenWallets method. This process typically involves user authentication and transfers ownership of the wallet to the user’s Capsule account.

const recoverySecret = await capsule.claimPregenWallets(userEmail);

Before claiming, you might need to update the wallet’s identifier, especially if you used a non-email identifier initially:

await capsule.updateWalletIdentifierPreGen(userEmail, walletId);

The claiming process usually involves these steps:

  1. Authenticate the user (e.g., email verification, OAuth)
  2. Update the wallet identifier if necessary
  3. Claim the wallet

Example flow:

// Assume user is authenticated and we have their email
const userEmail = 'user@example.com';

// Update identifier if necessary
await capsule.updateWalletIdentifierPreGen(userEmail, walletId);

// Claim the wallet
const recoverySecret = await capsule.claimPregenWallets(userEmail);

console.log('Wallet claimed successfully. Recovery secret:', recoverySecret);

Best Practices and Considerations

Reference Example

For a complete example demonstrating the usage of pregeneration methods, refer to our Wallet Pregeneration Example.

This example provides a comprehensive flow of pregeneration method usage in a React application context.