Introduction

This guide shows you how to generate an embedded wallet in both Ethereum and Solana from a Farcaster frame based on an email address input.

We will use a frame building library in this example, specifically Frog.fm however you can use any frame builder you like.

You can find a full demo of this implementation here and the source code for the demo here.

Implementation

Step 1: Configure your Dynamic app

Step 2: Bootstrap your frame

First, you’ll need to create a new frame template Frog.fm, they provide instructions on how to do this here. Specifically, they allow you to create a new frame and deploy to vercel with a single command. See here for more info.

Step 3: Check out the Dynamic API endpoint

You’ll be utilizing our new API endpoint built especially for frames. This endpoint is called POST https://app.dynamicauth.com/api/v0/environments/{environmentId}/embeddedWallets/farcaster and it takes in a JSON object with the following properties:

The full reference for the endpoint can be found here

{
  "chains": [
    "EVM"
  ],
  "email": "[email protected]",
  "fid": 123
}

The chains property is an array of the chains you want to support with the wallet. Currently, the supported chains are EVM and SOL.

The email property is the email address of the user you want to generate the wallet for, it must be a valid email.

The fid property is the Farcaster user ID for whom you want to use to generate the wallet. You can find the FID for a user from within the Warpcast profile tab by clicking on the three dots and choosing “about”.

Step 4: Define our creation function a frame with an email input

In your frame code, you’ll need to define a function that will be called when the user submits their email address. This function will call the Dynamic API endpoint to generate the wallet and then display the wallet to the user.

import { configDotenv } from "dotenv";
import { ChainEnum } from "@dynamic-labs/sdk-api/models/ChainEnum";
import { UserResponse } from "@dynamic-labs/sdk-api/models/UserResponse";
configDotenv();

const key = process.env.KEY;
const environmentId = process.env.ENVIRONMENT_ID;
let newWallets: string[];

const createEmbeddedWallet = async (
  email: string,
  fid: number,
  chains: ChainEnum[]
) => {
  console.log("Creating embedded wallets for", email, fid, chains);
  const options = {
    method: "POST",
    headers: {
      Authorization: `Bearer ${key}`,
      "Content-Type": "application/json",
    },

    body: JSON.stringify({
      email,
      fid,
      chains,
    }),
  };

  const response = await fetch(
    `https://app.dynamic-preprod.xyz/api/v0/environments/${environmentId}/embeddedWallets/farcaster`,
    options
  ).then((r) => r.json());

  console.log(response);
  newWallets = (response as UserResponse).user.wallets.map(
    (wallet: any) => wallet.publicKey
  );

  return newWallets;
};

Note that the key should be a Dynamic.xyz API key. You can get one from the following page: https://app.dynamic.xyz/dashboard/developer/api (you can find your ENVIRONMENT_ID on the same page)

Step 5: Call the creation function when the user submits their email

For this we will need to define our frame UI and call the createEmbeddedWallet function on submit. it will look like this:

import { Button, Frog, TextInput } from "frog";
import { handle } from "frog/vercel";

app.frame("/", async (c) => {
  const { frameData, inputText, status, buttonValue } = c;
  const isValidEmail = inputText
    ? /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(inputText)
    : false;

  const fid = frameData?.fid;
  let error = status != "initial" && (!isValidEmail || !fid);

  if (
    !error &&
    status != "initial" &&
    isValidEmail &&
    inputText &&
    fid &&
    buttonValue === "submit"
  ) {
    try {
      newWallets = await createEmbeddedWallet(inputText, fid, [
        ChainEnum.Sol,
        ChainEnum.Evm,
      ]);

      // Add any additional logic specific to your frame integration here. e.g. airdrop an NFT to the embedded wallet, etc.
    } catch (e) {
      error = true;
    }
  }

  return c.res({
    image: (
      <div
        style={{
          alignItems: "center",
          background: "linear-gradient(to right, #432889, #17101F)",
          backgroundSize: "100% 100%",
          display: "flex",
          flexDirection: "column",
          flexWrap: "nowrap",
          height: "100%",
          justifyContent: "center",
          textAlign: "center",
          width: "100%",
        }}
      >
        <div
          style={{
            alignItems: "center",
            background: "linear-gradient(to right, #432889, #17101F)",
            backgroundSize: "100% 100%",
            display: "flex",
            flexDirection: "column",
            flexWrap: "nowrap",
            height: "100%",
            justifyContent: "center",
            textAlign: "center",
            width: "100%",
            fontSize: 30,
            fontStyle: "normal",
          }}
        >
          {status === "initial" && !error ? (
            <div style={{ color: "white" }}>
              Create Dynamic-powered embedded wallets
            </div>
          ) : newWallets && newWallets.length > 0 ? (
            newWallets.map((wallet, index) => (
              <div key={index} style={{ color: "white" }}>
                {wallet}
              </div>
            ))
          ) : (
            <div style={{ color: "white" }}>
              No wallets created yet or an error occurred.
            </div>
          )}
        </div>
      </div>
    ),
    intents: [
      <TextInput placeholder="Enter a valid email" />,
      <Button value="submit">Create SOL + EVM Embedded Wallets</Button>,
    ],
  });
});

export const GET = handle(app);
export const POST = handle(app);

Step 6: Test the frame

You can now test the frame by running it locally and entering an email address. You should see the wallet address displayed on the screen after you submit the email address.

Step 7: Deploy the frame

With Frog.fm you can deploy quickly using Vercel. They have a great guide for it here.

Step 8: Connect to your dApp

Now that you’ve created embedded wallets for your users, which are linked to their email and Farcaster ID so you can set up Dynamic with your dApp, and the user can log into your dApp with either their email or Farcaster account to access their embedded wallets!