The only Solana unlock that nobody sees coming. Private token vesting, payroll, and grants on the same rails. Built on Umbra Privacy.
π Live demo: https://penumbra-three.vercel.app
π Deployed program (devnet): 6ZajuboUT9uBgnY9RBbHdErx1rTg6kMjSFkocT1WLbdr Β· deploy tx
π― Notarization tx: Solscan β memo "Penumbra"
π» Source: https://github.com/suvvvv/penumbra
Every Solana token unlock is public. Every cliff gets front-run. Every DAO contributor has their comp history doxxed by default. Penumbra ends that.
| Module | Who it's for | What it does |
|---|---|---|
| Vest (hero) | Token foundations, VC funds | Unobservable vesting. Cliffs complete without a public signal. Investors still get scoped attestations. |
| Stream | DAOs, grant programs | Private payroll, retainers, research grants. |
| Audit | CPAs, fund admins | Accept a scoped viewing key, decrypt just the authorized window, export an 8949-ready CSV. |
Every unlock on Solana is public. Analysts and MEV bots short into every cliff. Median price action after a 4-5% supply unlock: β14 to β18% within 72 hours. Foundations "solve" this with OTC sales, delayed vesting, or silent off-chain distributions β all terrible compromises.
Every DAO contributor paid in stablecoins hands any block-explorer user their full earnings history. Recruiters, competitors, exes, and adversaries can read it like a CV.
Transparency to the right parties (cap table, fund admin, tax authority) without transparency to everyone else. Public blockchains don't offer this. Umbra does.
Penumbra is three modules on one privacy rail:
- Foundation shields the full vest supply into an Umbra ETA owned by a
VestSchedulePDA. - Our Anchor program (
programs/penumbra-scheduler) records the cadence on-chain. No amounts, no recipients on-chain. - A keeper calls
tickon cadence. The program CPIs into Umbra'sgetEncryptedBalanceToReceiverClaimableUtxoCreatorFunction. A receiver- claimable UTXO lands in the stealth pool. - Recipients claim privately. Gas paid by the Umbra relayer.
- Foundation issues per-investor, per-fiscal-year viewing keys via
getComplianceGrantIssuerFunction. Cap-table transparency preserved.
Same primitives, different cadence. DAOs pay contributors without ever broadcasting the amount or recipient.
Accountant loads a grant ID, clicks decrypt, gets a CSV. Umbra's MPC re-encrypts just the authorized window for the grantee's X25519 key.
Each of these matters, and together they don't exist anywhere else:
- Encrypted Token Accounts (ETAs) β private-by-default balances, Rescue- ciphered, PDA-controllable. Vanilla Solana Confidential Transfer extensions can't be held by arbitrary PDAs without losing viewing-key separation.
- Stealth-pool UTXOs β Groth16-proof receiver-claimable UTXOs. Sender β recipient link severed cryptographically, not by heuristic obfuscation.
- Time-hierarchical MVKs β a single Poseidon hash chain turns "give me a fiscal-year viewing key" into one SDK call. This is the compliance primitive that nobody else has, and it's the reason Vest can offer real cap-table transparency at all.
- L1/viewing key decoupling β PDAs hold funds, X25519 keys read balances. A vesting PDA can schedule disbursements while the foundation MVK alone reads the history.
Eight distinct @umbra-privacy/sdk factories plus our own Anchor program
that CPIs into Umbra.
| Lifecycle stage | Umbra SDK factory |
|---|---|
| Session init | getUmbraClient, getUserRegistrationFunction |
| Treasury shielding | getPublicBalanceToEncryptedBalanceDirectDepositorFunction |
| Treasury withdraw | getEncryptedBalanceToPublicBalanceDirectWithdrawerFunction |
Vest tick (CPI from PenumbraScheduler) |
getEncryptedBalanceToReceiverClaimableUtxoCreatorFunction + @umbra-privacy/web-zk-prover |
| Recipient scan | getClaimableUtxoScannerFunction |
| Recipient claim (gasless) | getReceiverClaimableUtxoToEncryptedBalanceClaimerFunction |
| Attestation issue | getMasterViewingKeyDeriver β getComplianceGrantIssuerFunction |
| Fund admin / CPA decrypt | getSharedCiphertextReencryptorForUserGrantFunction |
See app/app/docs/page.tsx for the recipes and
app/lib/umbra/real.ts for the live wiring.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Next.js 16 app (app/) β
β β
β / overview + unlock narrative β
β /vest foundation dashboard (HERO) β
β /vest/simulator unlock-FUD chart (WOW) β
β /employer stream / payroll β
β /contributor recipient claim + tax preview β
β /accountant scoped decrypt + CSV export β
β /docs six SDK recipes β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β app/lib/umbra/ β
β service.ts shared interface used by every UI β
β real.ts live @umbra-privacy/sdk calls (8 factories) β
β demo.ts deterministic shim β reliable demos β
β hook.ts useUmbra() picks impl based on toggle β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β programs/penumbra-scheduler (Anchor) β
β Β· initialize_schedule Β· tick β
β Β· cancel Β· attest β
β tick() CPIs into Umbra to post stealth-pool UTXOs. β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
Solana devnet Β· Umbra devnet indexer / relayer / MPC
t-1d keeper polls PenumbraScheduler PDAs, finds cliff_ts β€ now
t+0 keeper.tick(schedule)
β PenumbraScheduler verifies due tranche index
β CPI into Umbra getEncryptedBalanceToReceiverClaimableUtxoCreatorFn
β UTXO lands in stealth pool keyed to recipient stealth addr
β program emits TrancheTicked (no amount, no recipient)
t+0.1h recipient wallet scans pool β finds UTXO via
getClaimableUtxoScannerFunction β claims gasless into ETA
t+quarterly foundation.attest(investor_x25519, fy_window)
β Umbra compliance-grant PDA created
β event emitted; investor dashboard decrypts own history
PenumbraSchedulerdevnet program id:6ZajuboUT9uBgnY9RBbHdErx1rTg6kMjSFkocT1WLbdr(Solscan β program account)- Deploy transaction:
36XSiK3JXnTeZawRCCVzgZtRxDYL9RRVupJLuhLqZQia23ZhsupQJyS8JjcBdbezss6WxFLnhqnxnmmB73VNeE1M - Upgrade authority:
2gxmyPVvXYir9Gt8oFRW7YVTatfkjcd2awRqf1EFMdtd - Umbra SDK version:
@umbra-privacy/sdk@4.0.0 - Umbra devnet endpoints (auto-configured):
- indexer:
https://utxo-indexer.api-devnet.umbraprivacy.com - relayer:
https://relayer.api-devnet.umbraprivacy.com
- indexer:
Requires Node β₯ 20. Anchor + Solana CLI optional (needed only to rebuild the program).
# Frontend
cd app
npm install
npm run dev
# β http://localhost:3000
# Program (optional β already deployed to devnet)
cd programs/penumbra-scheduler
anchor build
anchor deploy --provider.cluster devnetEnvironment variables (optional β defaults work for demo mode):
# app/.env.local
NEXT_PUBLIC_UMBRA_NETWORK=devnet # or mainnet-beta
NEXT_PUBLIC_SOLANA_RPC_URL=https://api.devnet.solana.com
NEXT_PUBLIC_SOLANA_RPC_WS=wss://api.devnet.solana.comSee DEMO_SCRIPT.md β tight 4:30 walk-through, opens with the unobservable
unlock and closes on the CSV export.
Demo vs live mode. The app ships with a demo-mode toggle (top nav).
With it on, every SDK call runs against an in-memory shim with seeded
Neuron Labs + Acme Labs data β so the video never breaks on an RPC flake.
Flip it off and every call in app/lib/umbra/real.ts dispatches to
@umbra-privacy/sdk@4 against Umbra devnet.
Umbra/
βββ app/ # Next.js 16 frontend
β βββ app/
β β βββ page.tsx # landing
β β βββ vest/ # foundation vesting dashboard
β β β βββ page.tsx
β β β βββ simulator/page.tsx # unlock-FUD chart (hero wow)
β β βββ employer/ # stream / payroll
β β βββ contributor/ # recipient claim
β β βββ accountant/ # scoped decrypt
β β βββ docs/ # six SDK recipes
β β βββ layout.tsx
β βββ components/
β β βββ ui/ # design system primitives
β β βββ layout/ # top nav, providers
β β βββ vest/ # dashboard + simulator
β β βββ employer/
β β βββ contributor/
β β βββ accountant/
β βββ lib/
β βββ constants.ts
β βββ types.ts
β βββ store/ # Zustand (persisted, bigint-safe)
β βββ umbra/
β βββ service.ts # shared interface
β βββ real.ts # live @umbra-privacy/sdk calls
β βββ demo.ts # deterministic shim
β βββ seed.ts # stream seeded data
β βββ vest-seed.ts # vesting seeded data
β βββ hook.ts # useUmbra()
β βββ index.ts
βββ programs/
β βββ penumbra-scheduler/ # Anchor program
β βββ Cargo.toml
β βββ src/lib.rs # all 4 instructions
β βββ tests/
β βββ README.md
βββ Anchor.toml
βββ Cargo.toml
βββ DEMO_SCRIPT.md
βββ README.md
| Criterion | How Penumbra scores |
|---|---|
| Core SDK integration | 8 distinct Umbra factories across ETAs, stealth-pool UTXOs, compliance grants, MPC re-encryption β plus a custom Anchor program that CPIs into Umbra. Not cosmetic. |
| Innovation | Private token vesting isn't on Umbra's prompt. It's the only compelling "only possible with Umbra" demo we found β needs PDA+ETA custody, stealth UTXOs, and time-hierarchical TVKs together. |
| Technical execution | Anchor program + Next.js app + live/demo mode toggle + typed factory wrappers + BigInt-safe persist + deployable program. |
| Commercial potential | Every Solana token project with β₯1 vest schedule is a buyer. Every DAO paying in stables is a secondary. |
| Impact | Fixes unlock FUD, fixes contributor doxxing, keeps regulators and fund admins happy. |
| Usability | Role-switchable, gasless claims, one-click attestations, interactive simulator. |
| Completeness | Six working surfaces + Anchor program + docs page + simulator + README + demo script. |
MIT.