Skip to content

Send UserOperations

In this last section, you will enable users to send UserOperations through their newly created Embedded Account on your app.

Add button to Send UserOperations

Add a new src/components/SendUOButton.tsx file and incorporate it onto the src/components/ProfileCard.tsx for authenticated users to send a UO. These files should now look as follows:

tsx
"use client";

import { useSmartAccountClient, useUser } from "@alchemy/aa-alchemy/react";
import { SendUOButton } from "./SendUOButton";

export const ProfileCard = () => {
  const user = useUser();
  const { client } = useSmartAccountClient({
    type: "MultiOwnerModularAccount",
  });

  return (
    <div className="flex flex-row rounded-lg bg-white p-10 dark:bg-[#0F172A]">
      <div className="flex flex-col gap-8">
        <div className="text-lg font-semibold">Welcome to your profile!</div>
        <div className="flex flex-col gap-4">
          <div className="flex flex-col gap-2">
            <div>Account address</div>
            <div className="text-wrap rounded-lg p-3 dark:bg-[#1F2937] dark:text-[#CBD5E1]">
              {client?.account.address}
            </div>
          </div>
          <div className="flex flex-col gap-2">
            <div>Email</div>
            <div className="text-wrap rounded-lg p-3 dark:bg-[#1F2937] dark:text-[#CBD5E1]">
              {user?.email}
            </div>
          </div>
        </div>
        <SendUOButton />
      </div>
    </div>
  );
};
tsx
import {
  useSendUserOperation,
  useSmartAccountClient,
} from "@alchemy/aa-alchemy/react";
import { useState } from "react";
import { Address } from "viem";
import { arbitrumSepolia } from "viem/chains";

export const SendUOButton = () => {
  const [vitalik] = useState<Address>(
    "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B"
  );

  const { client } = useSmartAccountClient({
    type: "MultiOwnerModularAccount",
    gasManagerConfig: {
      policyId: process.env.NEXT_PUBLIC_ALCHEMY_GAS_MANAGER_POLICY_ID!,
    },
    opts: {
      txMaxRetries: 20,
    },
  });
  const {
    sendUserOperation,
    sendUserOperationResult,
    isSendingUserOperation,
    error: isSendUserOperationError,
  } = useSendUserOperation({ client, waitForTxn: true });

  return (
    <div className="flex flex-col">
      {sendUserOperationResult == null ? (
        <button
          className="w-full transform rounded-lg bg-[#363FF9] p-3 font-semibold text-[#FBFDFF] transition duration-500 ease-in-out hover:scale-105 disabled:bg-[#C0D4FF] disabled:hover:scale-100 dark:disabled:bg-[#4252C5]"
          onClick={async () =>
            sendUserOperation({
              uo: {
                target: vitalik,
                data: "0x",
              },
            })
          }
          disabled={isSendingUserOperation}
        >
          <div className="flex flex-row items-center justify-center gap-3">
            {isSendingUserOperation && (
              // Loading spinner
              <div
                className="text-surface inline-block h-4 w-4 animate-spin rounded-full border-2 border-solid border-current border-e-transparent align-[-0.125em] motion-reduce:animate-[spin_1.5s_linear_infinite] dark:text-white"
                role="status"
              ></div>
            )}
            {isSendingUserOperation
              ? "Sending"
              : isSendUserOperationError
              ? "An error occurred. Try again!"
              : "Send a test transaction"}
          </div>
        </button>
      ) : (
        <a
          href={`${arbitrumSepolia.blockExplorers.default.url}/tx/${sendUserOperationResult.hash}`}
          target="_blank"
          rel="noopener noreferrer"
          className="w-full transform rounded-lg bg-[#363FF9] p-3 text-center font-semibold text-[#FBFDFF] transition duration-500 ease-in-out hover:scale-105 dark:disabled:bg-[#4252C5]"
        >
          View transaction details
        </a>
      )}
    </div>
  );
};

That's it! At this point, run the application using:

bash
npm run dev
bash
yarn dev
bash
pnpm run dev

You've now enabled users to sendUOs from their Embedded Account on your application, and the experience should look like the video below!

Congratulations! Using Account Kit, the Alchemy Signer, and Alchemy Modular Account, you created an application that authenticates a user by email to create their Embedded Account, and then uses that account to send a UserOperation!

Dive Deeper

You can do so much more with Embedded Accounts than this Quickstart guide could share!

  1. To learn more about the Alchemy Signer and how to support passkey login (and eventually social login), check out the technical docs for more details.
  2. To learn more about different smart account options available for your applications, check out the section Choosing a smart account.
  3. To learn more about how to use your smart accounts and what Account Kit offers to enhance users' web3 experiences, check out a number of guides we have in the Using smart accounts section, covering from basic to advanced usages.