# PoolSession

> Method-by-method reference for the SDK's main runtime object: signatures, parameters, returns, and errors.

`PoolSession` is the main runtime object. It is built by [PoolSessionBuilder](pool-session-builder), carries the wired services, and exposes the user-facing operations as methods. Usage walkthroughs live on the Operations pages; this page is the method reference. Parameter and result shapes are defined in the [types reference](types-reference).

All methods return promises except `getRevocableKeyIndex()`, the facade's only synchronous method. Most listed errors are exported from the package as types only, so catch them by matching `error.name` rather than `instanceof` (see [errors](types-reference#errors)).

## Deposit

```ts
deposit(params: DepositParams): Promise<TxReceipt>
prepareDeposit(params: DepositParams): Promise<PrepareDepositResult>
executeDeposit(result: PrepareDepositResult): Promise<TxReceipt>
depositFor(params: DepositForParams): Promise<TxReceipt>
prepareDepositFor(params: DepositForParams): Promise<PrepareDepositResult>
```

-   `deposit` runs prepare and execute in one step and resolves once the deposit transaction is mined.
-   `prepareDeposit` builds the deposit witness, proof, and calldata without submitting. For an ERC20 whose allowance is too low, the result carries an `approvalTx` that `executeDeposit` submits first.
-   `depositFor` deposits on behalf of another recipient, identified blindly by `noteAddressHash` or through `discoveryData`.

Throws: `InvalidDepositParams` (parameter validation), `AssetNotEnabled` (asset disabled on the [Entrypoint](../protocol/contracts/entrypoint)), `BelowMinimumAmount`, `AllowanceCheckFailed`, `DepositWitnessFailed`, `DepositProofFailed`, `DepositRecipientViewingKeyUnregistered` (`depositFor` with an unregistered recipient), `UnexpectedTransactionTarget` (prepared calldata fails the target check at execute time).

## Transfer and payment requests

```ts
prepareTransfer(params: TransferParams): Promise<PrepareTransferResult>
relayTransfer(params: RelayTransferParams): Promise<TransferResult>
transfer(params: TransferParams): Promise<TransferResult>
executeTransfer(opts: ExecuteTransferParams): Promise<TransferResult>
prepareColdStartTransfer(params: ColdStartTransferParams): Promise<PrepareTransferResult>
generatePaymentRequest(params: GeneratePaymentRequestParams): Promise<PaymentRequest>
prepareFulfillPaymentRequest(params: FulfillPaymentRequestParams): Promise<PrepareTransferResult>
```

-   `prepareTransfer` builds a private transfer (a transact proof with zero public output) and returns `executeOptions` for self-submission plus one `relayOptions` entry per configured relayer.
-   `relayTransfer` re-proves against the chosen relayer's processor and fee commitment, submits through that relayer, and settles local note state.
-   `transfer` and `executeTransfer` are the self-submit path: the prepared proof defaults its processor to your own address, so submission works but your wallet is publicly visible as the sender.
-   `prepareColdStartTransfer` targets a recipient by EVM address with no keystore lookup at all, generating the note secrets for you to deliver [out-of-band](../concepts/discoverable-vs-oob).
-   `generatePaymentRequest` is the recipient side of [payment requests](../operations/payment-requests) (five note slots by default).
-   `prepareFulfillPaymentRequest` is the payer side, and its result is submitted with `relayTransfer` or `executeTransfer` like any transfer.

Throws: `InvalidTransactParams` (validation, including a fee-commitment asset that differs from `tokenId`), `TransactNoteNotActive` (an input is not `ACTIVE`), `InsufficientTransactValue`, `RecipientViewingKeyUnregistered` (recipient unregistered and `allowOutOfBandFallback` not set), `WitnessPreparationFailed` (including the unregistered-sender case, surfaced as a "Leaf not found in tree" message), `FeeCommitmentExpired` (quote expired before submission), `RelayerRequestFailed` / `RelayerRejected` (relayer transport and rejection), `InvalidPaymentRequestParams`.

## Withdraw

```ts
prepareWithdraw(params: WithdrawParams): Promise<PrepareWithdrawResult>
relayWithdraw(params: ExecuteWithdrawRelayerParams): Promise<TxReceipt>
withdraw(params: WithdrawParams): Promise<TxReceipt>
executeWithdraw(result: PrepareWithdrawResult): Promise<TxReceipt>
```

-   `prepareWithdraw` builds a transact proof with a public output leg bound to `recipientAddress`.
-   `relayWithdraw` submits a prepared withdrawal through the relayer in the selected quote.
-   For self-submission, pass `processorAddress: yourWalletAddress` into `prepareWithdraw` or `withdraw`. By default the prepared calldata binds the zero address as processor and reverts on-chain with `PoolVault_InvalidProcessor`.

Throws: `InvalidTransactParams` (validation, including `amountSent` not equal to `amount + feeAmount`, and quote fields diverging from the fee commitment), `TransactNoteNotActive`, `InsufficientTransactValue`, `WitnessPreparationFailed`, `FeeCommitmentExpired`.

## Batch withdraw

```ts
prepareBatchWithdraw(params: BatchWithdrawSessionParams): Promise<PrepareBatchWithdrawResult>
relayBatchWithdraw(params: PrepareBatchWithdrawResult): Promise<TxReceipt>
selfSubmitBatchWithdraw(params: SelfSubmitBatchParams): Promise<TxReceipt>
prepareSelfSubmitBatch(params: SelfSubmitBatchParams): Promise<SelfSubmitBatchPrepareResult>
executeSelfSubmitBatch(prepared: SelfSubmitBatchPrepareResult): Promise<TxReceipt>
```

-   `prepareBatchWithdraw` partitions the asset's `ACTIVE` notes into single-label groups of at most five, requests one aggregate relayer quote, and builds one proof per group bound to its signed per-item routing. No local mutation.
-   `relayBatchWithdraw` submits the single `relayBatch` and, once the receipt's `Transacted` logs confirm every nullifier, persists the batch's note-state changes; unconfirmed nullifiers are warned about and left for `discoverNotes()`.
-   The self-submit trio proves zero-fee items and submits `relayBatch` as your own transaction; `SelfSubmitBatchParams` adds `relayContractAddress`.

Throws: `BatchWithdrawBaseError` subclasses `EmptyBatchSelection`, `BatchTooLarge`, `AssetNotRelayable` (a nonzero `maxRelayFee` below relay cost), `InfeasibleBatchFee` (a fee above its item's output), `BatchRoutingMismatch`, `BatchRoutingInvalid` (the relayer's signed routing disagrees with the SDK's recomputed fees); `RelayerInteractorBaseError`; `PoolSessionTransactBaseError` when the batch delegate is not configured. See [Batch withdraw](../operations/batch-withdraw).

## Withdraw and swap, reshield, swap and deposit

```ts
prepareSwapQuote(params: PrepareSwapQuoteParams): Promise<PreparedSwapQuote>
relayWithdrawAndSwap(params: ExecuteWithdrawAndSwapRelayerParams): Promise<TxReceipt>
estimateReshieldAmount(params: EstimateReshieldParams): Promise<ReshieldEstimate>
prepareReshieldQuote(params: PrepareReshieldQuoteParams): Promise<PreparedReshieldQuote>
relayReshield(params: ReshieldParams): Promise<TxReceipt>
estimateReshieldCrosschainAmount(params: EstimateReshieldCrosschainParams): Promise<ReshieldCrosschainEstimate>
prepareReshieldCrosschainQuote(params: PrepareReshieldCrosschainQuoteParams): Promise<PreparedReshieldCrosschainQuote>
relayReshieldCrosschain(params: ReshieldCrosschainParams): Promise<TxReceipt>
prepareSwapAndDeposit(params: SwapAndDepositParams): Promise<PrepareSwapAndDepositResult>
executeSwapAndDeposit(result: PrepareSwapAndDepositResult): Promise<TxReceipt>
swapAndDeposit(params: SwapAndDepositParams): Promise<TxReceipt>
```

-   `prepareSwapQuote` runs the relayer fee estimate, the aggregator quote, and the committed relayer quote, then validates every field of the signed commitment; `relayWithdrawAndSwap` proves and submits through `RelaySwaps`. Both need `withSwapQuoteProvider(...)`.
-   The reshield trio adds a `contractCalls` quote whose final step deposits the swapped output; you build the deposit proof yourself with `prepareDeposit` and pass it as `depositResult`. Needs `withSwapAndDepositQuoteProvider(...)` too. The `...Crosschain` trio takes `toChainId` and a destination-scoped `depositResult`, with an optional `dustRescue` stealth opt-in.
-   `prepareSwapAndDeposit` / `executeSwapAndDeposit` is the inbound, wallet-funded path: no `transact`, no relayer; the aggregator transaction's last step is the deposit.

Throws: `PoolSessionTransactBaseError` (a provider or delegate not configured); `SwapQuoteProviderBaseError` subclasses `SwapQuoteFailed`, `SwapStatusFailed`, `UnallowedLiFiAddress` (target or approval address outside `approvedRouters`), `RelaySwapsLayoutMismatch` (the contract's `ROUTING_TYPEHASH` disagrees with the SDK's encoding), `LiFiDepositCalldataNotFound`, `LiFiDepositTargetNotFound`, `LiFiRecipientNotFound`; `PoolSessionSwapDepositBaseError` subclasses `InvalidSwapAndDepositParams`, `SwapAndDepositQuoteFailed`. See [Withdraw and swap](../operations/withdraw-and-swap), [Reshield](../operations/reshield), [Swap and deposit](../operations/swap-and-deposit).

## Yield

```ts
readonly yield?: YieldSessions            // the first configured deployment, if any
readonly yields: readonly YieldSessions[] // every configured deployment, in configuration order
yieldFor(tokenAddress: Address): YieldSessions | undefined
```

Yield is a namespace per deployment rather than a set of session methods. `yieldFor` matches the share token or its underlying (case-insensitively) and returns `{ chainId, deployment, deposit, withdraw, token, router }`; `deposit` and `withdraw` are the yield sessions, `token` and `router` the `PPYieldToken` and `PPRouter` interactors.

```ts
yieldFor(t).deposit.sharesForUnderlying(underlyingAmount: bigint): Promise<bigint>
yieldFor(t).deposit.sizeSharesForBudget(budget: bigint, headroomPpm?: bigint): Promise<BudgetSizedYieldDeposit>
yieldFor(t).deposit.prepareYieldDeposit(params: YieldDepositParams): Promise<PreparedYieldDeposit>
yieldFor(t).withdraw.prepareYieldWithdraw(params: YieldWithdrawParams): Promise<PreparedYieldWithdraw>
yieldFor(t).withdraw.prepareYieldWithdrawRelay(params: YieldWithdrawRelayParams): Promise<PreparedYieldWithdrawRelay>
```

-   Deposits are sized in shares: `sharesForUnderlying` is `previewDeposit` exactly; `sizeSharesForBudget` fits the router's full price plus a rate headroom inside an all-in budget. `prepareYieldDeposit` builds the standard deposit proof, re-targets it at `PPRouter.depositExactShares`, and returns `approvalTxs`, `depositTx`, and `pendingNote`.
-   `prepareYieldWithdraw` builds the standard withdrawal proof against the router, sizes `minUnderlyingOut` from `quoteWithdraw` minus `slippageBps`, and returns a single `withdrawTx`. `prepareYieldWithdrawRelay` binds the relayer's signed fee commitment instead and returns typed relay params carrying `processorAddress = PPRouter` and `minUnderlyingOut`.

Configure with `withYieldDeployment(s)` on the builder, or let it derive deployments from the relayer's `/v1/details`. Throws: `YieldSessionBaseError` subclasses `InvalidYieldAmount` (non-positive shares, or a cap below the quote), `UnexpectedDepositCalldata` / `UnexpectedWithdrawCalldata`, `InvalidYieldAddress`, `DuplicateYieldDeployment`. See [Yield deposit](../operations/yield-deposit) and [Yield withdraw](../operations/yield-withdraw).

## Ragequit

```ts
rageQuit(params: RageQuitParams): Promise<TxReceipt>
prepareRageQuit(params: RageQuitParams): Promise<PrepareRageQuitResult>
executeRageQuit(result: PrepareRageQuitResult): Promise<TxReceipt>
```

Recovers a note's full value to its recorded owner; the circuit forces the destination, and the SDK method is camelCase while the contract method is `ragequit`. On a confirmed receipt the note is marked `EXITED` locally.

Throws: `InvalidRageQuitParams`, `NoteNotFoundError` (commitment not in the local note set), `RagequitNoteAlreadyExitedError`, `RagequitAddresslessNoteError` (a note whose `ownerAddress` is the zero address can never ragequit), `WitnessPreparationFailed` (including the unregistered-owner case), `UnexpectedTransactionTarget`.

## Keystore

```ts
isKeystoreRegistered(): Promise<boolean>
registerKeystore(options?: RegisterKeystoreOptions): Promise<TxReceipt[]>
prepareRegisterKeystore(options?: RegisterKeystoreOptions): Promise<RegisterKeystoreResult>
executeRegisterKeystore(result: RegisterKeystoreResult): Promise<TxReceipt[]>
getRevocableKeyIndex(): Hex
discoverRevocableKeyIndex(config: Omit<DeriveFromSignatureConfig, "revocableKeyIndex">, gapLimit?: number): Promise<Hex>
rotateRevocableKey(config: RotateRevocableKeyConfig): Promise<RotateRevocableKeyOutcome>
prepareRotateRevocableKey(config: RotateRevocableKeyConfig): Promise<RotateRevocableKeyResult>
executeRotateRevocableKey(result: RotateRevocableKeyResult): Promise<RotateRevocableKeyOutcome>
```

-   `isKeystoreRegistered` reads the session owner's on-chain nullifying-key hash (a zero value means unregistered) and takes no argument.
-   `registerKeystore` submits `setAuthPolicy` and, unless `includeViewingKey: false`, `setViewingKey`; it returns one receipt per transaction and handles the already-registered case, including partial registration where only the viewing key is missing. Registration is never automatic: no deposit, transfer, or session-construction path registers for you.
-   `discoverRevocableKeyIndex` recovers a rotated account's current index cold, scanning candidate indices up to `gapLimit` (default 20).
-   `rotateRevocableKey` advances the index by one and re-derives the key from a fresh wallet signature; persist `newRevocableKeyIndex` from the outcome, because future sessions must be built with it.

Throws: `RegistrationCheckFailed` (RPC failure during the status read), `KeystoreNotRegistered` (rotation or index discovery on an unregistered account), `RevocableKeyIndexNotFound` (no index matched within `gapLimit`), `CurrentLeafNotFound`, `RotationKeyMismatch`, `UnexpectedTransactionTarget`.

## Discovery and note management

```ts
discoverNotes(params?: DiscoverNotesParams): Promise<Note[]>
purgePhantomNotes(params?: PurgePhantomNotesParams): Promise<Hash[]>
addNotes(params: AddNoteParams[]): Promise<void>
markNotesSpent(params: MarkNoteSpentParams[]): Promise<void>
markNotesExited(params: MarkNoteExitedParams[]): Promise<void>
```

-   `discoverNotes` scans Note and Transacted events from the persisted sync cursor (or `fromBlock` when given), matches open payment requests, reconciles statuses, and advances the cursor.
-   `purgePhantomNotes` deletes locally stored notes whose commitments do not exist on-chain. It is never called implicitly, supports `dryRun: true`, and must not run while a transaction is in flight.
-   `addNotes`, `markNotesSpent`, and `markNotesExited` are bookkeeping for integrators who broadcast their own transactions: `addNotes` inserts owned outputs as `PENDING` (the transaction must already be mined), `markNotesSpent` records external spends, and `markNotesExited` records external ragequits.
-   After a ragequit, use `markNotesExited`, not `markNotesSpent`: `SPENT` is terminal, and the wrong mark wedges later discovery.

Throws: `NoteDiscoveryScanFailed`, `StateInvariantViolation` (an on-chain event contradicts terminal local state), `InvalidAddNoteParams`, `NoteCommitmentNotMined`, `InvalidMarkNoteSpentParams`, `InvalidMarkNoteExitedParams`, `NoteNotFoundError`, `InvalidStatusTransitionError`, `InvalidNoteError`.

## Export and import

```ts
exportAccount(): Promise<AccountExport>
importAccount(data: AccountExport): Promise<void>
importReceivedNote(note: Note): Promise<void>
```

-   `exportAccount` serializes notes, lineages, the sync cursor, and pending payment requests, stamped with owner and chain id. Keys are excluded.
-   `importAccount` replaces local note and payment-request state with an export.
-   `importReceivedNote` claims a note delivered out-of-band: the SDK verifies the owner matches the session and recomputes the `noteAddressHash` and commitment bindings before storing it as `PENDING`, and the next `discoverNotes()` promotes it.

Throws: `AccountExportMismatch` (export stamped for a different owner or chain), `InvalidNoteError` (shape, owner, or commitment binding fails), `NoteConflictError`.

## Lifecycle and persistence

Build one `PoolSession` per wallet-and-chain pair and reuse it for the user's session; constructing one instantiates services (Poseidon hashing is async, the [NoteManager](note-manager) loads from storage, relayer configs are parsed). NoteManager state goes to the configured persistent-storage adapter; the browser default is `localStorage` under `privacy-pool:v1:note-manager-state:{chainId}:{ownerAddress}` (lowercase, with per-owner keying so multi-account sessions don't collide). See [Integration architecture](../guides/integration-architecture) for what to persist and when.
