# Notes

> The fundamental unit of value in the pool. Every shielded balance is a set of notes.

A **note** is a record of shielded value the protocol tracks for one specific account. Your balance in the pool is never a single number: it is a set of notes, and each note can be spent independently. [Deposits](/operations/deposit) create notes, [transfers](/operations/transfer) consume notes and create new ones, and [withdrawals](/operations/withdraw) consume notes to release value back to a public address.

## Anatomy of a note

commitment The note's on-chain identifier: `Poseidon(precommitment, label)`, where `precommitment = Poseidon(noteAddressHash, tokenId, value, metadata)`.
value The amount, in wei or the smallest unit of the asset.
tokenId The asset address. ETH uses the placeholder 0xeeee…eeee, while an ERC20 note carries the token's contract address.
label The deposit lineage tag, `Poseidon(precommitment, depositSecret)`, carried forward through transfers.
ownerAddress The EVM address that controls this note, or 0x0…0 for non-owned recipient notes pending an out-of-band claim.
noteSecret A 32-byte secret. It feeds `noteAddressHash = Poseidon(ownerAddress, noteSecret)`, which flows into the precommitment and commitment. The nullifier is `Poseidon(privateNullifyingKey, commitment)` and is not derived from noteSecret.
noteAddressHash `Poseidon(ownerAddress, noteSecret)`. Binds the note to a specific recipient.
isOwned Whether the local session controls this note: `true` for normal notes, `false` for draft recipient notes the session generated as a sender but hasn't claimed (for example, notes awaiting out-of-band delivery).
status One of `INACTIVE`, `PENDING`, `ACTIVE`, `SPENT`, `REJECTED`, or `EXITED`. See [NoteManager](../sdk/note-manager).
createdAtBlock The on-chain `block.timestamp` when the commitment was inserted, as hex. Despite the name it is a timestamp, not a block number. State-proof witnesses recompute the timestamped leaf from it (see [State tree](state-tree)).
spentAtBlock The block number when the nullifier was published, as hex. Null while the note is unspent.
txHash The hash of the note-creation transaction.
depositSecret An optional secret, bound into `label = Poseidon(precommitment, depositSecret)` at deposit time. It is present only on the note that originated its lineage.

## Note lifecycle

1.  **Created** when a note enters the system through a deposit, as a transact output (either change or a recipient note), or through an import.
2.  **`INACTIVE`** for draft and unclaimed notes the session knows about but cannot yet spend.
3.  **`PENDING`** immediately after creation: a deposit waits for ASP attestation, while a transact output waits for chain inclusion.
4.  **`ACTIVE`** once attested or confirmed, at which point the note is spendable.
5.  **`SPENT`** when spending the note through a transact or withdraw publishes its nullifier on-chain.
6.  **`EXITED`** after a successful ragequit.
7.  **`REJECTED`** if the ASP refuses to attest, which is recoverable via [ragequit](/operations/ragequit).

### Valid status transitions

`NoteManager.updateNoteStatus` enforces `VALID_STATUS_TRANSITIONS` and throws `InvalidStatusTransitionError` for any edge not listed below:

| From | Allowed to |
|---|---|
| `INACTIVE` | `INACTIVE`, `PENDING`, `EXITED` |
| `PENDING` | `PENDING`, `ACTIVE`, `EXITED`, `REJECTED` |
| `ACTIVE` | `ACTIVE`, `SPENT`, `EXITED`, `REJECTED` |
| `SPENT` | `SPENT` |
| `EXITED` | `EXITED` |
| `REJECTED` | `REJECTED`, `EXITED` |

When a note transitions to `SPENT` or `EXITED`, `spentAtBlock` is set if it is currently unset: `spentAtBlock ??= currentBlock ?? bigintToHex(syncCursor)`.

**Before spending:** verify the selected inputs against [`PoolVault`](/protocol/contracts/pool-vault)`.spentNullifiers(nullifier)`. This catches notes that are already spent on-chain even when local state is stale after a partial flow. See [Failure modes](../dev-guide/failure-modes).

## Why notes (and not balances)?

Tracking value as notes rather than one balance is what makes the privacy properties work.

-   **Per-spend privacy**: each spend reveals only a fresh [nullifier](/concepts/commitments-and-nullifiers), computed from the spender's private nullifying key and the note's commitment, so the chain learns that *some* note was spent but not which one.
-   **Composability**: the `transact_NxM` circuit family takes N input notes and produces M outputs, which lets you split and merge value freely.
-   **Selective disclosure**: because every note carries its own secret, handing an auditor one note's secret reveals exactly that payment and nothing else (see [Selective disclosure](selective-disclosure)).
