# User operations

Source: https://docs.settlemint.com/docs/concepts/custody-and-signing/user-operations
Submit a signed smart-wallet user operation, replace a pending one, estimate gas, read its status and receipt, and see how it settles.

The platform runs an ERC-4337 bundler for each organisation and network, so you send signed user operations to its API instead of running your own bundler, funded [operator wallet](https://docs.settlemint.com/docs/concepts/custody-and-signing/operator-wallet), queue, nonce manager and settlement process. A user operation is the signed instruction a [Smart Wallet](https://docs.settlemint.com/docs/concepts/custody-and-signing/smart-wallet) submits, and an EntryPoint contract validates and executes it.

Each organisation and network has one bundler, its own stored operations, and two interfaces: the Platform API for a typed request and an ERC-4337 JSON-RPC endpoint for a client that already speaks the standard. An ordinary platform write to a deployed single-owner smart wallet takes the same path without starting a transaction workflow.

## Send a user operation [#send-a-user-operation]

`POST /api/v2/bundler/{chainId}/send` takes the canonical EntryPoint and a signed user operation. The platform checks that the EntryPoint is the one this network supports and that the sender belongs to the calling organisation, simulates validation, and stores the operation before answering with its hash. The call does not wait for bundling: a returned hash means the operation is stored, not that it executes. The bundler picks the stored operation up from there.

These checks run before the operation is stored:

- **The payer's funds.** For a [sponsored](https://docs.settlemint.com/docs/concepts/custody-and-signing/gas-sponsorship) operation the platform reads the paymaster's EntryPoint deposit. Otherwise it reads the sender's balance plus its deposit. When the operation's prefund, added to the prefund of the payer's other live operations, exceeds those funds, the submission is refused with `AA31` when the paymaster's deposit is too low, or `AA21` when the sender cannot pay its prefund, the gas the EntryPoint reserves before it runs the operation. A network that charges no gas skips the check, and so does a submission whose funds cannot be read.
- **The priority fee.** A priority fee below the deployment's configured minimum is refused. A network whose fee quote is zero for both fee components is exempt.
- **The maximum fee.** The signed `maxFeePerGas` must reach 1.5 times the base fee of the network's latest block plus the operation's own priority fee, and the base fee counts as zero on a network whose blocks carry none. That is the headroom the bundler signs its bundle with, so the operation still repays the bundle's price if the base fee rises by up to half before the bundle lands. A lower value is refused with a message that names the floor.
- **The pre-verification gas.** The signed `preVerificationGas` must reach the gas the bundler pays to carry the operation, which is the value the estimate returns. A lower value is refused with a message that names the price.
- **The size.** On a network whose blocks carry a calldata floor, an operation larger than the deployment's limit is refused. The default limit is 8,192 packed and ABI-encoded bytes, the ERC-7562 limit.
- **The sender's standing.** When a bundle reverts on chain because an operation became invalid after the platform admitted it, for example because its sender spent the nonce or the funds elsewhere, that sender is refused on the organisation's bundler for a while, 24 hours by default. Only the sender of the operation the revert names is refused, never the other senders in the bundle. A revert on the platform's own paymaster, or on the platform's own operation, refuses no one. The sender's other waiting operations fail instead of being bundled.
- **The pending limit.** An organisation may have a limited number of operations sent through these routes waiting on one network at once, 256 by default. A replacement does not count as a new operation, and neither do the platform's own operations.

A sender refusal and the pending limit answer `429` with code `exec.aa.ADMISSION_THROTTLED`, or JSON-RPC error `-32504`. Both are retryable platform errors: a sender refusal carries `retryAfterSeconds`, and a pending-limit refusal clears as the organisation's operations are bundled. The three limits are deployment settings.

An operation that signs zero for both fee fields on a network whose fee quote is zero for both fee components is exempt from the maximum-fee and pre-verification gas checks, and from the size limit, while the latest block carries no base fee. When that block charges a base fee, `send` refuses it, because no bundle can carry it.

The base fee and the network's fork can change between `send` and the bundle, so the bundler runs the maximum-fee and pre-verification gas checks again on each signed operation, against the block it builds the bundle on.

- An operation whose maximum fee is below that block's floor stays `PENDING` and is checked again at every new block, so it joins a bundle once the base fee falls far enough. Later operations in its lane, the sequence of operations from one sender and one nonce key, wait behind it. A replacement with higher fees sends it sooner.
- It fails if it is still below the floor an hour after the platform last stored it. That hour counts from when it was sent, replaced, released from `BLOCKED` or returned by a dropped bundle.
- An operation whose pre-verification gas is below that block's price can never be carried, such as one stored before a fork raised the calldata floor, so it fails. So does an operation whose maximum fee is below its own priority fee, and one that signs zero for both fee fields on a network that charges a base fee.

Each of these failures carries the error `PRE_FLIGHT_REJECTED`, and the caller sends a new operation with higher fees. An operation that signs zero for both fee fields on a network whose blocks carry no base fee files its bundle at zero fees and skips the pre-verification gas check.

The answer is the operation hash. Submitting the same hash again returns that hash instead of storing a second operation. While the bundler has not accepted the stored, prepared operation, the repeat hands it to the bundler again, which covers a hand-off that was lost. The status and receipt reads below are scoped to the organisation and the network, so a hash outside the organisation's stored operations answers null.

## Replace a pending operation [#replace-a-pending-operation]

`POST /api/v2/bundler/{chainId}/send` with a second signed operation from the same sender at the same nonce replaces the pending one, which is how you reprice an operation whose fees are too low.

- The original must still be a signed operation the integrator submitted, waiting for a bundle. An operation already written into a bundle cannot be replaced, and neither can one the platform prepared itself.
- The replacement's maximum fee and priority fee must each reach the original's value multiplied by 1.1, rounded down to a whole wei.
- A replacement swaps the stored operation and its hash in one step and wakes the bundler, so the original hash then reads as unknown.
- A refusal names its reason: the original is in a bundle, the fee rise is too low, or the operation cannot be replaced.
- The original's prefund does not count against the payer's funds for its replacement.

## Estimate gas [#estimate-gas]

`POST /api/v2/bundler/{chainId}/estimate` returns pre-verification gas, verification gas and a call gas limit, plus the paymaster's verification and post-operation limits for a sponsored operation. It requires a sender the organisation owns.

On a chain that runs the Osaka fork, one transaction carries at most 2^24 gas, and the platform takes the lower of that and the block gas limit. It simulates the call at the limit it is about to return and returns a limit the call finishes within, keeping a 1.05x margin over the measured gas. On a chain that runs the Amsterdam fork, it returns the measured gas with no margin. A call that does not fit the room one transaction leaves is refused with a message that names the measured need and the room. The bundler packs bundles against the same ceiling, so a bundle is not filed with more gas than that ceiling allows.

A chain from the Prague fork on prices a transaction's calldata at no less than a floor. EIP-7623 sets it at 10 gas for a zero byte and 40 for any other byte, and on the Amsterdam fork EIP-7976 raises it to 64 gas for every byte. The floor applies to the whole transaction, so the bundler files each bundle with at least the floor of the calldata it sends. A bundle whose operations cost less than their calldata is filed with the floor instead.

Pre-verification gas is 21,000 plus the larger of two prices:

- The standard price is 85,800 of per-operation overhead plus the operation's encoded bytes at 4 gas for a zero byte and 16 for any other byte, plus 10 gas a 32-byte word.
- The floor price is the same bytes at the chain's floor, plus the 132 bytes of the `handleOps` call that carries them at the floor's non-zero rate.

A small operation stays at its standard price, because its overhead outweighs the floor. A calldata-heavy operation on a floored chain pays its floor, so the bundler is repaid what the chain charges it. The signature, the paymaster data and the fixed-width nonce, gas limit and fee fields count at the non-zero rate whatever bytes they hold. An estimate therefore still holds once the operation is signed with its real nonce and fees.

## Read the status [#read-the-status]

`GET /api/v2/bundler/{chainId}/user-operations/{userOperationHash}` reads the stored operation: its sender, nonce, call data, creation and update times, transaction hash and block number when recorded, its error when one was recorded, and one status.

| Status | What the operation is doing |
| --- | --- |
| `PENDING` | Accepted, reserved against its lane, or being prepared. Nothing has left the platform yet. |
| `BLOCKED` | Waiting on an approval, on payer funds, on bundler funds or on a sponsorship renewal. |
| `BUNDLED` | Written into a bundle that the platform has sent. |
| `MINED` | The bundle landed. The receipt says whether the operation itself succeeded or reverted, and `error` carries the revert data. |
| `FAILED` | It does not execute. The error names the reason. |

The read finds an operation by its hash, so it never answers for a prebuilt operation nobody signed. A `MINED` operation whose call reverted settles as failed. The platform does not re-sign it with a larger gas limit, so the caller sends a new operation.

## Read the receipt [#read-the-receipt]

`GET /api/v2/bundler/{chainId}/user-operations/{userOperationHash}/receipt` answers only after the stored operation is confirmed or reverted on chain, and it answers null before that, and for a missing operation. The block hash comes from the stored settlement. For an operation settled before the platform recorded block hashes, the platform reads it from the network's transaction receipt, and the answer is null while the network returns none. The receipt carries the user operation hash, sender, nonce, a success flag, the transaction hash, the block hash and the block number, plus the failure reason when the operation reverted.

## Use the ERC-4337 endpoint [#use-the-erc-4337-endpoint]

`POST /bundler/{chainId}` speaks ERC-4337 JSON-RPC. It supports `eth_chainId`, `eth_sendUserOperation`, `eth_estimateUserOperationGas`, `eth_getUserOperationByHash`, `eth_getUserOperationReceipt`, `eth_supportedEntryPoints`, `pm_getPaymasterData` and `pm_getPaymasterStubData`. The two paymaster methods apply the sponsorship rules, and their network argument must match the network in the route.

The route needs an API key with an active organisation and write scope. The network must be available to that organisation. Its default network qualifies when it is an enabled EVM network. Another network also needs multi-network access and an active deployment on that network. A batch holds 1 to 100 requests, and a batch that holds only notifications answers HTTP 204 with no body.

## Write directly from a deployed single-owner wallet [#write-directly-from-a-deployed-single-owner-wallet]

An ordinary platform write that goes to a smart wallet with one managed owner key skips the transaction workflow. The write takes the bundler path when no approval policy gates the wallet, the plan clears with that one owner and holds no weighted signers, the account already has code on chain, the organisation does not use gasless forwarding, and the write is not the one that deploys the account.

The platform stores the request and its user operation row in one commit, and hands the row to the bundler only after that commit. The request reaches `COMPLETED` once the bundler has confirmed the operation, and a caller that asked to wait receives that settled outcome within its wait budget. A caller that did not ask to wait gets the request identifier at once. A write that does not qualify, such as a gated, multisig, owner-signed or first write, runs the transaction workflow and reaches the bundler from there. A repeat of a qualifying write with the same idempotency key starts nothing new.

## What happens to an operation no bundle executed [#what-happens-to-an-operation-no-bundle-executed]

A mined bundle can hold an operation the EntryPoint did not execute. The platform reads the operation's nonce at the EntryPoint and searches the EntryPoint's event log for it, and settles on that evidence, so the wallet's lane does not wait.

- One event settles the operation with its real outcome: confirmed, or failed with the data it reverted with.
- A nonce still unused and no event means the EntryPoint did not execute the operation. The platform returns it for a later bundle, at most three times. The next bundle that still carries no event for it fails it with a reason that says the EntryPoint never executed it.
- A nonce that is used with no event means another operation took it, so this one can never execute. It fails with a reason that says the nonce was consumed for another operation.
- A bundle that was never broadcast is abandoned and its operations return for a new bundle. A bundle whose transaction reverted is replayed at the block before it mined: the replay names the failing operation, and the rest return.
- Several events for one operation, a nonce that moved without an event, or a failed chain read hold the bundle with a visible reason and settle nothing.

Inside a mined bundle, elapsed time alone never settles an operation. A sponsorship that expired on a sponsored operation is renewed instead of failing the operation, and a used nonce alone is not evidence until the event log is read.

## What happens to a nonce the bundler skipped [#what-happens-to-a-nonce-the-bundler-skipped]

The bundler wallet sends every bundle at its own transaction nonce, and the chain mines those nonces in order. A nonce that is never sent therefore holds back every bundle above it. A withdrawal from the bundler wallet that was granted a nonce and then rejected leaves exactly that hole.

The platform counts the wallet's nonces from the number the chain has mined, and uses the node's pending count only to find the highest nonce in use. Some nodes count a run of queued transactions above a hole as if the hole were filled, so the pending count alone would hide it.

- A nonce nothing holds goes to the next bundle or withdrawal. When bundles wait above it, the platform fills it with a transfer of zero value from the wallet to itself, after three blocks with no operation ready.
- A nonce that a withdrawal still holds is never filled and never handed to another write.
- A gap-filling transfer stays owned until the chain mines past its nonce. If no configured node knows it six blocks later, the platform releases it and fills the nonce again.
- A bundle the platform cannot read back after a restart is judged by its own transaction hashes. If no configured node knows any of them and the wallet has not reached the nonce, the platform holds the bundle as dropped and raises an alert. It never frees or resends a dropped bundle, so bundling for that organisation and network waits until an operator decides what happens to it.

## What happens to a reservation nobody signed [#what-happens-to-a-reservation-nobody-signed]

A caller that prebuilds an operation reserves the wallet's lane for a lifetime it asks for, and the platform stamps the row with the moment that lifetime lapses. A sweep then closes the rows that were never signed, never bundled and never hashed:

- A prebuilt operation past its lifetime expires with the reason `reservation-expired`, and the caller prepares a new one. It was never signed, so it has no hash and the status read does not find it.
- A reserved operation the platform owns that lapses without a signature fails with the same reason.
- A prebuilt row that was never reserved and has sat for an hour also expires.
- A row whose signature is already stored, or is being committed, is never expired.

## You should see [#you-should-see]

- After you submit a signed operation and keep its hash, the status reads `MINED` or `FAILED`.
- The receipt carries the block number that a reconciliation uses as evidence.
- A `MINED` status with a receipt whose success flag is false is a call that reverted.

## Related pages [#related-pages]

Read [Smart Wallet](https://docs.settlemint.com/docs/concepts/custody-and-signing/smart-wallet) for the threshold that authorises an operation before it is signed, [Operator Wallet](https://docs.settlemint.com/docs/concepts/custody-and-signing/operator-wallet) for the account that pays the bundle, and [Transaction lifecycle](https://docs.settlemint.com/docs/concepts/settlement/transaction-lifecycle) for the workflow an ordinary platform write runs when it does not take this path.
