Skip to content

Transaction Frames

Frames can initiate transactions that apps that integrate Frames can complete, calling back your Frame.

An example snippet can be found below.

// ...
buttons: [
  <Button action="tx" target="/txdata" post_url="/frames">
    Buy a unit
  </Button>,
];

In your /txdata route you should handle the request and return transaction data that conforms to the TransactionTargetResponseSendTransaction type. The transaction helper function can be used to create the transaction data.

./app/frames/txdata/route.tsx
import { frames } from "../frames";
import { transaction } from "frames.js/core";
 
export const POST = frames(async (ctx) => {
  // Do something with the request data to generate transaction data
 
  // Create calldata for the transaction using Viem's `encodeFunctionData`
  const myCalldata = encodeFunctionData({
    abi: myContractAbi,
    functionName: "myFunction",
    args: [myArg1, myArg2],
  });
 
  // Return transaction data that conforms to the correct type
  return transaction({
    chainId: "eip155:10", // OP Mainnet
    method: "eth_sendTransaction",
    params: {
      abi: myContractAbi,
      to: myContractAddress,
      data: calldata,
      value: myValue.toString(),
    },
  });
});

Use the Transactions starter as a template to build your transaction Frames.

Open in StackBlitz

Using the connected wallet address

The client will include the user's connected wallet address that will be executing the transaction in the frame action payload in the when a frame button with action="tx" set is pressed.

The address is available in the context under the key connectedAddress.

Note:

  • The address is only available when the user has connected a wallet to the client the frame button pressed is has a tx action.
  • connectedAddress differs from the requesterVerifiedAddresses returned by the farcasterHubContext middleware.
./app/frames/txdata/route.tsx
import { frames } from "../frames";
import { transaction } from "frames.js/core";
 
export const POST = frames(async (ctx) => {
  if (!ctx.message) {
    throw new Error("No message");
  }
 
  const userAddress = ctx.message.connectedAddress;
 
  // Do something with the user's connected address that will be executing the tx
 
  return transaction(txData);
});