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

# Gelato Integration

export const TypeScriptConfigRequirement = () => {
  return <>
      <Note>
        <strong>TypeScript users:</strong> Set <code>moduleResolution: "node16"</code> or <code>"nodenext"</code> in your <code>tsconfig.json</code> (not the legacy <code>"node"</code>) to avoid compilation errors with the CDP SDK.
      </Note>
    </>;
};

Learn how to integrate CDP wallets as a wallet provider with the Gelato Bundler for sponsored user operations.

## Prerequisites

* A free [CDP Portal](https://portal.cdp.coinbase.com) account and project
* [Node.js 22+](https://nodejs.org/en/download)
* A node package manager installed (i.e., `npm`, `pnpm`, or `yarn`)
* Basic familiarity with React and TypeScript
* Configured your domain in CDP Portal (see below)

<Accordion title="How to configure your domain in CDP Portal">
  **Step 1: Access CDP Portal**

  Navigate to the [Security Configuration](https://portal.cdp.coinbase.com/products/embedded-wallets/security) in CDP Portal, and click **Add domain** to include your local app.

  <Frame>
    <img src="https://mintcdn.com/coinbase-prod/i_weT8-PD6DDa8y9/images/cors-config-add-domain.png?fit=max&auto=format&n=i_weT8-PD6DDa8y9&q=85&s=bdaf1e7d7193713db0bcb2451de79886" alt="Add domain dialog in CDP Portal" width="1892" height="1252" data-path="images/cors-config-add-domain.png" />
  </Frame>

  **Step 2: Add your domain**

  * For local development: Use `http://localhost:3000` (or your preferred port)
  * For production: Use your actual domain (e.g., `https://yourapp.com`)

  <Frame>
    <img src="https://mintcdn.com/coinbase-prod/kt8yDgpB8UeHhzQM/images/cors-config-with-localhost.png?fit=max&auto=format&n=kt8yDgpB8UeHhzQM&q=85&s=206d58371ee7eb393b613c555dcdb747" alt="Domain configuration with localhost" width="1208" height="538" data-path="images/cors-config-with-localhost.png" />
  </Frame>

  <Warning>
    For production apps, only add your actual production domain. Do not add `localhost` to production CDP projects as malicious apps running locally could impersonate your frontend and abuse your project credentials.
  </Warning>

  **Step 3: Save your changes**

  Click **Add domain** again to save your changes.

  <Frame>
    <img src="https://mintcdn.com/coinbase-prod/i_weT8-PD6DDa8y9/images/cors-config-with-domain.png?fit=max&auto=format&n=i_weT8-PD6DDa8y9&q=85&s=ad3793b48c19b364a9eb6c45766559af" alt="Domain configuration saved in CDP Portal" width="1892" height="1252" data-path="images/cors-config-with-domain.png" />
  </Frame>

  You should see your domain listed in the CDP Portal dashboard. The allowlist will take effect immediately upon saving.
</Accordion>

<TypeScriptConfigRequirement />

* A [Gelato](https://app.gelato.cloud/) account with an app and API key generated from `Paymaster & Bundler` > `API Keys`

Install the required CDP packages:

```bash theme={null}
# npm
npm install @coinbase/cdp-react @coinbase/cdp-hooks @coinbase/cdp-core viem
```

<Steps>
  <Step title="Set up .env file">
    Set the environment variables in your .env.local file:

    ```bash theme={null}
    NEXT_PUBLIC_PROJECT_ID=your_coinbase_cdp_project_id
    NEXT_PUBLIC_GELATO_API_KEY=your_gelato_api_key
    ```
  </Step>

  <Step title="Import Dependencies">
    ```tsx src/App.tsx theme={null}
    import { CDPReactProvider } from "@coinbase/cdp-react";
    import { AuthButton } from "@coinbase/cdp-react/components/AuthButton";
    import { useCurrentUser, useEvmAddress } from "@coinbase/cdp-hooks";
    import { toViemAccount } from "@coinbase/cdp-core";
    import { baseSepolia } from "viem/chains";
    import { createPublicClient, http } from "viem";
    import {
      createBundlerClient,
      toCoinbaseSmartAccount,
    } from "viem/account-abstraction";
    ```
  </Step>

  <Step title="Configure React provider">
    Set up the CDP React Provider in your app:

    ```tsx src/App.tsx theme={null}
    "use client";

    import { CDPReactProvider } from "@coinbase/cdp-react";

    function Providers({ children }: { children: React.ReactNode }) {
      return (
        <CDPReactProvider
          config={{
            projectId: process.env.NEXT_PUBLIC_PROJECT_ID as string,
            ethereum: {
              createOnLogin: "eoa",
            },
            appName: "Your App Name",
          }}
        >
          {children}
        </CDPReactProvider>
      );
    }
    ```
  </Step>

  <Step title="Create Bundler Client">
    Set up your component to use Coinbase CDP hooks and create a bundler client with Gelato integration:

    ```tsx src/App.tsx theme={null}
    "use client";

    import { AuthButton } from "@coinbase/cdp-react/components/AuthButton";
    import { useCurrentUser, useEvmAddress } from "@coinbase/cdp-hooks";
    import { toViemAccount } from "@coinbase/cdp-core";
    import { baseSepolia } from "viem/chains";
    import { createPublicClient, http } from "viem";
    import {
      createBundlerClient,
      toCoinbaseSmartAccount,
    } from "viem/account-abstraction";

    export default function Home() {
      const { evmAddress } = useEvmAddress();
      const { currentUser } = useCurrentUser();

      const createAccount = async () => {
        if (!currentUser?.evmAccounts) return;

        const viemAccount = await toViemAccount(currentUser?.evmAccounts[0]);

        const client = createPublicClient({
          chain: baseSepolia,
          transport: http(),
        });

        const account = await toCoinbaseSmartAccount({
          client,
          owners: [viemAccount],
          version: "1.1",
        });

        const bundlerClient = createBundlerClient({
          client: client,
          transport: http(
            `https://api.gelato.digital/bundlers/${baseSepolia.id}/rpc?apiKey=${process.env.NEXT_PUBLIC_GELATO_API_KEY}&sponsored=true`
          ),
        });

        console.log("Bundler client created:", bundlerClient);
        console.log("Smart account address:", account.address);
      };

      return (
        <div>
          <AuthButton />
          <div>{evmAddress}</div>
          <button onClick={createAccount}>Create Account</button>
        </div>
      );
    }
    ```
  </Step>

  <Step title="Send User Operations">
    Send sponsored user operations using the bundler client:

    ```tsx src/App.tsx theme={null}
    const sendUserOperation = async () => {
      const response = await bundlerClient.sendUserOperation({
        account,
        calls: [
          {
            to: account.address,
            value: BigInt(0),
            data: "0x",
          },
        ],
        maxFeePerGas: BigInt(0),
        maxPriorityFeePerGas: BigInt(0),
      });

      console.log("User operation response:", response);
    };
    ```
  </Step>
</Steps>
