Skip to main content

Send Transactions

In the context of ERC-4337, transactions are known as "user operations," or "userops" for short.

Contract Interactions

To interact with a contract, use the sendUserOperation function:

const { hash } = await ecdsaProvider.sendUserOperation({
target: contractAddress,
data: functionData,
value: value,

// If you want to wait for the UserOp to complete
await ecdsaProvider.waitForUserOperationTransaction(hash)

Just like a normal transaction, a UserOp consists of a target (the account or contract you want to interact with), a function calldata, and the ETH value attached to the transaction.

To easily encode function calldata, you can use Viem's helper functions like this:

const { encodeFunctionData, parseAbi } = require('viem')

const contractABI = parseAbi([
'function mint(address _to) public',

const { hash } = await ecdsaProvider.sendUserOperation({
target: contractAddress,
data: encodeFunctionData({
abi: contractABI,
functionName: 'mint',
args: [address],

Wagmi API

With Wagmi, use the usePrepareSendUserOperation and useSendUserOperation hooks to send UserOps:

import { usePrepareSendUserOperation, useSendUserOperation } from "@zerodev/wagmi";
import { useWaitForTransaction } from "wagmi";

// Prepare the tx
const { config } = usePrepareSendUserOperation({
to: contractAddress,
data: functionData,
value: value,

const { sendUserOperation, data } = useSendUserOperation(config);

// Wait on the status of the tx
hash: data?.hash,
enabled: !!data,
onSuccess(data) {
console.log("Transaction was successful.")

// Send the tx

Transferring ETH

Simply set data to 0x if you want to transfer ETH (or whatever native token):

const { hash } = await ecdsaProvider.sendUserOperation({
target: receiverAddress,
data: '0x',
value: amount,

Wagmi API

const { config } = usePrepareSendUserOperation({
to: receiverAddress,
data: '0x',
value: amount

Ethers API


The Ethers API is considered unstable and you might run into unexpected bugs.

ZeroDev uses Viem by default, but if your project uses Ethers, you could use the ZeroDev wallet object as an Ethers provider & signer:

const {
} = require('@zerodev/sdk')

// Use the function `ZeroDevEthersProvider` to create an Ethers provider
const provider = await ZeroDevEthersProvider.init('ECDSA', {
// ...other settings

// Get the signer from the Ethers provider
const signer = provider.getAccountSigner()

From here on, you can use the Ethers signer as you would expect. For example, to interact with contracts:

const nftContract = new Contract(contractAddress, contractABI, signer)
const receipt = await
await receipt.wait()