> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getpara.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Account Abstraction

> Implement ERC-4337 and EIP-7702 Account Abstraction in React Native with Para

export const Link = ({href, label, newTab = false}) => {
  const [isHovered, setIsHovered] = useState(false);
  return <a href={href} target={newTab ? '_blank' : '_self'} rel={newTab ? 'noopener noreferrer' : undefined} className="not-prose inline-block relative text-black font-semibold cursor-pointer border-b-0 no-underline" onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
      {label}
      <span className={`absolute left-0 bottom-0 w-full rounded-sm bg-gradient-to-r from-orange-600 to-purple-600 transition-all duration-300 ${isHovered ? 'h-0.5' : 'h-px'}`} />
    </a>;
};

## Account Abstraction

Account abstraction (AA) replaces traditional externally owned accounts (EOAs) with programmable smart contract accounts. This unlocks capabilities that EOAs alone cannot provide:

* **Gas sponsorship** — let users transact without holding native tokens for gas fees
* **Batched transactions** — bundle multiple operations into a single atomic transaction
* **Session keys** — grant temporary, scoped permissions without exposing the primary key
* **Custom authorization** — implement multi-factor auth, spending limits, or recovery logic at the account level
* **Programmable accounts** — create accounts with built-in rules for corporate or multi-user scenarios

Two standards are currently in use for AA on EVM-based chains:

|                     | EIP-4337                                                        | EIP-7702                                                   |
| ------------------- | --------------------------------------------------------------- | ---------------------------------------------------------- |
| **How it works**    | UserOperations processed by bundlers via an EntryPoint contract | EOA delegates to a smart contract via a type-4 transaction |
| **Account address** | New smart contract address (different from EOA)                 | Same as your EOA                                           |
| **Chain support**   | All EVM chains                                                  | Requires chain-level support                               |
| **Infrastructure**  | Bundler + Paymaster                                             | Provider-dependent                                         |
| **Gas overhead**    | Higher (extra validation steps)                                 | Lower (native execution)                                   |
| **Maturity**        | Production-ready                                                | Emerging                                                   |
| **Best for**        | Maximum compatibility, dedicated smart wallet                   | Keeping EOA address, simpler flows                         |

Both standards support **gas sponsorship** and **batched transactions**.

<Tip>
  Learn more about [EIP-4337](https://eips.ethereum.org/EIPS/eip-4337) and [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) on the Ethereum Improvement Proposals site.
</Tip>

## Para Integrations

Para acts as the **signer** (EOA) that controls smart contract wallets — it is not a smart wallet itself. Para handles secure key management via MPC, while the AA provider deploys and manages the smart contract account on-chain. This means your users' private keys remain secure and under their control regardless of which provider you choose.

Para wraps each provider in a shared `SmartAccount` interface. Whether you use EIP-4337 or EIP-7702 mode, your application code stays the same — you can swap providers or switch between standards without rewriting transaction logic.

Every provider integration is available as an **action function** (`createXxxSmartAccount`) — an imperative async function you can call anywhere, including outside React components, inside custom hooks, or in server-side code. React applications also get a **hook** (`useXxxSmartAccount`) — a declarative wrapper powered by React Query that handles initialization, caching, and automatic re-creation when config changes.

Both return the same `SmartAccount` object:

```typescript theme={null}
import type { Chain, Hex, LocalAccount, TransactionReceipt } from "viem";

interface SmartAccount {
  smartAccountAddress: Hex;              // On-chain account address
  signer: LocalAccount;                 // Para viem signer
  chain: Chain;                          // Configured chain
  mode: "4337" | "7702";                // Account type
  provider: string;                      // Provider name

  // Send a single transaction and wait for receipt
  sendTransaction(params: {
    to: Hex;
    value?: bigint;
    data?: Hex;
  }): Promise<TransactionReceipt>;

  // Send batched transactions atomically
  sendBatchTransaction(calls: Array<{
    to: Hex;
    value?: bigint;
    data?: Hex;
  }>): Promise<TransactionReceipt>;

  client: any;                           // Provider-specific client for advanced usage
}
```

When using `mode: "7702"`, the return type narrows to include an optional `delegationAddress` field — the smart
contract the EOA delegates to. When using `mode: "4337"`, `smartAccountAddress` is the counterfactual smart
contract address (different from `signer.address`).

## Provider Comparison

| Provider                                                      | 4337 | 7702 | External Wallets | Chain Restrictions                        | Key Feature                                       |
| ------------------------------------------------------------- | :--: | :--: | :--------------: | ----------------------------------------- | ------------------------------------------------- |
| [Alchemy](https://accountkit.alchemy.com/react/quickstart)    |   ✓  |   ✓  |         ✓        | Alchemy-supported chains                  | Modular accounts, gas policies                    |
| [ZeroDev](https://docs.zerodev.app/)                          |   ✓  |   ✓  |         ✓        | Any EVM chain                             | Kernel accounts, session keys, plugins            |
| [Pimlico](https://docs.pimlico.io/)                           |   ✓  |   ✓  |         ✓        | Any EVM chain                             | Permissionless SDK, flexible paymaster            |
| [Biconomy](https://docs.biconomy.io/)                         |   ✓  |   ✓  |         ✓        | MEE-supported chains                      | Cross-chain orchestration via MEE                 |
| [Thirdweb](https://portal.thirdweb.com/)                      |   ✓  |   ✓  |         ✓        | Any EVM chain                             | Smart wallets, gas sponsorship                    |
| [Gelato](https://docs.gelato.network/)                        |      |   ✓  |                  | Any EVM chain                             | Native 7702, built-in gas sponsorship             |
| [Porto](https://porto.sh)                                     |      |   ✓  |                  | [Multiple chains](https://porto.sh/relay) | 7702-native relay, merchant-based gas sponsorship |
| [Safe](https://docs.safe.global/)                             |   ✓  |      |         ✓        | Any EVM chain                             | Multi-sig, modular accounts                       |
| [Rhinestone](https://docs.rhinestone.wtf/)                    |   ✓  |      |         ✓        | Any EVM chain                             | Cross-chain orchestration                         |
| [Coinbase Developer Platform](https://docs.cdp.coinbase.com/) |   ✓  |      |                  | Base, Base Sepolia only                   | Coinbase smart accounts                           |

## Provider Guides

Select a provider below for installation and usage instructions. Each tab shows two patterns:

* **Custom Hook** — a React component pattern that initializes the smart account once in a `useEffect` and manages send state with `useMutation` from `@tanstack/react-query`. Good for screens that need reactive loading and error state out of the box.
* **Action** — the raw `async` function call. Use this directly in event handlers, background tasks, or any state management setup you already have.

<Note>
  You'll need an initialized and authenticated Para instance before calling any `createXxxSmartAccount` function. See the <Link label="React Native Setup Guide" href="/v3/react-native/setup/react-native" /> for details.
</Note>

<Tabs>
  <Tab title="Alchemy">
    <Link label="Alchemy Account Kit" href="https://www.alchemy.com/account-kit" /> provides modular smart accounts with built-in gas sponsorship via Alchemy's Gas Manager. Supports both EIP-4337 and EIP-7702 modes.

    ### Setup

    1. Create an <Link label="Alchemy account" href="https://dashboard.alchemy.com/signup" /> and obtain your **API key** and **Gas Policy ID** from the Alchemy dashboard.

    2. Install the required dependencies:

    <CodeGroup>
      ```bash npm theme={null}
      npm install @getpara/react-native-wallet @getpara/aa-alchemy viem
      ```

      ```bash yarn theme={null}
      yarn add @getpara/react-native-wallet @getpara/aa-alchemy viem
      ```
    </CodeGroup>

    ### Usage

    <Tabs>
      <Tab title="Custom Hook">
        Initializes the smart account once when the component mounts using `useEffect`, then wraps `sendTransaction` in a `useMutation` from React Query for built-in `isPending` and error state.

        ```tsx AlchemyScreen.tsx theme={null}
        import { useState, useEffect } from "react";
        import { useMutation } from "@tanstack/react-query";
        import { createAlchemySmartAccount } from "@getpara/aa-alchemy";
        import { usePara } from "@getpara/react-native-wallet";
        import type { SmartAccount } from "@getpara/react-native-wallet";
        import { sepolia } from "viem/chains";
        import { parseEther } from "viem";

        export function AlchemyScreen() {
          const para = usePara();
          const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);

          useEffect(() => {
            createAlchemySmartAccount({
              para,
              apiKey: process.env.EXPO_PUBLIC_ALCHEMY_API_KEY!,
              chain: sepolia,
              gasPolicyId: process.env.EXPO_PUBLIC_ALCHEMY_GAS_POLICY_ID,
              mode: "4337",
            }).then(setSmartAccount);
          }, []);

          const { mutate: sendTx, isPending } = useMutation({
            mutationFn: () =>
              smartAccount!.sendTransaction({
                to: "0xRecipient",
                value: parseEther("0.01"),
              }),
            onSuccess: (receipt) =>
              console.log("Transaction hash:", receipt.transactionHash),
          });

          return (
            <View>
              <Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
              <Button
                title={isPending ? "Sending..." : "Send"}
                onPress={() => sendTx()}
                disabled={!smartAccount || isPending}
              />
            </View>
          );
        }
        ```
      </Tab>

      <Tab title="Action">
        Directly awaits the smart account creation and calls `sendTransaction` as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.

        ```typescript alchemy-action.ts theme={null}
        import { createAlchemySmartAccount } from "@getpara/aa-alchemy";
        import { sepolia } from "viem/chains";
        import { parseEther } from "viem";

        const smartAccount = await createAlchemySmartAccount({
          para,
          apiKey: process.env.EXPO_PUBLIC_ALCHEMY_API_KEY!,
          chain: sepolia,
          gasPolicyId: process.env.EXPO_PUBLIC_ALCHEMY_GAS_POLICY_ID,
          mode: "4337", // or "7702"
        });

        const receipt = await smartAccount.sendTransaction({
          to: "0xRecipient",
          value: parseEther("0.01"),
        });

        const batchReceipt = await smartAccount.sendBatchTransaction([
          { to: "0xRecipientA", value: parseEther("0.01") },
          { to: "0xContractAddress", data: "0xencodedCallData" },
        ]);
        ```
      </Tab>
    </Tabs>

    <Note>
      Alchemy requires chains from `@account-kit/infra` (e.g. `sepolia`, `baseSepolia`). Plain viem chains are automatically mapped if an Alchemy equivalent exists. For gasless transactions, set up a Gas Manager Policy in your <Link label="Alchemy Dashboard" href="https://dashboard.alchemy.com" /> and pass the policy ID as `gasPolicyId`.
    </Note>
  </Tab>

  <Tab title="ZeroDev">
    <Link label="ZeroDev" href="https://docs.zerodev.app/" /> provides Kernel smart accounts with gas sponsorship, session keys, recovery, and chain abstraction. Supports both EIP-4337 and EIP-7702 modes.

    ### Setup

    1. Create a <Link label="ZeroDev account" href="https://dashboard.zerodev.app/" /> and obtain your **Project ID** from the ZeroDev dashboard.

    2. Install the required dependencies:

    <CodeGroup>
      ```bash npm theme={null}
      npm install @getpara/react-native-wallet @getpara/aa-zerodev viem
      ```

      ```bash yarn theme={null}
      yarn add @getpara/react-native-wallet @getpara/aa-zerodev viem
      ```
    </CodeGroup>

    ### Usage

    <Tabs>
      <Tab title="Custom Hook">
        Initializes the smart account once when the component mounts using `useEffect`, then wraps `sendTransaction` in a `useMutation` from React Query for built-in `isPending` and error state.

        ```tsx ZeroDevScreen.tsx theme={null}
        import { useState, useEffect } from "react";
        import { useMutation } from "@tanstack/react-query";
        import { createZeroDevSmartAccount } from "@getpara/aa-zerodev";
        import { usePara } from "@getpara/react-native-wallet";
        import type { SmartAccount } from "@getpara/react-native-wallet";
        import { sepolia } from "viem/chains";
        import { parseEther } from "viem";

        export function ZeroDevScreen() {
          const para = usePara();
          const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);

          useEffect(() => {
            createZeroDevSmartAccount({
              para,
              projectId: process.env.EXPO_PUBLIC_ZERODEV_PROJECT_ID!,
              chain: sepolia,
              mode: "4337",
            }).then(setSmartAccount);
          }, []);

          const { mutate: sendTx, isPending } = useMutation({
            mutationFn: () =>
              smartAccount!.sendTransaction({
                to: "0xRecipient",
                value: parseEther("0.01"),
              }),
            onSuccess: (receipt) =>
              console.log("Transaction hash:", receipt.transactionHash),
          });

          return (
            <View>
              <Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
              <Button
                title={isPending ? "Sending..." : "Send"}
                onPress={() => sendTx()}
                disabled={!smartAccount || isPending}
              />
            </View>
          );
        }
        ```
      </Tab>

      <Tab title="Action">
        Directly awaits the smart account creation and calls `sendTransaction` as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.

        ```typescript zerodev-action.ts theme={null}
        import { createZeroDevSmartAccount } from "@getpara/aa-zerodev";
        import { sepolia } from "viem/chains";
        import { parseEther } from "viem";

        const smartAccount = await createZeroDevSmartAccount({
          para,
          projectId: process.env.EXPO_PUBLIC_ZERODEV_PROJECT_ID!,
          chain: sepolia,
          mode: "4337", // or "7702"
        });

        const receipt = await smartAccount.sendTransaction({
          to: "0xRecipient",
          value: parseEther("0.01"),
        });

        const batchReceipt = await smartAccount.sendBatchTransaction([
          { to: "0xRecipientA", value: parseEther("0.01") },
          { to: "0xContractAddress", data: "0xencodedCallData" },
        ]);
        ```
      </Tab>
    </Tabs>

    <Note>
      You can optionally pass `bundlerUrl` and `paymasterUrl` to use custom infrastructure instead of ZeroDev's defaults. See the <Link label="ZeroDev RPC documentation" href="https://docs.zerodev.app/meta-infra/rpcs" /> for details.
    </Note>
  </Tab>

  <Tab title="Pimlico">
    <Link label="Pimlico" href="https://docs.pimlico.io/" /> provides AA infrastructure via permissionless.js, a lightweight TypeScript library built on viem. Supports both EIP-4337 and EIP-7702 modes.

    ### Setup

    1. Create a <Link label="Pimlico account" href="https://dashboard.pimlico.io/" /> and obtain your **API key** from the Pimlico dashboard.

    2. Install the required dependencies:

    <CodeGroup>
      ```bash npm theme={null}
      npm install @getpara/react-native-wallet @getpara/aa-pimlico viem
      ```

      ```bash yarn theme={null}
      yarn add @getpara/react-native-wallet @getpara/aa-pimlico viem
      ```
    </CodeGroup>

    ### Usage

    <Tabs>
      <Tab title="Custom Hook">
        Initializes the smart account once when the component mounts using `useEffect`, then wraps `sendTransaction` in a `useMutation` from React Query for built-in `isPending` and error state.

        ```tsx PimlicoScreen.tsx theme={null}
        import { useState, useEffect } from "react";
        import { useMutation } from "@tanstack/react-query";
        import { createPimlicoSmartAccount } from "@getpara/aa-pimlico";
        import { usePara } from "@getpara/react-native-wallet";
        import type { SmartAccount } from "@getpara/react-native-wallet";
        import { sepolia } from "viem/chains";
        import { parseEther } from "viem";

        export function PimlicoScreen() {
          const para = usePara();
          const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);

          useEffect(() => {
            createPimlicoSmartAccount({
              para,
              apiKey: process.env.EXPO_PUBLIC_PIMLICO_API_KEY!,
              chain: sepolia,
              mode: "4337",
            }).then(setSmartAccount);
          }, []);

          const { mutate: sendTx, isPending } = useMutation({
            mutationFn: () =>
              smartAccount!.sendTransaction({
                to: "0xRecipient",
                value: parseEther("0.01"),
              }),
            onSuccess: (receipt) =>
              console.log("Transaction hash:", receipt.transactionHash),
          });

          return (
            <View>
              <Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
              <Button
                title={isPending ? "Sending..." : "Send"}
                onPress={() => sendTx()}
                disabled={!smartAccount || isPending}
              />
            </View>
          );
        }
        ```
      </Tab>

      <Tab title="Action">
        Directly awaits the smart account creation and calls `sendTransaction` as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.

        ```typescript pimlico-action.ts theme={null}
        import { createPimlicoSmartAccount } from "@getpara/aa-pimlico";
        import { sepolia } from "viem/chains";
        import { parseEther } from "viem";

        const smartAccount = await createPimlicoSmartAccount({
          para,
          apiKey: process.env.EXPO_PUBLIC_PIMLICO_API_KEY!,
          chain: sepolia,
          mode: "4337", // or "7702"
        });

        const receipt = await smartAccount.sendTransaction({
          to: "0xRecipient",
          value: parseEther("0.01"),
        });

        const batchReceipt = await smartAccount.sendBatchTransaction([
          { to: "0xRecipientA", value: parseEther("0.01") },
          { to: "0xContractAddress", data: "0xencodedCallData" },
        ]);
        ```
      </Tab>
    </Tabs>

    <Note>
      The Pimlico bundler/paymaster URL is automatically constructed from your API key and chain name. You can override it with a custom `rpcUrl`.
    </Note>
  </Tab>

  <Tab title="Biconomy">
    <Link label="Biconomy" href="https://docs.biconomy.io/" /> provides smart accounts with cross-chain orchestration via its Multi-chain Execution Environment (MEE). Supports both EIP-4337 and EIP-7702 modes.

    ### Setup

    1. Create a <Link label="Biconomy account" href="https://dashboard.biconomy.io/" /> and obtain your **API key** from the Biconomy dashboard.

    2. Install the required dependencies:

    <CodeGroup>
      ```bash npm theme={null}
      npm install @getpara/react-native-wallet @getpara/aa-biconomy viem
      ```

      ```bash yarn theme={null}
      yarn add @getpara/react-native-wallet @getpara/aa-biconomy viem
      ```
    </CodeGroup>

    ### Usage

    <Tabs>
      <Tab title="Custom Hook">
        Initializes the smart account once when the component mounts using `useEffect`, then wraps `sendTransaction` in a `useMutation` from React Query for built-in `isPending` and error state.

        ```tsx BiconomyScreen.tsx theme={null}
        import { useState, useEffect } from "react";
        import { useMutation } from "@tanstack/react-query";
        import { createBiconomySmartAccount } from "@getpara/aa-biconomy";
        import { usePara } from "@getpara/react-native-wallet";
        import type { SmartAccount } from "@getpara/react-native-wallet";
        import { sepolia } from "viem/chains";
        import { parseEther } from "viem";

        export function BiconomyScreen() {
          const para = usePara();
          const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);

          useEffect(() => {
            createBiconomySmartAccount({
              para,
              apiKey: process.env.EXPO_PUBLIC_BICONOMY_API_KEY!,
              chain: sepolia,
              mode: "4337",
            }).then(setSmartAccount);
          }, []);

          const { mutate: sendTx, isPending } = useMutation({
            mutationFn: () =>
              smartAccount!.sendTransaction({
                to: "0xRecipient",
                value: parseEther("0.01"),
              }),
            onSuccess: (receipt) =>
              console.log("Transaction hash:", receipt.transactionHash),
          });

          return (
            <View>
              <Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
              <Button
                title={isPending ? "Sending..." : "Send"}
                onPress={() => sendTx()}
                disabled={!smartAccount || isPending}
              />
            </View>
          );
        }
        ```
      </Tab>

      <Tab title="Action">
        Directly awaits the smart account creation and calls `sendTransaction` as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.

        ```typescript biconomy-action.ts theme={null}
        import { createBiconomySmartAccount } from "@getpara/aa-biconomy";
        import { sepolia } from "viem/chains";
        import { parseEther } from "viem";

        const smartAccount = await createBiconomySmartAccount({
          para,
          apiKey: process.env.EXPO_PUBLIC_BICONOMY_API_KEY!,
          chain: sepolia,
          mode: "4337", // or "7702"
        });

        const receipt = await smartAccount.sendTransaction({
          to: "0xRecipient",
          value: parseEther("0.01"),
        });

        const batchReceipt = await smartAccount.sendBatchTransaction([
          { to: "0xRecipientA", value: parseEther("0.01") },
          { to: "0xContractAddress", data: "0xencodedCallData" },
        ]);
        ```
      </Tab>
    </Tabs>

    <Note>
      Biconomy transactions are executed via the MEE (Multi-chain Execution Environment). You can optionally pass a custom `meeUrl` to use your own MEE node.
    </Note>
  </Tab>

  <Tab title="Thirdweb">
    <Link label="Thirdweb" href="https://portal.thirdweb.com/" /> provides smart wallets with built-in gas sponsorship. Supports both EIP-4337 and EIP-7702 modes.

    ### Setup

    1. Create a <Link label="Thirdweb account" href="https://thirdweb.com/dashboard" /> and obtain your **Client ID** from the Thirdweb dashboard.

    2. Install the required dependencies:

    <CodeGroup>
      ```bash npm theme={null}
      npm install @getpara/react-native-wallet @getpara/aa-thirdweb viem @thirdweb-dev/react-native-adapter react-native-mmkv react-native-nitro-modules @react-native-community/netinfo react-native-svg @coinbase/wallet-mobile-sdk
      ```

      ```bash yarn theme={null}
      yarn add @getpara/react-native-wallet @getpara/aa-thirdweb viem @thirdweb-dev/react-native-adapter react-native-mmkv react-native-nitro-modules @react-native-community/netinfo react-native-svg @coinbase/wallet-mobile-sdk
      ```
    </CodeGroup>

    <Tip>
      Thirdweb requires additional native dependencies for React Native beyond what other AA providers need. The packages above include `@thirdweb-dev/react-native-adapter` and its peer dependencies. See the <Link label="Thirdweb React Native Getting Started guide" href="https://portal.thirdweb.com/react-native/v5/getting-started" /> for full details.
    </Tip>

    ### Usage

    <Tabs>
      <Tab title="Custom Hook">
        Initializes the smart account once when the component mounts using `useEffect`, then wraps `sendTransaction` in a `useMutation` from React Query for built-in `isPending` and error state.

        ```tsx ThirdwebScreen.tsx theme={null}
        import { useState, useEffect } from "react";
        import { useMutation } from "@tanstack/react-query";
        import { createThirdwebSmartAccount } from "@getpara/aa-thirdweb";
        import { usePara } from "@getpara/react-native-wallet";
        import type { SmartAccount } from "@getpara/react-native-wallet";
        import { sepolia } from "viem/chains";
        import { parseEther } from "viem";

        export function ThirdwebScreen() {
          const para = usePara();
          const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);

          useEffect(() => {
            createThirdwebSmartAccount({
              para,
              clientId: process.env.EXPO_PUBLIC_THIRDWEB_CLIENT_ID!,
              chain: sepolia,
              sponsorGas: true,
              mode: "4337",
            }).then(setSmartAccount);
          }, []);

          const { mutate: sendTx, isPending } = useMutation({
            mutationFn: () =>
              smartAccount!.sendTransaction({
                to: "0xRecipient",
                value: parseEther("0.01"),
              }),
            onSuccess: (receipt) =>
              console.log("Transaction hash:", receipt.transactionHash),
          });

          return (
            <View>
              <Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
              <Button
                title={isPending ? "Sending..." : "Send"}
                onPress={() => sendTx()}
                disabled={!smartAccount || isPending}
              />
            </View>
          );
        }
        ```
      </Tab>

      <Tab title="Action">
        Directly awaits the smart account creation and calls `sendTransaction` as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.

        ```typescript thirdweb-action.ts theme={null}
        import { createThirdwebSmartAccount } from "@getpara/aa-thirdweb";
        import { sepolia } from "viem/chains";
        import { parseEther } from "viem";

        const smartAccount = await createThirdwebSmartAccount({
          para,
          clientId: process.env.EXPO_PUBLIC_THIRDWEB_CLIENT_ID!,
          chain: sepolia,
          sponsorGas: true,
          mode: "4337", // or "7702"
        });

        const receipt = await smartAccount.sendTransaction({
          to: "0xRecipient",
          value: parseEther("0.01"),
        });

        const batchReceipt = await smartAccount.sendBatchTransaction([
          { to: "0xRecipientA", value: parseEther("0.01") },
          { to: "0xContractAddress", data: "0xencodedCallData" },
        ]);
        ```
      </Tab>
    </Tabs>

    <Note>
      Set `sponsorGas: false` to disable gas sponsorship. In EIP-4337 mode, you can optionally provide `factoryAddress` and `accountAddress` for custom smart wallet deployments.
    </Note>
  </Tab>

  <Tab title="Gelato">
    <Link label="Gelato" href="https://docs.gelato.network/" /> provides native EIP-7702 smart accounts with built-in gas sponsorship via relay infrastructure. Gelato only supports EIP-7702 mode.

    ### Setup

    1. Create a <Link label="Gelato account" href="https://app.gelato.network/" /> and obtain your **API key** from the Gelato dashboard.

    2. Install the required dependencies:

    <CodeGroup>
      ```bash npm theme={null}
      npm install @getpara/react-native-wallet @getpara/aa-gelato viem
      ```

      ```bash yarn theme={null}
      yarn add @getpara/react-native-wallet @getpara/aa-gelato viem
      ```
    </CodeGroup>

    ### Usage

    <Tabs>
      <Tab title="Custom Hook">
        Initializes the smart account once when the component mounts using `useEffect`, then wraps `sendTransaction` in a `useMutation` from React Query for built-in `isPending` and error state.

        ```tsx GelatoScreen.tsx theme={null}
        import { useState, useEffect } from "react";
        import { useMutation } from "@tanstack/react-query";
        import { createGelatoSmartAccount } from "@getpara/aa-gelato";
        import { usePara } from "@getpara/react-native-wallet";
        import type { SmartAccount } from "@getpara/react-native-wallet";
        import { sepolia } from "viem/chains";
        import { parseEther } from "viem";

        export function GelatoScreen() {
          const para = usePara();
          const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);

          useEffect(() => {
            createGelatoSmartAccount({
              para,
              apiKey: process.env.EXPO_PUBLIC_GELATO_API_KEY!,
              chain: sepolia,
            }).then(setSmartAccount);
          }, []);

          const { mutate: sendTx, isPending } = useMutation({
            mutationFn: () =>
              smartAccount!.sendTransaction({
                to: "0xRecipient",
                value: parseEther("0.01"),
              }),
            onSuccess: (receipt) =>
              console.log("Transaction hash:", receipt.transactionHash),
          });

          return (
            <View>
              <Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
              <Button
                title={isPending ? "Sending..." : "Send"}
                onPress={() => sendTx()}
                disabled={!smartAccount || isPending}
              />
            </View>
          );
        }
        ```
      </Tab>

      <Tab title="Action">
        Directly awaits the smart account creation and calls `sendTransaction` as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.

        ```typescript gelato-action.ts theme={null}
        import { createGelatoSmartAccount } from "@getpara/aa-gelato";
        import { sepolia } from "viem/chains";
        import { parseEther } from "viem";

        const smartAccount = await createGelatoSmartAccount({
          para,
          apiKey: process.env.EXPO_PUBLIC_GELATO_API_KEY!,
          chain: sepolia,
        });

        const receipt = await smartAccount.sendTransaction({
          to: "0xRecipient",
          value: parseEther("0.01"),
        });

        const batchReceipt = await smartAccount.sendBatchTransaction([
          { to: "0xRecipientA", value: parseEther("0.01") },
          { to: "0xContractAddress", data: "0xencodedCallData" },
        ]);
        ```
      </Tab>
    </Tabs>

    <Note>
      Gelato only supports EIP-7702 mode. Gas sponsorship is built into Gelato's relay infrastructure — no separate paymaster configuration is needed.
    </Note>
  </Tab>

  <Tab title="Porto">
    <Link label="Porto" href="https://porto.sh/docs" /> provides 7702-native smart accounts with a built-in relay — no bundler or paymaster needed. Porto only supports EIP-7702 mode.

    ### Setup

    1. No API key needed. Porto uses its own relay RPC. For **mainnet gas sponsorship**, set up a <Link label="Porto merchant account" href="https://porto.sh/sdk/guides/sponsoring" /> and pass your endpoint as `merchantUrl`.

    2. Install the required dependencies:

    <CodeGroup>
      ```bash npm theme={null}
      npm install @getpara/react-native-wallet @getpara/aa-porto viem
      ```

      ```bash yarn theme={null}
      yarn add @getpara/react-native-wallet @getpara/aa-porto viem
      ```
    </CodeGroup>

    ### Usage

    <Tabs>
      <Tab title="Custom Hook">
        Initializes the smart account once when the component mounts using `useEffect`, then wraps `sendTransaction` in a `useMutation` from React Query for built-in `isPending` and error state.

        ```tsx PortoScreen.tsx theme={null}
        import { useState, useEffect } from "react";
        import { useMutation } from "@tanstack/react-query";
        import { createPortoSmartAccount } from "@getpara/aa-porto";
        import { usePara } from "@getpara/react-native-wallet";
        import type { SmartAccount } from "@getpara/react-native-wallet";
        import { base } from "viem/chains";
        import { parseEther } from "viem";

        export function PortoScreen() {
          const para = usePara();
          const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);

          useEffect(() => {
            // Testnets: gas sponsored by default. Mainnet: merchantUrl required.
            createPortoSmartAccount({
              para,
              chain: base,
              merchantUrl: process.env.EXPO_PUBLIC_PORTO_MERCHANT_URL,
            }).then(setSmartAccount);
          }, []);

          const { mutate: sendTx, isPending } = useMutation({
            mutationFn: () =>
              smartAccount!.sendTransaction({
                to: "0xRecipient",
                value: parseEther("0.01"),
              }),
            onSuccess: (receipt) =>
              console.log("Transaction hash:", receipt.transactionHash),
          });

          return (
            <View>
              <Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
              <Button
                title={isPending ? "Sending..." : "Send"}
                onPress={() => sendTx()}
                disabled={!smartAccount || isPending}
              />
            </View>
          );
        }
        ```
      </Tab>

      <Tab title="Action">
        Directly awaits the smart account creation and calls `sendTransaction` as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.

        ```typescript porto-action.ts theme={null}
        import { createPortoSmartAccount } from "@getpara/aa-porto";
        import { parseEther } from "viem";
        import { base } from "viem/chains";

        // Testnets: gas sponsored by default. Mainnet: merchantUrl required.
        const smartAccount = await createPortoSmartAccount({
          para,
          chain: base,
          merchantUrl: process.env.EXPO_PUBLIC_PORTO_MERCHANT_URL,
        });

        const receipt = await smartAccount.sendTransaction({
          to: "0xRecipient",
          value: parseEther("0.01"),
        });

        const batchReceipt = await smartAccount.sendBatchTransaction([
          { to: "0xRecipientA", value: parseEther("0.01") },
          { to: "0xContractAddress", data: "0xencodedCallData" },
        ]);
        ```
      </Tab>
    </Tabs>

    <Note>
      Porto only supports EIP-7702 mode. Supports <Link label="multiple chains" href="https://porto.sh/relay" /> including Base, Optimism, Arbitrum, and Ethereum. On testnets, gas is sponsored by default. For mainnet, a <Link label="merchant account" href="https://porto.sh/sdk/guides/sponsoring" /> is required.
    </Note>
  </Tab>

  <Tab title="Safe">
    <Link label="Safe" href="https://docs.safe.global/" /> provides multi-signature smart contract wallets with ERC-4337 compatibility, powered by Pimlico's bundler and paymaster. Safe only supports EIP-4337 mode.

    ### Setup

    1. Create a <Link label="Pimlico account" href="https://dashboard.pimlico.io/" /> and obtain your **API key** — Safe uses Pimlico for bundler and paymaster services.

    2. Install the required dependencies:

    <CodeGroup>
      ```bash npm theme={null}
      npm install @getpara/react-native-wallet @getpara/aa-safe viem
      ```

      ```bash yarn theme={null}
      yarn add @getpara/react-native-wallet @getpara/aa-safe viem
      ```
    </CodeGroup>

    ### Usage

    <Tabs>
      <Tab title="Custom Hook">
        Initializes the smart account once when the component mounts using `useEffect`, then wraps `sendTransaction` in a `useMutation` from React Query for built-in `isPending` and error state.

        ```tsx SafeScreen.tsx theme={null}
        import { useState, useEffect } from "react";
        import { useMutation } from "@tanstack/react-query";
        import { createSafeSmartAccount } from "@getpara/aa-safe";
        import { usePara } from "@getpara/react-native-wallet";
        import type { SmartAccount } from "@getpara/react-native-wallet";
        import { sepolia } from "viem/chains";
        import { parseEther } from "viem";

        export function SafeScreen() {
          const para = usePara();
          const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);

          useEffect(() => {
            createSafeSmartAccount({
              para,
              pimlicoApiKey: process.env.EXPO_PUBLIC_PIMLICO_API_KEY!,
              chain: sepolia,
            }).then(setSmartAccount);
          }, []);

          const { mutate: sendTx, isPending } = useMutation({
            mutationFn: () =>
              smartAccount!.sendTransaction({
                to: "0xRecipient",
                value: parseEther("0.01"),
              }),
            onSuccess: (receipt) =>
              console.log("Transaction hash:", receipt.transactionHash),
          });

          return (
            <View>
              <Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
              <Button
                title={isPending ? "Sending..." : "Send"}
                onPress={() => sendTx()}
                disabled={!smartAccount || isPending}
              />
            </View>
          );
        }
        ```
      </Tab>

      <Tab title="Action">
        Directly awaits the smart account creation and calls `sendTransaction` as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.

        ```typescript safe-action.ts theme={null}
        import { createSafeSmartAccount } from "@getpara/aa-safe";
        import { sepolia } from "viem/chains";
        import { parseEther } from "viem";

        const smartAccount = await createSafeSmartAccount({
          para,
          pimlicoApiKey: process.env.EXPO_PUBLIC_PIMLICO_API_KEY!,
          chain: sepolia,
        });

        const receipt = await smartAccount.sendTransaction({
          to: "0xRecipient",
          value: parseEther("0.01"),
        });

        const batchReceipt = await smartAccount.sendBatchTransaction([
          { to: "0xRecipientA", value: parseEther("0.01") },
          { to: "0xContractAddress", data: "0xencodedCallData" },
        ]);
        ```
      </Tab>
    </Tabs>

    <Note>
      Safe only supports EIP-4337 mode. You can optionally pass `safeVersion` (default: `"1.4.1"`) and `saltNonce` for deterministic address generation.
    </Note>
  </Tab>

  <Tab title="Rhinestone">
    <Link label="Rhinestone" href="https://docs.rhinestone.wtf/" /> provides cross-chain smart accounts with intent-based transactions and automatic bridging. Rhinestone only supports EIP-4337 mode.

    ### Setup

    1. Obtain your **Rhinestone API key** and optionally a **Pimlico API key** for bundler/paymaster infrastructure.

    2. Install the required dependencies:

    <CodeGroup>
      ```bash npm theme={null}
      npm install @getpara/react-native-wallet @getpara/aa-rhinestone viem
      ```

      ```bash yarn theme={null}
      yarn add @getpara/react-native-wallet @getpara/aa-rhinestone viem
      ```
    </CodeGroup>

    ### Usage

    <Tabs>
      <Tab title="Custom Hook">
        Initializes the smart account once when the component mounts using `useEffect`, then wraps `sendTransaction` in a `useMutation` from React Query for built-in `isPending` and error state.

        ```tsx RhinestoneScreen.tsx theme={null}
        import { useState, useEffect } from "react";
        import { useMutation } from "@tanstack/react-query";
        import { createRhinestoneSmartAccount } from "@getpara/aa-rhinestone";
        import { usePara } from "@getpara/react-native-wallet";
        import type { SmartAccount } from "@getpara/react-native-wallet";
        import { sepolia } from "viem/chains";
        import { parseEther } from "viem";

        export function RhinestoneScreen() {
          const para = usePara();
          const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);

          useEffect(() => {
            createRhinestoneSmartAccount({
              para,
              chain: sepolia,
              rhinestoneApiKey: process.env.EXPO_PUBLIC_RHINESTONE_API_KEY!,
              pimlicoApiKey: process.env.EXPO_PUBLIC_PIMLICO_API_KEY,
            }).then(setSmartAccount);
          }, []);

          const { mutate: sendTx, isPending } = useMutation({
            mutationFn: () =>
              smartAccount!.sendTransaction({
                to: "0xRecipient",
                value: parseEther("0.01"),
              }),
            onSuccess: (receipt) =>
              console.log("Transaction hash:", receipt.transactionHash),
          });

          return (
            <View>
              <Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
              <Button
                title={isPending ? "Sending..." : "Send"}
                onPress={() => sendTx()}
                disabled={!smartAccount || isPending}
              />
            </View>
          );
        }
        ```
      </Tab>

      <Tab title="Action">
        Directly awaits the smart account creation and calls `sendTransaction` as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.

        ```typescript rhinestone-action.ts theme={null}
        import { createRhinestoneSmartAccount } from "@getpara/aa-rhinestone";
        import { sepolia } from "viem/chains";
        import { parseEther } from "viem";

        const smartAccount = await createRhinestoneSmartAccount({
          para,
          chain: sepolia,
          rhinestoneApiKey: process.env.EXPO_PUBLIC_RHINESTONE_API_KEY!,
          pimlicoApiKey: process.env.EXPO_PUBLIC_PIMLICO_API_KEY,
        });

        const receipt = await smartAccount.sendTransaction({
          to: "0xRecipient",
          value: parseEther("0.01"),
        });

        const batchReceipt = await smartAccount.sendBatchTransaction([
          { to: "0xRecipientA", value: parseEther("0.01") },
          { to: "0xContractAddress", data: "0xencodedCallData" },
        ]);
        ```
      </Tab>
    </Tabs>

    <Note>
      Rhinestone only supports EIP-4337 mode. Both `rhinestoneApiKey` and `pimlicoApiKey` are optional but recommended for production. See the <Link label="Rhinestone documentation" href="https://docs.rhinestone.dev" /> for advanced cross-chain use cases.
    </Note>
  </Tab>

  <Tab title="Coinbase Developer Platform">
    <Link label="Coinbase Developer Platform" href="https://docs.cdp.coinbase.com/" /> provides Coinbase smart accounts on Base using viem's built-in `toCoinbaseSmartAccount`. CDP only supports EIP-4337 mode on Base and Base Sepolia.

    ### Setup

    1. Create a <Link label="CDP account" href="https://portal.cdp.coinbase.com/" /> and obtain your **RPC token** from the paymaster URL in the CDP dashboard.

    2. Install the required dependencies:

    <CodeGroup>
      ```bash npm theme={null}
      npm install @getpara/react-native-wallet @getpara/aa-cdp viem
      ```

      ```bash yarn theme={null}
      yarn add @getpara/react-native-wallet @getpara/aa-cdp viem
      ```
    </CodeGroup>

    ### Usage

    <Tabs>
      <Tab title="Custom Hook">
        Initializes the smart account once when the component mounts using `useEffect`, then wraps `sendTransaction` in a `useMutation` from React Query for built-in `isPending` and error state.

        ```tsx CDPScreen.tsx theme={null}
        import { useState, useEffect } from "react";
        import { useMutation } from "@tanstack/react-query";
        import { createCDPSmartAccount } from "@getpara/aa-cdp";
        import { usePara } from "@getpara/react-native-wallet";
        import type { SmartAccount } from "@getpara/react-native-wallet";
        import { baseSepolia } from "viem/chains";
        import { parseEther } from "viem";

        export function CDPScreen() {
          const para = usePara();
          const [smartAccount, setSmartAccount] = useState<SmartAccount | null>(null);

          useEffect(() => {
            createCDPSmartAccount({
              para,
              rpcToken: process.env.EXPO_PUBLIC_CDP_RPC_TOKEN!,
              chain: baseSepolia,
            }).then(setSmartAccount);
          }, []);

          const { mutate: sendTx, isPending } = useMutation({
            mutationFn: () =>
              smartAccount!.sendTransaction({
                to: "0xRecipient",
                value: parseEther("0.01"),
              }),
            onSuccess: (receipt) =>
              console.log("Transaction hash:", receipt.transactionHash),
          });

          return (
            <View>
              <Text>Smart Account: {smartAccount?.smartAccountAddress}</Text>
              <Button
                title={isPending ? "Sending..." : "Send"}
                onPress={() => sendTx()}
                disabled={!smartAccount || isPending}
              />
            </View>
          );
        }
        ```
      </Tab>

      <Tab title="Action">
        Directly awaits the smart account creation and calls `sendTransaction` as a plain async function. Use this in event handlers, background tasks, or with any state management solution you already have.

        ```typescript cdp-action.ts theme={null}
        import { createCDPSmartAccount } from "@getpara/aa-cdp";
        import { baseSepolia } from "viem/chains";
        import { parseEther } from "viem";

        const smartAccount = await createCDPSmartAccount({
          para,
          rpcToken: process.env.EXPO_PUBLIC_CDP_RPC_TOKEN!,
          chain: baseSepolia,
        });

        const receipt = await smartAccount.sendTransaction({
          to: "0xRecipient",
          value: parseEther("0.01"),
        });

        const batchReceipt = await smartAccount.sendBatchTransaction([
          { to: "0xRecipientA", value: parseEther("0.01") },
          { to: "0xContractAddress", data: "0xencodedCallData" },
        ]);
        ```
      </Tab>
    </Tabs>

    <Note>
      CDP only supports EIP-4337 mode and is limited to **Base** and **Base Sepolia** chains.
    </Note>
  </Tab>
</Tabs>

<Warning>
  In EIP-4337 mode, funds must be sent to `smartAccount.smartAccountAddress` — not to the Para EOA address.
</Warning>

## Key Considerations for Mobile

* Complete authentication with Para before the component mounts — the Para instance must have an active session
* The `useEffect` pattern above fires once on mount; add config values to the dependency array if they can change at runtime
* Wrap `sendTransaction` calls in `useMutation` for loading state and error handling in mobile UIs
* Test on physical devices to verify signing flows, particularly for EIP-7702 delegation transactions
