Shielded Viewing Keys

Happy saturday from zecfi capital!!

I’m trying to understand how to audit/verify shielded ZEC treasury balances.

We receive fees in SOL (our governance token is an SPL token) and currently use Zodl Swap via near to convert SOL → ZEC, which then auto-shields into the shielded pool. We have the Unified Viewing Keys, but our viewing tool shows no shielded memos for these deposits. The autoshield transaction hash shows funds moving into the shielded pool, but it doesn’t appear to create a viewable receipt.

What would be the correct way is to verify shielded treasury reserves?

Couple things to unpack here.

First: if you have the correct Unified Viewing Key (UVK) for the receiving shielded address, you should be able to see incoming notes and memos but only if:

  • The funds were sent to an address derived from that key

  • The wallet scanning with the UVK is fully synced

  • The memo field was actually populated (memos are optional)

Auto-shield flows often don’t include memos. So “no memo visible” doesn’t mean no funds — it just means no memo was attached.

Second: the txid showing funds entering the shielded pool only proves value moved into the pool. It does not prove it was sent to your shielded address.

To verify treasury reserves properly:

  1. Make sure you’re using the incoming viewing key (not just an outgoing key).

  2. Use a tool that rescans from a block height prior to first deposit.

  3. Confirm that the shielded address used by the swap service matches one derived from your unified address.

If you want audit-grade verification, the correct method is:

  • Publish a view-only key (or incoming viewing key) for the treasury address.

  • Let auditors independently scan the chain for notes belonging to that key.

  • Reconcile shielded note values against internal accounting.

If your current viewer shows nothing, the most common causes are:

  • Wrong key type

  • Funds were shielded to a different address

  • Scanner not synced far enough back

Start by confirming the exact unified address the swap is paying into and derive the viewing key from that same seed. That’s usually where the mismatch happens.

1 Like

the only keys I see are unified viewing key or view key (private). I used the unified.

im rather new to dev related things; struggling to figure this out. I would love to do audit grade verifications that I can post consistently. or figure out a way to have like an easy 1.2.3. step guide for holders to check whever they want to verify.

open to a call etc if anyone can help me figure this out. would be greatly appreciated. I had my sol treasury wallet compromised and just wanted to set up safe verifiable treasury balances.

If you used the Unified Viewing Key, that’s correct in principle. That key should let you see all incoming shielded notes for addresses derived from that unified address.

If you’re seeing nothing, it’s usually one of these:

  1. The swap isn’t sending to the same unified address you derived the UVK from.

  2. The viewer hasn’t rescanned from before the first deposit block.

  3. You’re using a tool that doesn’t fully support unified accounts / proper note scanning.

Important: the on-chain “auto-shield” tx only proves funds entered the shielded pool — not that they went to your shielded receiver. That’s the common misunderstanding.

For audit-grade verification, clean structure would be:

:one: Use a dedicated treasury unified address (never reuse personal wallets).
:two: Derive and store the Incoming Viewing Key securely.
:three: Use a reliable full-node-backed viewer to rescan from block height 0 (or before first deposit).
:four: Publish the viewing key (read-only) so anyone can independently verify balances.

That gives you consistent, public proof of reserves without exposing spend authority.

Since you mentioned a prior compromise make sure:

  • The seed phrase for this ZEC treasury is offline and never exposed.

  • The viewing key you publish is not a spending key.

  • The swap service is hardcoded to send only to the exact unified address you control.

If you want a simple “holder verification guide,” it should basically be:

  1. Copy treasury viewing key.

  2. Paste into supported ZEC viewer.

  3. Confirm total shielded balance + note history matches reported treasury.

The biggest thing right now is confirming the swap is actually paying the correct unified address. That’s the first place I’d look.

1 Like

thats where im confused.

I generated a fresh zodl wallet.

I exported seed to cake/ywallet as both have support viewing keys.

both zodl and cake wallet show all the transactions the same;

I fount the txs on intents explore, and the funds did end up in correct zodl/cake wallet that was freshly gen’d after comprimise. I am pretty sure it was only sol wallet that was comprimised but wanted to be safu so generated fresh everything.

how is it possible that the unified viewing key that is generated at the wallet level; not pick up the u addy the intents send to if it ends up in my u balance.

I assume that each time I generate a quote via the swap on zodl; its pointing to a new u addy derived from seed; how else would the funds end up in my wallet.

is it possible that those addys dont show up in viewing keys auth since they were not generated at time of viewing key? as I said im rather novice to dev related technicalities.

ty so much for taking time to respond. :folded_hands:

1 Like

No worries bro, pleasure is all mine. You’re thinking in the right direction, but here’s the key point:

If the funds show up in Zodl and Cake, and both were restored from the same seed, then the notes absolutely belong to that unified account.

A Unified Viewing Key (UVK) is derived from the same seed/account. It is not “frozen in time.” It doesn’t matter if new unified addresses are generated later — they’re all derived from the same account keys. The UVK should see them.

Generating new “u addresses” per swap quote is normal. Those are just diversified addresses derived from the same account. The viewing key should still detect notes sent to any of them.

So if:

  • Wallet shows balance

  • Explorer shows funds entering shielded pool

  • Same seed restored across wallets

Then the issue is almost certainly the viewer tool, not the key or the address derivation.

Common causes:

  1. The viewer is not scanning from the correct birthday height.

  2. The viewer doesn’t fully support unified account scanning the way Cake/YWallet do.

  3. You’re pasting the wrong key type (full viewing key vs unified viewing key mismatch).

  4. The viewer expects an Incoming Viewing Key specifically, not the unified string.

Important distinction:
Unified Viewing Key = container for multiple receiver types.
Some tools want the specific Sapling incoming viewing key, not the unified wrapper.

That’s usually where people get stuck.

If you want audit-grade proof:

  • Pick one wallet (YWallet is solid for this).

  • Restore from seed.

  • Export the incoming viewing key for that account.

  • Test that key in a second independent viewer.

  • Confirm note detection matches wallet balance.

If two independent tools detect the same notes using a viewing key derived from your seed, you have verifiable reserves.

Given your compromise history: you did the right thing generating fresh everything. Just make sure you record the exact account index used (account 0, 1, etc.), because UVKs are account-specific.

You’re not crazy the math guarantees the UVK should see all diversified addresses under that account. If it doesn’t, it’s tooling or key-type mismatch, not protocol behavior.

I’m not sure if it was mentioned but after you import the viewing key, you have to rescan the wallet

We have a decryption tool on cipherscan.

You either need the TX and the viewing key or just the viewing key and wallet birthdate.

It might help you out.

(Decryption all happens on the client side so you should be safe.)