Integration
Onchain events
The pool’s logs are the source of truth for anyone rebuilding shielded state — a wallet, an indexer, a block explorer. Three events carry everything. None of them leak an amount, an asset, or an owner.
The events
| Event | Emitted when | What the chain sees |
|---|---|---|
NoteCommitted | A note enters the tree | An opaque commitment hash and its leaf index. Nothing about the note itself. |
NoteCipher | Paired with every committed note | The note encrypted to its owner’s view key. Only that key can read it. |
Nullified | A note is spent | An unlinkable nullifier. It marks the note spent and ties to no address. |
Signatures and topics
The Solidity signature and its keccak256 topic hash, for filtering logs directly:
NoteCommitted(bytes32 indexed commitment, uint32 leafIndex)
topic0 0xacd3e4a7bca8bf97ebe636db52c23601ef31ff83f3054576536dc2dd85c65d12
NoteCipher(uint32 leafIndex, bytes ciphertext)
topic0 0x60afd175ebe031d03117571e6c2be630fbbdfba97b78a8b386661d0a241b03a0
Nullified(bytes32 indexed nullifier)
topic0 0x42e78517ce08fb9519169f7389ca7fb9cb2651093568ccb618ba89e401eae763Index the pool with viem
Replay from the pool’s deploy block. Every NoteCommitted is a leaf in order; the matching NoteCipher at the same index carries the encrypted note; the Nullified set tells you which leaves are spent.
import { createPublicClient, http, parseAbiItem } from "viem";
const POOL = "0xf9F825f2D6d8509c78baaa587694f74672C32A59";
const DEPLOY_BLOCK = 92522685n;
const client = createPublicClient({
transport: http("https://46630.rpc.thirdweb.com"),
});
// Every leaf, in order — the commitment tree.
const notes = await client.getLogs({
address: POOL,
event: parseAbiItem(
"event NoteCommitted(bytes32 indexed commitment, uint32 leafIndex)",
),
fromBlock: DEPLOY_BLOCK,
toBlock: "latest",
});
// Which of them are spent.
const spent = await client.getLogs({
address: POOL,
event: parseAbiItem("event Nullified(bytes32 indexed nullifier)"),
fromBlock: DEPLOY_BLOCK,
toBlock: "latest",
});Pull NoteCipher the same way and pair it to a note by leafIndex — that is all a wallet needs to find, decrypt, and spend what is yours. The CLI does exactly this on cowl scan.
Note
Governance emits too:
VerifierSwapProposed, VerifierSwapExecuted, and OwnershipTransferred. Watch them to track the timelocked verifier swap on a pool that has not yet renounced ownership.