All Stealth Pool factories live under @umbra-privacy/sdk/burn.
getBurnableStealthPoolNoteScannerFunction
Import: @umbra-privacy/sdk/burn
function getBurnableStealthPoolNoteScannerFunction(
args: { client: IUmbraClient },
deps?: GetBurnableStealthPoolNoteScannerFunctionDeps,
): BurnableStealthPoolNoteScannerFunction;
Returns a zero-arg scanner. When called, it discovers every active Stealth Pool tree, loads scan progress from client.utxoDataStore, fetches missing ranges from the indexer, decrypts ciphertexts addressable by your viewing keys, persists progress, and returns the result grouped by (kind, source).
client.indexerApiEndpoint must be set (pass it to getUmbraClient).
Deps
fetchStealthPoolNoteData?: StealthPoolNoteDataFetcherFunction — override the default indexer note-data fetcher.
fetchMerkleProof?: MerkleProofFetcherFunction — override the single-leaf Merkle proof fetcher used internally for sanity checks. The burner factory uses its own fetchBatchMerkleProof dep at submit time.
aesDecryptor?: AesDecryptorFunction — override the AES-GCM decryptor used to decode receiver-burnable note ciphertexts.
x25519GetPublicKey? / x25519GetSharedSecret? — override X25519 ECDH primitives.
additionalX25519PrivateKeys?: readonly X25519PrivateKey[] — multi-key wallets can scan against extra X25519 keys.
Returns
type BurnableStealthPoolNoteScannerFunction = () => Promise<ScannedStealthPoolNoteResult>;
ScannedStealthPoolNoteResult
interface ScannedStealthPoolNoteResult {
readonly etaToStealthPoolSelfBurnable: readonly DecryptedStealthPoolNoteData[];
readonly etaToStealthPoolReceiverBurnable: readonly DecryptedStealthPoolNoteData[];
readonly ataToStealthPoolSelfBurnable: readonly DecryptedStealthPoolNoteData[];
readonly ataToStealthPoolReceiverBurnable: readonly DecryptedStealthPoolNoteData[];
readonly scannedTrees: readonly ScannedTreeProgress[];
}
interface ScannedTreeProgress {
readonly treeIndex: U128;
readonly scannedRange: { start: U32; end: U32 } | null;
readonly totalLeaves: U32;
readonly fullyScanned: boolean;
}
Notes are not proof-bundled — proofs are fetched per batch at burn time.
Errors
Throws FetchUtxosError (named with the legacy noun; class name retained for backwards compatibility — the error itself covers V18 Stealth Pool Note scanning). See Errors.
Example
import { getBurnableStealthPoolNoteScannerFunction } from "@umbra-privacy/sdk/burn";
const scan = getBurnableStealthPoolNoteScannerFunction({ client });
const result = await scan();
console.log("Self-burnable from ETA:", result.etaToStealthPoolSelfBurnable.length);
getReceiverBurnableStealthPoolNoteIntoETABurnerFunction
Import: @umbra-privacy/sdk/burn
function getReceiverBurnableStealthPoolNoteIntoETABurnerFunction(
args: { client: IUmbraClient },
deps: {
fetchBatchMerkleProof: BatchMerkleProofFetcherFunction;
zkProver: IZkProverForBurnReceiverBurnableStealthPoolNoteIntoEncryptedTokenAccount;
relayer: {
submitBurn: BurnSubmitterFunction;
pollBurnStatus: BurnStatusPollerFunction;
getRelayerAddress: () => Promise<Address>;
};
hooks?: BurnHooks;
awaitCompletion?: boolean; // default true
pollingIntervalMs?: number; // default 3000
timeoutMs?: number; // default 120_000
/* additional optional crypto + RPC + key-derivation overrides */
},
): ReceiverBurnableStealthPoolNoteIntoETABurnerFunction;
Burns receiver-burnable notes into the caller’s ETA. Natively batches: groups by destinationAddress, chunks to ≤5 per proof.
Required deps
fetchBatchMerkleProof — typically client.fetchBatchMerkleProof (auto-wired when indexerApiEndpoint is set on the client).
zkProver — getClaimReceiverClaimableUtxoIntoEncryptedBalanceProver() from @umbra-privacy/sdk/zk-prover. (The interface type is aliased internally as IZkProverForBurnReceiverBurnableStealthPoolNoteIntoEncryptedTokenAccount — the underlying type is identical.)
relayer — adapter built from getUmbraRelayer({ apiEndpoint }). BurnSubmitterFunction and BurnStatusPollerFunction are V18 TypeScript aliases of ClaimSubmitterFunction and ClaimStatusPollerFunction, so the relayer client’s submitClaim / pollClaimStatus plug in directly under the renamed property names.
Returns
type ReceiverBurnableStealthPoolNoteIntoETABurnerFunction = (
stealthPoolNotes: readonly (DecryptedStealthPoolNoteData & { kind: "receiver-burnable" })[],
optionalData?: OptionalData32,
microLamportsPerAcu?: MicroLamportsPerAcu,
) => Promise<BurnStealthPoolNoteIntoETAResult>;
interface BurnStealthPoolNoteIntoETAResult {
readonly signatures: readonly TransactionSignature[]; // every tx submitted (from OperationOutcome)
readonly batches: Map<U32, BurnBatchResult>; // keyed by batch index
}
interface BurnBatchResult {
readonly requestId: string; // relayer-assigned tracking ID
readonly status: BurnStatus;
readonly txSignature?: string; // on-chain burn tx (when landed)
readonly callbackSignature?: string; // MPC callback tx (when finalised)
readonly resolvedVariant?: string; // e.g. "claim_into_existing_shared_balance_v18"
readonly failureReason?: string | null;
readonly stealthPoolNoteIds?: readonly string[]; // "treeIndex:leafIndex" pairs
}
type BurnStatus =
| "received" | "validating" | "offsets_reserved" | "building_tx" | "tx_built"
| "submitting" | "submitted" | "awaiting_callback" | "callback_received"
| "finalizing" | "completed" | "failed" | "timed_out" | "refunded";
completed / callback_received indicate success. The signature to display is callbackSignature ?? txSignature. failureReason containing "NullifierAlreadyBurnt" means the note was already burnt — the SDK treats this as idempotent success.
Errors
Throws ClaimUtxoError. See Errors. The "transaction-validate" stage often indicates a stale Merkle proof — the burner refetches on retry.
getSelfBurnableStealthPoolNoteIntoETABurnerFunction
Import: @umbra-privacy/sdk/burn
Same shape as the receiver variant. MAX_NOTES_PER_PROOF = 1 — the SDK loops internally; caller still passes an array. zkProver is IZkProverForClaimSelfClaimableUtxoIntoEncryptedBalance — use getClaimSelfClaimableUtxoIntoEncryptedBalanceProver from @umbra-privacy/sdk/zk-prover.
getSelfBurnableStealthPoolNoteIntoATABurnerFunction
Import: @umbra-privacy/sdk/burn
Same shape; tokens released to the destination ATA instead of an ETA. zkProver is IZkProverForClaimSelfClaimableUtxoIntoPublicBalance — use getClaimSelfClaimableUtxoIntoPublicBalanceProver from @umbra-privacy/sdk/zk-prover.
Receiver-burnable → ATA exists on-chain but is not yet shipped in the SDK. Use receiver-burnable → ETA then a regular withdrawal until the SDK adds the direct path.
Full scan + burn example
import {
getBurnableStealthPoolNoteScannerFunction,
getReceiverBurnableStealthPoolNoteIntoETABurnerFunction,
getSelfBurnableStealthPoolNoteIntoETABurnerFunction,
} from "@umbra-privacy/sdk/burn";
import { getUmbraRelayer } from "@umbra-privacy/sdk";
import {
getClaimReceiverClaimableUtxoIntoEncryptedBalanceProver,
getClaimSelfClaimableUtxoIntoEncryptedBalanceProver,
} from "@umbra-privacy/sdk/zk-prover";
const r = getUmbraRelayer({ apiEndpoint: "https://relayer.api.umbraprivacy.com" });
const relayerDeps = {
submitBurn: r.submitClaim,
pollBurnStatus: r.pollClaimStatus,
getRelayerAddress: r.getRelayerAddress,
};
const scan = getBurnableStealthPoolNoteScannerFunction({ client });
const burnReceiverIntoEta = getReceiverBurnableStealthPoolNoteIntoETABurnerFunction(
{ client },
{
fetchBatchMerkleProof: client.fetchBatchMerkleProof!,
zkProver: getClaimReceiverClaimableUtxoIntoEncryptedBalanceProver(),
relayer: relayerDeps,
},
);
const burnSelfIntoEta = getSelfBurnableStealthPoolNoteIntoETABurnerFunction(
{ client },
{
fetchBatchMerkleProof: client.fetchBatchMerkleProof!,
zkProver: getClaimSelfClaimableUtxoIntoEncryptedBalanceProver(),
relayer: relayerDeps,
},
);
const result = await scan();
if (result.ataToStealthPoolReceiverBurnable.length > 0) {
const out = await burnReceiverIntoEta(result.ataToStealthPoolReceiverBurnable);
for (const [batchIndex, batch] of out.batches) {
console.log("Batch", batchIndex, "status:", batch.status, "id:", batch.requestId);
}
}
if (result.etaToStealthPoolSelfBurnable.length > 0) {
await burnSelfIntoEta(result.etaToStealthPoolSelfBurnable);
}
FetchUtxosError
Thrown by getBurnableStealthPoolNoteScannerFunction.
Stage values: "initialization" | "validation" | "key-derivation" | "indexer-fetch" | "proof-fetch" | "proof-enrichment".
See Errors.
ClaimUtxoError
Thrown by all burner factories.
Stage values: "initialization" | "validation" | "key-derivation" | "zk-proof-generation" | "pda-derivation" | "instruction-build" | "transaction-build" | "transaction-compile" | "transaction-sign" | "transaction-validate" | "transaction-send".
See Errors. Before retrying after "transaction-send", verify on-chain — the nullifier may have been burnt. The burner itself treats NullifierAlreadyBurnt as idempotent success in BurnBatchOutcome.failureReason.