guides
Guide

Wallet Pregeneration

Magic Staff · August 13, 2024
Wallet Pregeneration

Wallet Pregeneration offers a streamlined and efficient way to create non-custodial wallets programmatically without requiring end users to initiate or complete an authentication flow. This feature simplifies the onboarding process, making digital ownership more accessible and straightforward for your users. This feature is currently in beta, so please reach out to Magic for early access!

Using Magic's Wallet Pregeneration, you can generate wallets that users can later claim by authenticating through your application. This approach is particularly useful for a variety of use cases, such as preloading wallets with NFTs or tokens. For instance, you might want to provide new users with initial token balances or exclusive NFTs as part of a promotion or reward system. By preloading these assets into pregenerated wallets, you can enhance user engagement and provide a smooth and rewarding onboarding experience.

This guide demonstrates how to use the Wallet Pregeneration feature. We'll cover the steps to programmatically create these wallets, preload them with Sepolia tokens and allow users to claim them with minimal friction. The examples provided are based on a Next.js web app generated using the Magic CLI tool but can be easily adapted for any JavaScript framework.

#Project prerequisites

To follow along with this guide, you’ll need the following:

  1. A Magic Publishable API Key
  2. A Magic Secret API Key (for wallet pregeneration requests)
  3. Early access to the feature (Reach out to Magic for this)
  4. A web client

You can get your Publishable and Secret API Key from your Magic Dashboard.

We’ll use the make-scoped-magic-app CLI tool to bootstrap a Next.js app with Magic authentication already baked into the client. You’re welcome to use your own client, but this tutorial and its accompanying code snippets assume the output of the make-scoped-magic-app CLI as the starting point.

The make-scoped-magic-app CLI tool is an easy way to bootstrap new projects with Magic. To generate your application, simply run the command below in the shell of your choice. Be sure to replace <YOUR_PUBLISHABLE_API_KEY> with the Publishable API Key from your Magic Dashboard.

Bash
01npx make-scoped-magic-app \\
02    --template nextjs-dedicated-wallet \\
03    --network ethereum-sepolia \\
04    --login-methods EmailOTP \\
05    --publishable-api-key <YOUR_PUBLISHABLE_API_KEY>

This will bootstrap the starting point of the tutorial for you. In the scaffolded project, be sure to add your Magic Publishable API Key to the .env as NEXT_PUBLIC_MAGIC_API_KEY.

.env
01# Publishable API Key found in the Magic Dashboard
02NEXT_PUBLIC_MAGIC_API_KEY=pk_live_1234567890
03
04# The RPC URL for the blockchain network
05NEXT_PUBLIC_BLOCKCHAIN_NETWORK=ethereum-sepolia

#Wallet pregeneration

There are 3 available endpoints related to the wallet pregeneration process. This section will guide you through using these endpoints to create, monitor, and query pregenerated wallets. By utilizing these endpoints, you can programmatically generate wallets for your users, track the status of wallet creation, and query detailed information about the generated wallets.

This approach ensures that you have full control and visibility over the wallet pregeneration process. You can use any HTTP client to send the POST requests. For this guide we will be using cURL requests. Let's take a further look into the details of each endpoint and how to use them effectively.

note

Each application needs to be manually enabled to use the Wallet Pregeneration feature, so reach out to Magic for early access!

#Create wallets

To create wallets tied to specific emails, we send a payload with identifiers along with the Magic secret key to the create_wallets endpoint.

The identifiers array contains identifier_payload objects, which consist of 1 or multiple of the users email addresses and identifier type, which in this case is email_address. You can pregenerate multiple wallets in a single POST request, but for the sake of this guide we will just be creating one wallet.

The first thing we need to do is send a POST request to generate the wallets and link them to the email addresses attached. The request requires the Magic secret API key as a header and the identifiers payload as the data.

Bash
01curl --request POST \\
02  --url '<https://api.magic.link/v1/api/wallet_pregen/create_wallets>' \\
03  --header 'X-Magic-Secret-Key: <your_magic_secret_api_key>' \\
04  --header 'Content-Type: application/json' \\
05  --data '{
06    "identifiers": [
07      {
08⁠        "identifier": "user1@example.com",
09        "identifier_type": "email_address" 
10      },
11      // You can add more identifier_payload objects as needed
12    ]
13  }'

Once you send the request you will receive an object back from the request containing the data, which will include a job_id if the request was successful, error_code, message and status of the request. The status will return “ok” if the request is successful.

Now that we’ve successfully generated the wallets, we can take the job_id and check if users have claimed their wallets.

#Query job status

The get_job_status endpoint allows you to monitor the progress and status of wallet pregeneration jobs. This is essential for ensuring that the wallets are created successfully and are ready for users to claim. By querying the job status, you can retrieve detailed information about the job, such as the number of wallets processed, any errors encountered, and the overall status of the job.

Similar to the previous POST request, we will need to add the Magic secret API key as headers and add the job_id from the previous request as the body.

The body should look similar to this:

Json
01{
02    "job_id": "91a5be54-61bf-4761-e89k-b7f35ace81d3"
03}

To query the job status, you can use the following cURL command. This command sends a POST request to the get_job_status endpoint with the necessary headers and body parameters:

Bash
01curl --request POST \\
02  --url '<https://api.magic.link/v1/api/wallet_pregen/get_job_status>' \\
03  --header 'X-Magic-Secret-Key: <your_magic_secret_api_key>' \\
04  --header 'Content-Type: application/json' \\
05  --data '{
06    "job_id": "91a5be54-61bf-4761-e89k-b7f35ace81d3"
07  }'

The response from the get_job_status endpoint provides detailed information about the wallet pregeneration job.

Json
01{
02    "data": {
03        "client_id": "A5cJpjmJk3eQq4PXC9uJuoWESlcD3_CIwZgvDVdY0wg=",
04        "created_at": 1716331284,
05        "expires_at": 1718923161,
06        "job_id": "91a5be54-61bf-4761-e89k-b7f35ace81d3",
07        "key_generation_stats": {
08            "errors": 0,
09            "processed": 1,
10            "total": 1
11        },
12        "status": "SUCCESS",
13        "updated_at": 1716331161
14    },
15    "error_code": "",
16    "message": "",
17    "status": "ok"
18}

Here is a brief overview of the key fields in the return object:

  • data: Contains the main details of the job.
    • client_id: A unique identifier for the client.
    • created_at: Timestamp of when the job was created.
    • expires_at: Timestamp of when the job expires.
    • job_id: The unique identifier for the job.
    • key_generation_stats: Statistics about the key generation process.
      • errors: Number of errors encountered.
      • processed: Number of wallets processed.
      • total: Total number of wallets to be generated.
    • status: The current status of the job (e.g., SUCCESS, PENDING).
    • updated_at: Timestamp of the last update to the job status.
  • error_code: Error code if any issues occurred (empty if no errors).
  • message: Additional message information (empty if no issues).
  • status: Overall status of the API request (e.g., "ok").

Once we confirm that the wallet(s) have been generated, we can move on to the next step and query the identifiers tied to the pregenerated wallet public addresses.

#Query wallet identifiers

The get_identifiers endpoint allows you to retrieve detailed information about the identifiers associated with pregenerated wallets. This query is useful for checking which specific identifiers, such as email addresses, are linked to the pregenerated wallet public addresses. Additionally, you can filter the results to see which wallets have been claimed by users and set limits on the number of results returned.

We will be using this endpoint to retrieve the users wallet address so we can send it some tokens. This way, when a user logs in to the Magic application using Email OTP, they will see a balance in their wallet from the transfer.

The body for this request should contain the job_id, along with optional parameters of claimed and limit.

Json
01{
02  "job_id": "91a5be54-61bf-4761-e89k-b7f35ace81d3",
03  "claimed": false, // optional
04  "limit": 1 // optional 
05}

Just like the previous requests, we should set the Magic private API key as the X-Magic-Secret-Key header. Send the POST request with the required payload to retrieve the identifiers tied to the pregenerated wallet public addresses. This will allow you to see which identifiers are associated with each wallet and whether they have been claimed.

Here's an example of the POST request to the get_identifiers endpoint:

Bash
01curl --request POST \\
02  --url '<https://api.magic.link/v1/api/wallet_pregen/get_identifiers>' \\
03  --header 'X-Magic-Secret-Key: <your_magic_secret_api_key>' \\
04  --header 'Content-Type: application/json' \\
05  --data '{
06    "job_id": "91a5be54-61bf-4761-e89k-b7f35ace81d3",
07    "claimed": false, // optional
08    "limit": 10 // optional 
09  }'

If successful, the response will include detailed information about the identifiers associated with the pregenerated wallets. This information will indicate whether the wallets have been claimed and provide the corresponding public addresses. Here’s an example of the response you can expect:

Json
01{
02  "data": {
03    "identifiers": [
04      {
05          "claimed": false,
06          "expires_at": 1718925889,
07          "identifier": "youremail@example.com",
08          "identifier_type": "email_address",
09          "job_id": "91a5be54-61bf-4761-e89k-b7f35ace81d3",
10          "public_address": "0xBAcFD5E443eFDFECb9850a9d8a23C33701E66742",
11          "status": "success",
12          "status_detail": "Successfully generated wallet"
13      }
14    ]
15  },
16  "error_code": "",
17  "message": "",
18  "status": "ok"
19}

This information allows you to effectively manage and track the pregenerated wallets, ensuring that each identifier is correctly associated with a wallet and verifying the claim status of your digital assets.

Now that we’ve got the user information, we want to copy the public_address of the user so we can transfer it some Sepolia ETH testnet tokens.

#Fund wallet

For this guide, we will just be transferring some testnet tokens to the pregenerated wallet. However, you can also do things like airdrop NFTs, distribute loyalty points or issue event tickets to enhance user engagement and provide additional value.

You can either transfer funds from an existing wallet or use a Sepolia faucet and paste in the unclaimed wallet address from the previous step. Keep that wallet address handy, as we will want to cross reference it with the wallet address displayed in our application after logging in.

Once that transaction is successful we can move on to the next step.

#Claim wallet

The application we generated earlier has Email One-Time Passcode (OTP) enabled, which streamlines the authentication process for users. With this feature, along with our pregenerated wallets, all we need to do is log in using one of the email address that we added as the identifier payload during the wallet pregeneration process.

Run your local server and navigate to your localhost. You will see a component for logging in with an email. Add the email that you pregenerated the wallet for and retrieve the OTP code from that email’s inbox. Back in the app, paste the code into the prompt and continue.

Congratulations! You should now see some cards displayed on the screen including one with your pregenerated wallet address and balance.

#Next steps

We have a suite of resources to help developers and companies with a wide variety of use cases. Below are some ideas to get you started, but feel free to browse our documentation or reach out with specific questions.

Let's make some magic!