# Discover your notes from chain

> Reconcile your local NoteManager with on-chain state, using the ASP note-events fast path when available.

## What this lets you do

Sync your local view of shielded balances with what's actually on-chain. The SDK's [`NoteManager`](/sdk/note-manager) keeps a per-wallet local index of [notes](/concepts/notes) (commitment, value, status, asset, label), and `discoverNotes()` scans the chain for events that affect your account and reconciles the two.

This is the entry point to every read-side flow: displaying balances and picking which notes to spend.

## Constraints & limits

-   **Cold sync can be slow if the [ASP](/concepts/asp-attestation) is unavailable:** the first `discoverNotes()` starts from the sync cursor, which is `0x0` on a fresh NoteManager. On the ASP fast-path (next bullet) that's cheap, because the ASP serves its indexed event history and only the tail past its last-synced block is fetched over RPC. But on the pure-RPC fallback (no `aspUrl`, or ASP unavailable) the SDK paginates `eth_getLogs` from block 0 at 10K blocks per page, which can hit free-tier rate limits. Bound the scan by passing `fromBlock` (e.g. the pool's deploy block) to `discoverNotes()`. There is no deployment-block config, and the SDK never learns it on its own.
-   **ASP note-events fast-path:** when `aspUrl` is configured, the SDK pulls encrypted Note events from the ASP's `/{chainId}/public/note-events` endpoint instead of paginating `eth_getLogs` itself, then gap-fills any range past the ASP's last-synced block over RPC. (The separate `/{chainId}/public/event-snapshot/payload` endpoint backs status reconciliation, the spent/ragequit/phantom-purge checks, not the primary Note-event scan.)
-   **Cursor and notes live in the persistent-storage adapter you configure,** typically the browser's `localStorage` (the SDK's `LocalStorageService`). The stored state includes the secrets needed to spend, so protect it like any wallet data. Storage is not configured by default, so without an adapter the cursor and notes stay in memory only and are lost on reload, forcing a full rescan next time. Configure a persistent adapter to keep subsequent syncs fast.
-   **Local state can lag behind chain state:** a spent note may still look active locally after a failed or partial flow. Before picking inputs to spend, always [verify spent status on-chain](verify-spent).

## What it unlocks next

-   [List notes](list-notes): filter the result by status / asset / label.
-   [Private transfer](/operations/transfer): pick freshly-discovered `ACTIVE` notes as inputs.
-   [Check note attestation](/operations/deposit#check-a-deposits-attestation-status): see which `PENDING` notes have transitioned to `ACTIVE`.

## How to use it

```ts
// Reconcile from chain. Returns immediately with the up-to-date set.
await session.discoverNotes();

// Read the current view.
const account = await session.exportAccount();
const active = account.notes.filter((n) => n.status === "ACTIVE");
console.log(`${active.length} spendable notes`);
```

**Avoid tight polling:** calling `discoverNotes()` in a tight loop (e.g. from a polling hook with no debounce) reruns chain scans and can starve out RPC quota. Sync on explicit user action or on a long stale-time.

## Behind the scenes

SDK call `session.discoverNotes()`
Data sources ASP `/{chainId}/public/note-events` for the encrypted Note stream (with RPC gap-fill past its last-synced block), falling back to paginated `eth_getLogs` when no `aspUrl` is set. Status reconciliation additionally reads the ASP `event-snapshot` payload (transacts, ragequits, snapshot block)
Decryption Per-note ECDH with your `viewingPrivateKey` against the event's ephemeral pubkey
State update NoteManager flushes new notes and status transitions to the persistent-storage adapter
