> For the complete documentation index, see [llms.txt](https://docs.zama.org/protocol/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.zama.org/protocol/confidential-vault/reference/batcher-interface.md).

# Batcher Interface

Every function, event, and error on the deposit and redeem batchers.

Both batchers — `DepositVaultBatcherConfidential` and `RedeemVaultBatcherConfidential` — expose the same deployed ABI. Encrypted values (`euint64`, `ebool`) are ABI-encoded as `bytes32`.

The Solidity type `IVaultBatcherConfidential` is the gateway-specific extension (join, recover, vault wiring, timing/slippage). Claim, quit, dispatch, and callback live on OpenZeppelin `BatcherConfidential`. This page lists both surfaces.

## Batch states

```solidity
enum BatchState { Pending, Dispatched, Finalized, Canceled } // 0, 1, 2, 3
```

## User functions

### claim

```solidity
function claim(uint256 batchId, address account) returns (euint64)
```

Transfers `account`'s share of a finalized batch — encrypted deposit × exchange rate, rounded down — in the output token, always to `account`. Callable by anyone. A repeat claim transfers zero. Reverts `BatchUnexpectedState` unless the batch is `Finalized`; reverts `ZeroDeposits` if `account` never joined.

### quit

```solidity
function quit(uint256 batchId) returns (euint64)
```

Refunds the caller's exact encrypted deposit in the input token. All-or-nothing, no fee. Callable only while the batch is `Pending` or `Canceled`. Available while paused. Reverts `ZeroDeposits` if the caller never joined.

### join

```solidity
function join(address beneficiary, externalEuint64 encryptedAmount, bytes calldata inputProof) returns (euint64)
```

Pulls encrypted `fromToken` from the caller and credits `beneficiary` in the current batch. Empty `inputProof` accepts an already-allowed handle. Reverts `InvalidBeneficiary` if `beneficiary` is zero. Joins revert while paused.

Joining is also a `confidentialTransferAndCall` on the input token (`fromToken()`), with the batcher as the recipient. The batcher's `onConfidentialTransferReceived` hook — callable only by the input token — records the position and emits `Joined`.

### recover

```solidity
function recover(uint256 batchId, address account) returns (euint64)
```

Refunds `account`'s deposit in a canceled batch, on their behalf. Funds always go to `account`. Available while paused. Reverts `BatchUnexpectedState` unless the batch is `Canceled`.

## Lifecycle functions (permissionless)

### dispatchBatch

```solidity
function dispatchBatch()
```

Closes the pending batch once it reaches its pinned minimum age, opens the next batch, and requests public decryption of the aggregate. Reverts `BatchTooYoung(batchId, elapsed, required)` before the minimum age, and `EnforcedPause` while paused.

### dispatchBatchCallback

```solidity
function dispatchBatchCallback(uint256 batchId, uint64 unwrapAmountCleartext, bytes decryptionProof)
```

Settles a dispatched batch with the public cleartext aggregate and KMS proof. Outcomes: finalizes (vault settlement succeeded), cancels (zero aggregate, paused, or callback deadline passed), or leaves the batch `Dispatched` when the vault call reverted — in which case the call is retryable with identical arguments. Gas is flat in the participant count.

## View functions

### Wiring

| Function             | Returns                                                        |
| -------------------- | -------------------------------------------------------------- |
| `vault()`            | The ERC-4626 vault this batcher settles against.               |
| `fromToken()`        | Input confidential token (cUSDC on deposit, cShare on redeem). |
| `toToken()`          | Output confidential token.                                     |
| `routeDescription()` | Human-readable route string.                                   |

### Batch data

| Function                     | Returns                                                               |
| ---------------------------- | --------------------------------------------------------------------- |
| `currentBatchId()`           | Id of the sole pending batch. Ids start at 1.                         |
| `batchState(uint256)`        | `BatchState` as `uint8`. Reverts `BatchNonexistent` for unopened ids. |
| `deposits(uint256, address)` | The account's encrypted position handle. Zero handle = never joined.  |
| `totalDeposits(uint256)`     | The batch's encrypted aggregate handle.                               |
| `exchangeRate(uint256)`      | Output units per input unit × 10⁶. Zero until finalized.              |
| `exchangeRateDecimals()`     | Always `6`.                                                           |
| `unwrapRequestId(uint256)`   | The dispatch's unwrap request id. Zero until dispatched.              |

### Timing and policy

Per-batch getters return the values pinned at batch creation; the bare getters return the live policy that will apply to the next batch.

| Per batch                        | Live                 | Meaning                                                 |
| -------------------------------- | -------------------- | ------------------------------------------------------- |
| `batchCreatedAt(uint256)`        | —                    | Batch opening timestamp.                                |
| `batchDispatchedAt(uint256)`     | —                    | Dispatch timestamp. Zero until dispatched.              |
| `batchMinBatchAge(uint256)`      | `minBatchAge()`      | Age required before dispatch. Cap: 7 days.              |
| `batchCallbackDeadline(uint256)` | `callbackDeadline()` | Post-dispatch settlement window. Cap: 30 days.          |
| `batchMaxSlippageBps(uint256)`   | `maxSlippageBps()`   | Deposit slippage bound. Cap: 10000. Always 0 on redeem. |
| —                                | `paused()`           | Whether joins and dispatch are halted.                  |
| —                                | `owner()`            | The batcher's owner.                                    |

## Events

```solidity
event Joined(uint256 indexed batchId, address indexed account, euint64 amount);
event Quit(uint256 indexed batchId, address indexed account, euint64 amount);
event BatchDispatched(uint256 indexed batchId);
event BatchFinalized(uint256 indexed batchId, uint64 exchangeRate);
event BatchCanceled(uint256 indexed batchId);
event Claimed(uint256 indexed batchId, address indexed account, euint64 amount);

event MinBatchAgeSet(uint256 minBatchAge);
event CallbackDeadlineSet(uint256 callbackDeadline);
event MaxSlippageBpsSet(uint16 maxSlippageBps);
```

`Joined.amount` is the effective joined amount — zero when the join was clamped. `Claimed.amount` and `Quit.amount` are the actually transferred amounts. All three are encrypted handles, decryptable only by the account. Inherited OpenZeppelin events also fire: `Paused`, `Unpaused`, `OwnershipTransferred`.

## Errors

### Lifecycle

| Error                                                                               | Raised when                                                                                                   |
| ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `BatchUnexpectedState(uint256 batchId, BatchState current, bytes32 expectedStates)` | An operation ran in the wrong state. `expectedStates` is a bitmap of `1 << state`.                            |
| `BatchNonexistent(uint256 batchId)`                                                 | `batchState` queried for an id never opened.                                                                  |
| `BatchTooYoung(uint256 batchId, uint256 elapsed, uint256 required)`                 | `dispatchBatch` before the pinned minimum age.                                                                |
| `ZeroDeposits(uint256 batchId, address account)`                                    | `quit` or `claim` for an account that never joined.                                                           |
| `InvalidExchangeRate(uint256 batchId, uint256 totalDeposits, uint64 exchangeRate)`  | Finalization produced a zero rate (output below one unit) or overflowed `uint64`. The batch deadline-cancels. |
| `SlippageExceeded(uint256 batchId, uint256 actual, uint256 minimum)`                | Deposit settlement value fell below the slippage bound. The callback is retryable.                            |
| `Unauthorized()`                                                                    | The receive hook was called by anything other than `fromToken()`.                                             |

### Configuration (owner / deploy time)

| Error                                                  | Raised when                                                  |
| ------------------------------------------------------ | ------------------------------------------------------------ |
| `InvalidMinBatchAge()`                                 | Setting a minimum batch age above 7 days.                    |
| `InvalidCallbackDeadline()`                            | Setting a callback deadline above 30 days.                   |
| `InvalidMaxSlippageBps()`                              | Setting slippage above 10000 bps.                            |
| `RouteAssetMismatch(address actual, address expected)` | Deploy wiring: asset wrapper does not match `vault.asset()`. |
| `RouteShareMismatch(address actual, address expected)` | Deploy wiring: share wrapper does not wrap the vault.        |
| `InvalidWrapperToken(address token)`                   | Deploy wiring: token is not an ERC-7984 ERC-20 wrapper.      |

### Inherited

| Error                                 | Raised when                             |
| ------------------------------------- | --------------------------------------- |
| `EnforcedPause()`                     | Join or dispatch while paused.          |
| `OwnableUnauthorizedAccount(address)` | Non-owner calling an owner function.    |
| `ReentrancyGuardReentrantCall()`      | Reentrant `claim`, `quit`, or callback. |

Confidential-token errors an integrator also meets: `ERC7984UnauthorizedUseOfEncryptedAmount` (encrypted input bound to the wrong contract/user), `ERC7984UnauthorizedSpender` (missing operator on a `confidentialTransferFrom`), and `SenderNotAllowedToUseHandle` (FHE ACL rejection).

## HCU: the FHE compute budget

FHEVM meters homomorphic operations per transaction (HCU), capped at 20M. A `claim` costs about 2.7M HCU, so **at most 7 claims fit in one transaction**; the eighth reverts with `HCUTransactionLimitExceeded`. Joins and quits fit comfortably in single transactions.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.zama.org/protocol/confidential-vault/reference/batcher-interface.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
