Skip to content

Farcaster Frames

Enable cross-chain and cross-token payments in Farcaster Frames using Glide

In this guide, we will create a Frames app that lets users mint an NFT on Zora using DEGEN on Base.

Here's the NFT contract we'll use: 0xb88f2f291d...8755accc9ed9c77ce. The contract has a mintFor function that allows users to mint by sending ETH to the contract on Zora.

We'll use the Glide to let users pay for the minting using DEGEN on Base.

Setup

We'll use the Frog.fm framework to build a Farcaster Frames app. But, you can use any framework you like. Glide works with the underlying Frames spec.

Steps

1. Create a frog app

If you haven't already, create a Frog app. You can learn more about Frog here.

npm
npm init frog

2. Install Glide & viem

npm
npm install @paywithglide/glide-js viem

3. Create a Glide config

import { createGlideConfig, chains } from "@paywithglide/glide-js";
 
export const config = createGlideConfig({
  projectId: "your project id",
 
  // Lists the chains where payments will be accepted
  chains: [chains.base],
});

4. Create the default frame

The default frame shows an image of the NFT and a button to mint the NFT.

The button has a target of /mint, which we'll use to create the Glide session for minting the NFT.

It also has an action set to /tx-status, which we'll use to show the transaction status once the user has paid.

app.frame("/", (c) => {
  return c.res({
    image:
      "https://storage.withfabric.xyz/loom/cff20f6d-e485-4271-9f54-47cf53334abd.png",
    imageAspectRatio: "1:1",
 
    intents: [
      <Button.Transaction target="/mint">Mint with Degen</Button.Transaction>,
    ],
 
    action: "/tx-status",
  });
});

5. Handle the /mint route

The mint route creates a Glide session to mint the NFT on Zora using DEGEN on Base.

The Glide session contains an unsigned payment transaction for making the payment using DEGEN. This route returns the payment transaction to the user so the Farcaster client can let the user sign and send it.

app.transaction("/mint", async (c) => {
  const { address } = c;
 
  const { unsignedTransaction } = await createSession(config, {
    chainId: chains.zora.id,
    account: address,
 
    paymentCurrency: currencies.degen,
 
    abi: fabricABI,
    address: "0xb88f2f291d796de8b44993b8755accc9ed9c77ce",
    functionName: "mintFor",
    args: [address, 100000000000n],
    value: 100000000000n,
  });
 
  if (!unsignedTransaction) {
    throw new Error("missing unsigned transaction");
  }
 
  // Return the payment transaction to the user
  return c.send({
    chainId: `eip155:${chains.base.id}`,
    to: unsignedTransaction.to,
    data: unsignedTransaction.input,
    value: hexToBigInt(unsignedTransaction.value),
  });
});

6. Handle the /tx-status route

In this route, we'll use the payment transaction hash provided to us by the Farcaster client to get the Glide session status and show the user the status of the transaction.

If the transaction is pending, we'll show a button to refresh the status.

app.frame("/tx-status", async (c) => {
  const { transactionId, buttonValue } = c;
 
  // The payment transaction hash is passed with transactionId if the user just completed the payment. If the user hit the "Refresh" button, the transaction hash is passed with buttonValue.
  const hash = transactionId || buttonValue;
 
  if (!txHash) {
    throw new Error("missing transaction hash");
  }
 
  try {
    let session = await getSessionByPaymentTransaction(config, {
      chainId: chains.base.id,
      hash,
    });
 
    // Wait for the session to complete. It can take a few seconds
    session = await waitForSession(config, session.sessionId);
 
    return c.res({
      image: (
        <div
          style={{
            display: "flex",
            justifyContent: "center",
            fontSize: 64,
            marginTop: "200px",
          }}
        >
          Mint complete!
        </div>
      ),
      intents: [
        <Button.Link
          href={`https://explorer.zora.energy/tx/${session.sponsoredTransactionHash}`}
        >
          View on Zora
        </Button.Link>,
      ],
    });
  } catch (e) {
    // If the session is not found, it means the payment is still pending.
    // Let the user know that the payment is pending and show a button to refresh the status.
    return c.res({
      image: (
        <div
          style={{
            display: "flex",
            justifyContent: "center",
            fontSize: 44,
            marginTop: "200px",
          }}
        >
          Waiting for payment confirmation..
        </div>
      ),
 
      intents: [
        <Button value={hash} action="/tx-status">
          Refresh
        </Button>,
      ],
    });
  }
});

Success

You've successfully integrated Glide with Farcaster Frames to let users pay for minting an NFT using DEGEN on Base.