Skip to main content
Scanning requires the cryptography WASM module. This guide covers unified inbox scanning, balance reads, and sweeping.

Setup

Unified scan

Filter custom announcement rows

If you have indexer JSON instead of adapters:

Cross-chain only

Balances

Per-output native balances (multichain):
Aggregated ERC-20 + native on Ethereum:
Per-output token balances across chains (for a token inbox). Ethereum defaults to the configured tracked ERC-20s; Solana SPL mints (base58) must be passed:

Sweep

Sweep on Starknet

Starknet sweeps don’t go through sweep. Build the calls with buildStarknetSweep and let the app’s Starknet wallet broadcast them — the counterfactual stealth account self-funds its deploy_account fee, so there’s no gas drop or relayer step here.
See Starknet for the full flow and caveats.

Sweep tokens

Pass token to sweep the full ERC-20 / SPL balance instead of the native asset. On Ethereum the stealth address must hold native gas (see gasDrop on the send, or use the gasless sweep below); on Solana set closeAccount to reclaim the token-account rent.

Gasless token sweep

When the stealth address holds a token but no native gas, build a relayer-submittable sweep. The stealth key authorizes it offline; a relayer pays the gas and takes fee in the token (spec/relayer-market.md §9).
On Solana, pass the relayer’s feePayer; the returned transaction is partially signed by the stealth key, and the relayer co-signs as fee payer. The fee is split in the same signed transaction: the destination receives amount - fee and the relayer’s token account receives fee, so the relayer is reimbursed in-token for the gas it fronts (sweep.fee / sweep.destinationAmount report the split):

Submitting to a relayer node

An opaque-relayer node serves the sweep directly over HTTP — no job, bid, or payload round. Discover its per-chain fee payer / forwarder with getSweepInfo, then POST the built sweep with postGaslessSweep (both from @opaquecash/relayer-client):
The node fronts the gas, is reimbursed the in-token fee, and returns the confirmed transaction id. If it rejects the sweep (wrong forwarder, wrong fee payer, or an under-priced fee), the error message says why — rebuild with the values from /v1/sweep/info and retry.

Manual key reconstruction

When you need custom signing logic instead of sweep:
Build a viem PrivateKeyAccount from the bytes and sign a transfer from output.stealthAddress.

PSR trait discovery

Fetch native announcement rows for the chain and scan V2 attestation markers:
DiscoveredTrait includes the shared fields (attestationId, stealthAddress, txHash, blockNumber, discoveredAt, ephemeralPubkey) plus V2 fields (schemaId, schemaName, issuer, attestationUid, dataHex, nonce, merkleLeafPreimage, isValid, issuerAuthorized). getStealthSignerPrivateKeyForReputationTrait needs the ephemeralPubkey field returned by the scanner. Use discoverTraits(rows) or its alias getReputationTraitsFromAnnouncements(rows) only for legacy V1 0xA7 markers. New attestations created by issueAttestation use V2. Low-level witness JSON for custom prover flows: