Skip to main content
Portal’s React Native SDK provides methods for building, signing, and broadcasting ERC-4337 batch UserOperations — bundling multiple transfers into a single smart-account operation. These methods are available on Account Abstraction-enabled clients only and require a CAIP-2 chain ID starting with eip155:.
Batch UserOperations require Account Abstraction to be enabled for your organization and client.

Prerequisites

Before using batch UserOperations, ensure you have:
  • A properly initialized Portal client (see Getting Started)
  • An Account Abstraction-enabled client with a smart contract wallet (see Account abstraction)
  • An active wallet funded with the token(s) you intend to batch, on an eip155: chain

sendBatchUserOp

Builds, signs, and broadcasts a batch of token transfers as a single UserOperation. Portal’s paymaster sponsors the gas; the user pays nothing in native tokens.
result.data.userOpHash is a UserOperation hash, not an on-chain transaction hash — it will not resolve on a block explorer such as Etherscan or Monadscan. To wait for on-chain inclusion, call portal.waitForConfirmation(result.data.userOpHash, params.chain).
portal.waitForConfirmation resolves an RPC URL for the chain from gatewayConfig before it can poll for the UserOperation receipt. This works out of the box for the 10 built-in gateway chains (which include Ethereum Sepolia and Monad Testnet); for any other eip155: chain, add an RPC URL for it to gatewayConfig when you initialize Portal, or the call throws No gateway URL configured for network "...".

Parameters

SendBatchUserOpRequest: SendBatchUserOpTransaction:

Returns

Promise<BroadcastBatchedUserOpResponse>:

sendBatchedAssets

Like sendBatchUserOp, but appends a gas-reimbursement transfer to the batch. The paymaster still sponsors the gas; the reimbursement call recovers that cost from the user’s smart account, in a fee token of your choice (e.g. USDC). The method runs a two-pass build: the first pass builds the user’s calls plus a placeholder fee call and estimates the gas cost of the full batch (metadata.estimatedGasCostWei); the second pass builds the final batch with the real fee amount.

GasReimbursement fields

sendBatchedAssets throws if the estimated gas cost is 0. Some chains/bundlers carry no on-chain fee on the UserOperation (e.g. bundler-level sponsorship that covers all fees). On those chains use sendBatchUserOp instead.

Low-level primitives

If you need direct control over the build/sign/broadcast cycle, use the low-level methods. Unlike the Web SDK, signing a userOpHash on React Native does not require a PortalCurve argument — portal.rawSign takes the message and an optional chain ID instead.
buildBatchedUserOp returns metadata.estimatedGasCostWei — a build-time upper bound (totalGas × maxFeePerGas). This value is '0' on chains where the UserOperation carries no on-chain fee. metadata.totalGas and metadata.maxFeePerGas may also be undefined on backends that predate these fields.

buildBatchedUserOp

buildBatchedUserOp(params: BuildBatchedUserOpRequest, traceId?: string): Promise<BuildBatchedUserOpResponse> UserOperationCall:

broadcastBatchedUserOp

broadcastBatchedUserOp(params: BroadcastBatchedUserOpRequest, traceId?: string): Promise<BroadcastBatchedUserOpResponse>

Error handling

sendBatchUserOp and sendBatchedAssets validate their input before doing any async work, and wrap downstream failures with context about which step failed: The low-level buildBatchedUserOp and broadcastBatchedUserOp methods validate their own required fields (chain, calls/userOperation/signature) the same way, throwing before making a network request if any are missing.

Limitations

  • Batch UserOperations are only supported on eip155: (EVM) chains — there is no Solana or other non-EVM equivalent.
  • Requires Account Abstraction to be enabled for your organization and client; standard MPC wallets cannot batch calls into a single UserOperation.
  • sendBatchedAssets requires the target chain/bundler to report a non-zero estimatedGasCostWei. Use sendBatchUserOp on chains where gas is fully sponsored with no on-chain fee.

Differences from the Web SDK

The request/response shapes and method names are identical to the Web SDK’s batch UserOperations, including validation rules and the sendBatchedAssets two-pass build/estimate flow. Two things differ:
  • Signing the userOpHash: The Web SDK signs via portal.rawSign(PortalCurve.SECP256K1, hashToSign). React Native’s portal.rawSign doesn’t take a PortalCurve — call it as portal.rawSign(hashToSign, chain, options?) instead.
  • waitForConfirmation: On Web, waitForConfirmation routes any eip155: chain through the connected provider automatically. On React Native, it resolves an RPC URL from gatewayConfig first — see the warning under sendBatchUserOp above.

Best practices

  • Use sendBatchUserOp / sendBatchedAssets for the common case; drop to the low-level buildBatchedUserOp / rawSign / broadcastBatchedUserOp flow only when you need to inspect or modify the UserOperation before it’s signed.
  • Pass your own traceId when you need to correlate a batch’s buildTransaction, build, sign, and broadcast calls with your own logs — otherwise the SDK generates one automatically.
  • Use signatureApprovalMemo to tell users what they’re approving, especially for sendBatchedAssets, where the batch includes a fee transfer the user didn’t explicitly request.
  • Call portal.waitForConfirmation(result.data.userOpHash, chain) after broadcasting if a subsequent step depends on on-chain inclusion — broadcasting only confirms the bundler accepted the UserOperation, not that it landed on-chain.
  • For gas reimbursement, keep convertGasToFeeAmount fast and resilient (it runs mid-flow, between the estimate and final build) and apply a bufferBps margin to absorb gas-price drift between the two passes.

Support

If you encounter any issues or have questions about batch UserOperations, feel free to reach out to our support team.