Prize savings vaults on Solana, earn yield-based prizes without risking your principal.
Moocon Vaults is a tokenized prize savings protocol. Deposit any supported token, receive a transferable position token (pToken), and the yield generated by all depositors is pooled and paid out to a single winner each round. Winners are selected by a verifiable on-chain commit–reveal scheme combined with MagicBlock VRF, run inside a MagicBlock Ephemeral Rollup for fast, low-cost fulfillment. Your principal is always redeemable 1:1.
| Live app | https://moocon.xyz/ |
| Docs | https://docs.moocon.xyz/ |
| Program ID (Devnet) | 42HTr1W3XTLoYRzbXgxij89nPg38LXYmQoztTXtTpSuT |
Lending yield is safe and boring. Anything actually exciting requires putting principal at risk. There's no middle ground.
Prize savings products solve this , they've existed in traditional finance for decades with hundreds of billions locked in them. On-chain, the concept is still early, and existing implementations are limited to native SOL staking. Moocon Vaults is the first to open it up to any supported lending token, stablecoins included.
- Deposit USDC or WSOL , funds flow into Jupiter Lending and earn yield continuously.
- Receive pTokens , position tokens representing your share of the vault. Transferable. 1 pToken = 1 ticket.
- Every round (30–60 min), a winner is drawn from all current depositors using MagicBlock VRF + commit–reveal, executed on a MagicBlock Ephemeral Rollup.
- Winner claims the round's pooled yield as pTokens of the same vault.
- Withdraw anytime , burn pTokens to redeem the underlying tokens.
A points system and referral program sit on top for growth incentives.
No participant , including the protocol , can know or influence who wins before it happens. The drawing depends on two independent entropy sources that must both be present before a winner can be derived, and the randomness lifecycle runs on a MagicBlock Ephemeral Rollup (ER) for fast, low-cost fulfillment.
Step 1 , Snapshot. Every eligible vault position is captured into a Merkle tree at round start. Each depositor's wallet and ticket weight is included. The Merkle root is committed to the smart contract on-chain.
Step 2 , Commit. The operator hashes a secret and submits it to the contract (base layer), which creates the round's Reward account holding the committed secret hash and Merkle root. From this point, the secret is locked in.
Step 3 , Delegate + request. The Reward account is delegated to the MagicBlock ER, and a VRF request is issued from inside the rollup against the delegated ephemeral queue. The MagicBlock VRF oracle fulfills it via an on-ER callback that writes the randomness into the reward.
Step 4 , Reveal. The operator publishes the secret (on the ER). The secret and the on-chain VRF randomness are XOR-combined into a final seed, which runs through the KISS algorithm to pick a winner index. The reveal transaction also commits and undelegates the finalized reward back to the base layer, where anyone can verify the result against their Merkle proof and the winner can claim.
Prize-linked savings accounts (PLSAs) have existed in banking for decades. A bank pools the interest earned across all depositors and pays it out as prizes instead of distributing it pro-rata. The friction:
- Opaque draws. The drawing happens inside the institution. Depositors must trust that the winner was selected fairly , there is no way to independently verify the RNG, the eligible-participant set, or the prize amount.
- Custodial principal. Your deposit sits on the bank's balance sheet. Redemption depends on the institution's solvency and operating hours, not a guarantee.
- Walled gardens. Positions are non-transferable and account-bound. You cannot sell, lend, or compose your savings position with anything else.
- Jurisdiction-locked. Each product is bound to one bank, one currency, one regulatory regime.
Moocon Vaults reconstructs the same product as a composable, verifiable on-chain protocol:
- Verifiable draws. Eligibility is snapshotted into a Merkle tree whose root is committed on-chain. The winner is derived from two independent entropy sources , an operator commit–reveal secret XOR-combined with MagicBlock VRF , so no party (including the operator) can predict or bias the outcome. The request/fulfill/reveal steps execute inside a MagicBlock Ephemeral Rollup and the finalized result is committed back to base layer. Anyone can recompute the result from their Merkle proof.
- Non-custodial principal. Deposits flow into Jupiter Lend and are represented by a transferable pToken. Principal is redeemable 1:1 by burning pTokens against the program , no operator approval, no business hours.
- Composable positions. pTokens are SPL tokens: transferable, tradeable, and usable as collateral elsewhere. 1 pToken = 1 ticket, so the position is the lottery entry.
- Any supported token. Not limited to native SOL staking , any Jupiter-supported lending token (USDC, WSOL today) can back a vault.
Deposit ──▶ Jupiter Lend (yield) ──▶ pTokens (1:1, transferable)
│
round start: Merkle snapshot ──▶ root on-chain (base)
│
commit (secret hash) ──▶ create Reward (base)
│
delegate Reward ──▶ MagicBlock Ephemeral Rollup
│
request_randomness (ER) ──▶ MagicBlock VRF oracle callback (ER)
│
reveal: secret XOR VRF ──▶ KISS RNG ──▶ winner index, then
commit + undelegate Reward back to base
│
winner claims pooled yield • anyone withdraws principal anytime
- Operator liveness. Rounds are driven by an off-chain operator (snapshot → commit → delegate → request → reveal). The operator cannot bias the result (VRF entropy is external), but it can stall a round by not revealing. Principal redemption is unaffected and always available.
- VRF + ER dependency. Randomness relies on the MagicBlock VRF oracle fulfilling requests inside the Ephemeral Rollup, and on the ER validator being available to accept the delegated reward and commit it back. A reveal cannot complete until fulfillment lands on the ER.
- Snapshot timing. Eligibility is fixed at snapshot time. Deposits made mid-round are not eligible until the next round's snapshot.
- Yield-source risk. Prizes depend on yield generated by Jupiter Lend; the protocol inherits the underlying lending market's risk and rate variability.
- Devnet only. Currently deployed to Devnet. Token set and economic parameters are not production-hardened.
Prerequisites: Bun, Solana CLI, Anchor 0.32, Rust toolchain.
git clone https://github.com/<your-org>/moocon-vaults.git
cd moocon-vaults
bun installanchor build
bun run test # boots the local MagicBlock stack, runs all suites, tears downThe randomness flow is exercised against a real local MagicBlock stack rather than a mock:
bun run test (via scripts/local-er/run-tests.sh) starts a base validator
(mb-test-validator), an Ephemeral Rollup (ephemeral-validator), and the vrf-oracle,
then runs mocha against base :8899 + ER :7799. The binaries come from the dev dependency
@magicblock-labs/ephemeral-validator (installed by bun install). See
scripts/local-er/README.md for the stack details.
Per-suite tests (each boots + tears down the stack) are wired up in package.json:
bun run test:deposit
bun run test:randomness
bun run test:reveal
bun run test:multi-user
bun run test:reward-lifecycle
# Or manage the stack yourself:
bun run local-er:start # start base + ER + vrf-oracle (deploys the program)
bun run local-er:smoke # one-shot end-to-end draw sanity check
bun run local-er:stopcd api
bun install
bun run dev # http://localhost:7777cd app
bun install
cp .env.example .env # set VITE_API_ENDPOINT + VITE_SOLANA_RPC_URL
bun dev # http://localhost:5173cd landing
bun install
bun dev # http://localhost:3000cd docs
bun install
bun devBootstrapping a fresh deployment, funding wallets, and triggering rounds:
bun run scripts/devnet/init.ts # initialize global state
bun run scripts/devnet/init-vault.ts # create a vault (USDC / WSOL)
bun run scripts/devnet/deposit.ts
bun run scripts/devnet/draw.ts # snapshot → commit → reveal a round
bun run scripts/devnet/claim.ts
bun run scripts/devnet/redeem.tsThe program is built with Anchor (Rust) and deployed to Solana Devnet.
| Program ID | 42HTr1W3XTLoYRzbXgxij89nPg38LXYmQoztTXtTpSuT |
| Supported tokens | USDC, WSOL |
| USDC faucet | https://faucet.circle.com/ |
| SOL faucet | https://faucet.solana.com/ |
Two ways to exercise the deployed Devnet program end-to-end:
- Web app (minimal frontend) , live at https://moocon.xyz/, or run locally (
cd app && bun dev, see Quickstart §4). Connects a wallet, deposits, and shows positions/rounds against the Devnet program. - CLI scripts (
scripts/devnet/*.ts) , a runnable client covering the full lifecycle:init→init-vault→deposit→draw(snapshot/commit/reveal) →claim→withdraw. Each prints the resulting Devnet transaction signature.
Built on Jupiter Lend, MagicBlock Ephemeral Rollups + VRF, and Metaplex Token Metadata.