/**
 * Incremental sapling-diff cache (the FETCH layer).
 *
 * octez.js's SaplingTransactionViewer re-fetches a pool's ENTIRE `single_sapling_get_diff`
 * on every balance/transaction read (O(pool size), no offset, no cache). A pool's diff only
 * ever grows (commitment/nullifier trees are append-only), so this cost climbs without bound
 * and is paid on every scan, for every account, for every asset viewed.
 *
 * This module makes that fetch incremental WITHOUT touching the audited decrypt/spend logic:
 * a caching read-provider wraps the real RPC adapter and reconstructs the head diff from a
 * persisted FINALIZED prefix plus a freshly-fetched UNCONFIRMED tail. The viewer still runs
 * its normal `getBalance()` over the (identical) reconstructed diff, so there is zero risk of
 * a wrong balance — the only thing that changes is how many bytes cross the wire.
 *
 *   today:       get_diff(head)                      → 525 KB every scan (XTZ pool, and growing)
 *   incremental: get_diff(head~2, offset=cached)     → ~125 B when nothing finalized since last
 *              + get_diff(head,   offset=finalized)  → only the unconfirmed tail (≤2 blocks)
 *
 * Cached data is PUBLIC pool state (encrypted commitments + nullifiers) keyed by
 * `(rpc host, set contract / sapling id)` — account-agnostic, so it is shared across every
 * shielded account on the device and carries no decrypted/private material.
 *
 * Reorg safety: Tezos (Tenderbake) finalizes a block after 2 confirmations, so the diff at
 * `head~2` is immutable — safe to persist. The unconfirmed tail (`head~2`..`head`) is fetched
 * fresh every scan and NEVER persisted, so a reorg of a recent block self-heals on the next
 * scan, and an account's own just-submitted note still shows immediately (it's in the tail).
 *
 * Foolproof by construction: any error (offset unsupported, short chain, store failure, …)
 * falls back to the wrapped adapter's full fetch — never a wrong or missing result.
 */
/** The shape octez.js's get_diff RPC returns (snake_case, passed through verbatim). */
export interface SaplingDiffResponse {
    root: string;
    commitments_and_ciphertexts: unknown[];
    nullifiers: unknown[];
}
/** Persisted FINALIZED state for one pool. Public data only. */
export interface CachedSaplingDiff {
    /** count of finalized commitments cached (the next offset_commitment to fetch from) */
    offC: number;
    /** count of finalized nullifiers cached (the next offset_nullifier to fetch from) */
    offN: number;
    commitments: unknown[];
    nullifiers: unknown[];
}
/**
 * Pluggable persistent store for the diff cache. The browser uses an IndexedDB-backed
 * implementation automatically; Node/Lambda/tests can inject {@link MemoryDiffStore} or a
 * custom store. Methods may be sync or async.
 */
export interface SaplingDiffStore {
    get(key: string): Promise<unknown> | unknown;
    set(key: string, value: unknown): Promise<void> | void;
    delete(key: string): Promise<void> | void;
    /** Optional: delete every key with the given prefix (used to evict an account's balance cache). */
    deleteByPrefix?(prefix: string): Promise<void> | void;
}
/** In-memory store (process lifetime). For Node/Lambda/tests; browsers should use IndexedDB. */
export declare class MemoryDiffStore implements SaplingDiffStore {
    private readonly map;
    get(key: string): unknown;
    set(key: string, value: unknown): void;
    delete(key: string): void;
    deleteByPrefix(prefix: string): void;
}
/** IndexedDB-backed store — works on the main thread AND inside Web Workers (same origin DB). */
export declare class IndexedDbDiffStore implements SaplingDiffStore {
    private readonly dbName;
    private readonly storeName;
    private dbPromise;
    private open;
    get(key: string): Promise<unknown>;
    set(key: string, value: unknown): Promise<void>;
    delete(key: string): Promise<void>;
    deleteByPrefix(prefix: string): Promise<void>;
}
/** The default store for the current runtime: IndexedDB if available (browser / web worker), else none. */
export declare function createDefaultDiffStore(): SaplingDiffStore | null;
export type DiffTarget = {
    kind: 'contract' | 'id';
    id: string;
};
/**
 * A pool's diff at head, split into the immutable FINALIZED prefix (head~2, persisted) and the
 * UNCONFIRMED tail (head~2..head, never persisted). `finalized*` are the FULL finalized arrays
 * (indices 0..finalizedCount); the tail arrays continue from there. Positions are absolute and
 * stable (commitment/nullifier trees are append-only), which is what lets a decrypted-note
 * cache key off the position.
 */
export interface PoolDiffSplit {
    root: string;
    finalizedCommitments: unknown[];
    finalizedNullifiers: unknown[];
    tailCommitments: unknown[];
    tailNullifiers: unknown[];
}
/**
 * Sync a pool's diff incrementally: extend the persisted finalized prefix by its offset, then
 * fetch the fresh unconfirmed tail. Persists ONLY the finalized prefix. The finalized fetch
 * transfers ~nothing in steady state; the tail is ≤2 blocks. This is the shared core used both
 * by the v1 read-provider (which merges the two) and the v2 balance cache (which needs them
 * separately so it can persist decrypted notes for the finalized prefix only).
 */
export declare function syncPoolDiff(store: SaplingDiffStore, rpcUrl: string, target: DiffTarget): Promise<PoolDiffSplit>;
/**
 * Wrap an octez.js read provider so the viewer's `get_diff` calls at `head` are served
 * incrementally. Every other provider method, and any non-`head` block read, delegates to the
 * real adapter unchanged. Any failure in the incremental path also delegates (full fetch), so
 * the wrapper can only ever make reads cheaper — never wrong, never failed.
 */
export declare function makeCachingReadProvider<T extends object>(adapter: T, rpcUrl: string, store: SaplingDiffStore): T;
//# sourceMappingURL=saplingDiffCache.d.ts.map