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

# sendUserOperation

# sendUserOperation

Sends a user operation with one or more calls and waits for the transaction receipt. Works for both single transactions and batch transactions. This is the primary function for executing transactions with ZeroDev Account Abstraction.

## Usage

```javascript theme={"system"}
import { sendUserOperation } from "@dynamic-labs-sdk/zerodev";
import { isEvmWalletAccount } from "@dynamic-labs-sdk/evm";
import { getPrimaryWalletAccount } from "@dynamic-labs-sdk/client";
import { parseEther } from "viem";

const walletAccount = getPrimaryWalletAccount();

if (walletAccount && isEvmWalletAccount(walletAccount)) {
  const receipt = await sendUserOperation({
    walletAccount,
    calls: [
      {
        to: recipientAddress,
        value: parseEther("0.01"),
        data: "0x",
      },
    ],
  });

  console.log("Transaction successful:", receipt.userOpHash);
  console.log("Success:", receipt.success);
}
```

## Parameters

You must provide either a `walletAccount` or a `kernelClient`, but not both.

| Parameter         | Type                          | Description                                                                 |
| ----------------- | ----------------------------- | --------------------------------------------------------------------------- |
| `calls`           | `BatchCall[]`                 | Array of calls to execute (single or multiple)                              |
| `calls[].to`      | `Hex`                         | The recipient address for this call                                         |
| `calls[].value`   | `bigint`                      | The value to send in wei for this call                                      |
| `calls[].data`    | `Hex` (optional)              | The transaction data for this call                                          |
| `walletAccount`   | `EvmWalletAccount` (optional) | The wallet account. Required if no `kernelClient` is provided               |
| `kernelClient`    | `KernelClient` (optional)     | An existing kernel client. Required if no `walletAccount` is provided       |
| `withSponsorship` | `boolean` (optional)          | Whether to use sponsorship. Default: `true`. Only used with `walletAccount` |

## Returns

`Promise<UserOperationReceipt>` - Returns the UserOperation receipt with transaction details.

The receipt includes:

* `userOpHash`: The UserOperation hash
* `success`: Boolean indicating if the operation succeeded
* Additional transaction details from the receipt

## Examples

### Single transaction (sponsored by default)

```javascript theme={"system"}
const receipt = await sendUserOperation({
  walletAccount,
  calls: [
    {
      to: "0x...",
      value: parseEther("0.1"),
    },
  ],
});

console.log("UserOp Hash:", receipt.userOpHash);
```

### Batch transaction (multiple recipients)

```javascript theme={"system"}
const receipt = await sendUserOperation({
  walletAccount,
  calls: [
    { to: "0xRecipient1...", value: parseEther("0.1") },
    { to: "0xRecipient2...", value: parseEther("0.2") },
    { to: "0xRecipient3...", value: parseEther("0.3") },
  ],
});

console.log("Batch transaction successful:", receipt.userOpHash);
```

### Without sponsorship (user pays gas)

```javascript theme={"system"}
const receipt = await sendUserOperation({
  walletAccount,
  withSponsorship: false,
  calls: [
    {
      to: "0x...",
      value: parseEther("0.1"),
    },
  ],
});
```

### Using existing kernel client

```javascript theme={"system"}
const kernelClient = await createKernelClientForWalletAccount({
  smartWalletAccount: walletAccount,
});

const receipt = await sendUserOperation({
  kernelClient,
  calls: [
    {
      to: "0x...",
      value: parseEther("0.1"),
    },
  ],
});
```

### Token transfer

```javascript theme={"system"}
import { encodeFunctionData } from "viem";

const receipt = await sendUserOperation({
  walletAccount,
  calls: [
    {
      to: tokenAddress,
      value: 0n,
      data: encodeFunctionData({
        abi: erc20Abi,
        functionName: "transfer",
        args: [recipientAddress, parseEther("100")],
      }),
    },
  ],
});
```

### DeFi workflow (Approve + Swap)

```javascript theme={"system"}
import { encodeFunctionData } from "viem";

const receipt = await sendUserOperation({
  walletAccount,
  calls: [
    {
      to: tokenAddress,
      value: 0n,
      data: encodeFunctionData({
        abi: erc20Abi,
        functionName: "approve",
        args: [swapRouterAddress, amount],
      }),
    },
    {
      to: swapRouterAddress,
      value: 0n,
      data: encodeFunctionData({
        abi: swapRouterAbi,
        functionName: "swap",
        args: [tokenA, tokenB, amount],
      }),
    },
  ],
});

console.log("Approve + Swap completed atomically:", receipt.userOpHash);
```

### With gas estimation and sponsorship check

```javascript theme={"system"}
import {
  estimateUserOperationGas,
  canSponsorUserOperation,
  sendUserOperation
} from "@dynamic-labs-sdk/zerodev";

const calls = [
  { to: "0x...", value: parseEther("0.1") },
  { to: "0x...", value: parseEther("0.2") },
];

// Estimate gas
const estimatedGas = await estimateUserOperationGas({
  walletAccount,
  calls,
});

// Check sponsorship
const canSponsor = await canSponsorUserOperation({
  walletAccount,
  calls,
});

console.log(`Estimated gas: ${formatEther(estimatedGas)} ETH`);
console.log(`Will be sponsored: ${canSponsor}`);

// Send with appropriate sponsorship setting
const receipt = await sendUserOperation({
  walletAccount,
  withSponsorship: canSponsor,
  calls,
});
```

### Error handling

```javascript theme={"system"}
try {
  const receipt = await sendUserOperation({
    walletAccount,
    calls: [
      { to: "0xRecipient1...", value: parseEther("0.1") },
      { to: "0xRecipient2...", value: parseEther("0.2") },
    ],
  });

  console.log("All operations succeeded:", receipt.userOpHash);
} catch (error) {
  console.error("Batch transaction failed - no operations were executed");
  console.error(error);
}
```

## React

Use `sendUserOperation` inside a button handler. Use `useGetWalletAccounts` from `@dynamic-labs-sdk/react-hooks` to reactively get the wallet account:

```tsx theme={"system"}
import { sendUserOperation } from '@dynamic-labs-sdk/zerodev';
import { isEvmWalletAccount } from '@dynamic-labs-sdk/evm';
import { useGetWalletAccounts } from '@dynamic-labs-sdk/react-hooks';
import { useState } from 'react';
import { parseEther } from 'viem';

function GaslessSendButton({ recipientAddress }) {
  const { data: walletAccounts = [] } = useGetWalletAccounts();
  const walletAccount = walletAccounts.find(isEvmWalletAccount);
  const [opHash, setOpHash] = useState('');

  const handleSend = async () => {
    if (!walletAccount) return;
    const receipt = await sendUserOperation({
      walletAccount,
      calls: [{ to: recipientAddress, value: parseEther('0.01'), data: '0x' }],
    });
    setOpHash(receipt.userOpHash);
  };

  return (
    <div>
      <button onClick={handleSend} disabled={!walletAccount}>Send (Gasless)</button>
      {opHash && <p>UserOp hash: {opHash}</p>}
    </div>
  );
}
```

## Benefits of Batch Transactions

* **Atomicity**: All operations succeed or all fail together
* **Cost Efficiency**: Single validation per batch reduces gas fees
* **Better UX**: Users approve once for multiple operations
* **Composability**: Enable complex multi-step workflows

## Notes

* By default, transactions use sponsorship (`withSponsorship: true`)
* Batch transactions are atomic - if any call fails, the entire batch fails
* The function waits for the UserOperation receipt before returning
* Gas savings increase with larger batches due to shared validation costs

## Related functions

* [estimateUserOperationGas](/javascript/reference/zerodev/estimate-user-operation-gas) - Estimate gas for a user operation
* [canSponsorUserOperation](/javascript/reference/zerodev/can-sponsor-user-operation) - Check if operation can be sponsored
* [createKernelClientForWalletAccount](/javascript/reference/zerodev/create-kernel-client-for-wallet-account) - Create a ZeroDev Kernel client
* [isGasSponsorshipError](/javascript/reference/zerodev/is-gas-sponsorship-error) - Check if an error is a gas sponsorship error
* [Migration guide (v0.9)](/javascript/reference/zerodev/migration-v0.9) - Upgrading from the previous transaction API
