Pregenerated wallets are a powerful feature of Para that enable server-side wallet creation without requiring user authentication. This approach allows your application to perform blockchain operations autonomously, making it ideal for agent-based systems, automated workflows, and backend services.

The pregeneration flow works by creating a wallet associated with an identifier of your choice (email, phone, username, or custom ID). Para then provides you with the user share of the 2/2 MPC key, which you must securely store on your server until it’s either claimed by a user or used for signing operations.

Key Benefits

  • Authentication-free operations: Create and use wallets without requiring user authentication
  • Autonomous agents: Provide blockchain capabilities to AI agents or automated systems
  • User pre-provisioning: Create wallets for existing user bases before they interact with your application
  • Server-side signing: Perform blockchain operations entirely from your backend

Creating a Pregenerated Wallet

import { Para as ParaServer, Environment, WalletType } from "@getpara/server-sdk@alpha";

// Initialize the Para Server SDK
const paraServer = new ParaServer(Environment.BETA, "YOUR_API_KEY");

// Check if a wallet already exists for this identifier
const hasWallet = await paraServer.hasPregenWallet({
  pregenId: { email: "user@example.com" },
});

// Create a pregenerated wallet if needed
if (!hasWallet) {
  const pregenWallet = await paraServer.createPregenWallet({
    type: 'EVM', // or 'SOLANA', 'COSMOS'
    pregenId: { email: "user@example.com" },
  });
  
  // Now use the pregenerated wallet
}

Method Parameters

createPregenWallet Args
object

The identifier can be an email or phone number, a third-party user ID (for Farcaster, Telegram, Discord, or X), or a custom ID relevant to your application. Choose an identifier that works best for your application architecture.

Securing the User Share

After creating a pregenerated wallet, you must securely store the user share. This component is critical for the wallet’s operation and security.

// Retrieve the user share for the pregenerated wallet
const userShare = await paraServer.getUserShare();

// Store this user share securely in your database
// NEVER store this in plain text - always encrypt it!

You must securely store this user share in your backend, associated with the user’s identifier. If this share is lost, the wallet becomes permanently inaccessible.

Secure Storage Best Practices

We strongly recommend implementing robust encryption for user shares both in transit and at rest. Consider using a high-entropy encryption key with AES-GCM encryption. Do not store encryption keys in the same database as the encrypted data.

Para offers pre-launch security reviews for teams in the Growth tier or above. Reach out to the Para team for assistance with your implementation!

Storage Security Recommendations

  • Encrypt user shares in-transit and at-rest
  • Implement access controls for your share database
  • Maintain regular database backups to prevent data loss
  • Create disaster recovery processes for compromise scenarios
  • Have a key rotation plan in case of security incidents
  • Complete security fire drills before launching

Using a Pregenerated Wallet

To use a pregenerated wallet for blockchain operations, you need to:

  1. Retrieve the encrypted user share from your database
  2. Decrypt the user share
  3. Load it into your Para client instance
// Retrieve and decrypt the user share from your database
const encryptedUserShare = await database.getUserShare(walletId);
const userShare = decryptUserShare(encryptedUserShare);

// Load the user share into the Para client
await paraServer.setUserShare(userShare);

When implementing setUserShare in API routes or serverless functions, it’s critical to create a new Para client instance for each request. This prevents different users’ shares from conflicting with each other. Creating a new Para client has minimal overhead and won’t impact request performance.

Signing Operations

Once the user share is loaded, you can test the wallet functionality by signing a message. However, for production use, we recommend using the blockchain library integrations described in the next section.

// Test signing a message
const messageBase64 = Buffer.from("Hello, World!").toString('base64');
const signature = await paraServer.signMessage({
  walletId,
  messageBase64,
});

Using with Blockchain Libraries

Pregenerated wallets work seamlessly with all blockchain integration libraries. Here are some examples:

Wallet Claiming Flow

Claiming pregenerated wallets must be done client-side with the Para Client SDK. The Server SDK does not support the key rotation operations required for wallet claiming.

For applications that need to transfer ownership of pregenerated wallets to users, you’ll need to implement a client-side claiming flow. This process involves:

  1. Securely transferring the user share from your server to the client
  2. Loading the share into the client-side Para instance
  3. Using the client SDK to claim the wallet

For a comprehensive guide on implementing the claiming flow, refer to our web documentation:

Core Pregeneration Methods

Use Cases

Best Practices

  • Choose appropriate identifiers that align with your application architecture
  • Implement robust encryption for user share storage
  • Create backup systems to prevent data loss
  • Use a separate database for user share storage with enhanced security
  • Monitor for suspicious activity in your pregenerated wallet systems
  • Implement rate-limiting to prevent abuse of wallet creation
  • Document your recovery procedures for security incidents
  • Consider multi-region replication for high-availability systems

Example Implementation

Here’s a reference example demonstrating the creation and secure storage of pregenerated wallets:

Community Showcase

Check out some novel use cases of pregenerated wallets created by our community: