Blender is a deterministic reward distributor on Solana. Creator rewards flow into a program-owned Intake Vault, are blended into a Reward Pool, and are paid out to BLENDER holders via a reward-per-token index. No privacy or mixing features are implemented or intended.
- Blender collects creator rewards, blends them into a single reward pool, and lets holders claim their share at any time.
- Blender is not a mixer and does not provide anonymity or obfuscation.
- Fixed-supply stake token (BLENDER); no minting after deployment, no blacklist, no freezes.
- Collect: Creator rewards (one SPL mint, e.g., USDC) are deposited into the Intake Vault (program-owned token account). Deposits emit
CreatorRewardsDeposited. - Blend: A keeper calls
blend_to_poolto move funds from Intake Vault to Reward Pool. This emitsBlendedToPool. - Index update:
update_rewardsrecomputes the global reward index based on Reward Pool growth; emitsRewardsIndexUpdated. - Claim: Holders call
claim_rewardsand receive their proportional share directly from the Reward Pool; emitsRewardsClaimed.
- Scale constant:
$S = 1{,}000{,}000{,}000$ . - When the pool grows by
$\Delta$ , the reward index increments by$\Delta \times S / \text{total_stake}$ . - A holder with balance
$b$ and last index$I_u$ at global index$I_g$ can claim:$$\text{claimable} = b \times (I_g - I_u) / S.$$ - No snapshots are required; accounting is deterministic from balances and the index.
Path: programs/blender/src/lib.rs
- Config: reward mint, stake mint, blend authority, config authority, thresholds, cooldown.
- GlobalRewards: reward index, total distributed, last updated slot, pool snapshot, total stake, vault bumps.
- IntakeVault: program-owned SPL account for incoming rewards.
- RewardPoolVault: program-owned SPL account for distributable rewards.
- UserRewards: user checkpoint (owner, last reward index, accrued, init flag).
- initialize: set config, PDAs, vaults; assert stake mint authorities are revoked.
- deposit_creator_rewards(amount): deposit reward mint into Intake Vault; emits
CreatorRewardsDeposited. - blend_to_pool(amount): keeper-only move from Intake Vault to Reward Pool; updates index; emits
BlendedToPool. - update_rewards(): refresh index from Reward Pool growth; emits
RewardsIndexUpdated. - claim_rewards(): update index, compute user pending, transfer from Reward Pool; emits
RewardsClaimed. - update_config(...): rate-limited parameter updates by config authority; emits
ConfigUpdated.
- No withdrawal path except
claim_rewards. - Reward mint is fixed in Config and enforced on vaults.
- Stake mint must have mint_authority and freeze_authority removed before initialization.
- Config changes are signer-gated and slot-cooled-down.
- Checked arithmetic throughout to avoid overflows.
Path: apps/worker
- Watches Intake Vault for deposits.
- Triggers
blend_to_poolwhen intake balance exceeds threshold or on schedule. - Calls
update_rewardsafter blends or periodically. - Persists blend cycles and reward updates to Postgres via Prisma; no custody of funds.
Path: apps/web
- Overview of reward pool, total distributed, and index.
- How it works flow and transparency page with PDAs and verification checklist.
- Rewards page for wallet connection and claiming (UI scaffold; on-chain wiring to be added).
- No APR or guaranteed return messaging.
- apps/web: Next.js dashboard (Tailwind, shadcn-style UI primitives).
- apps/worker: Keeper/indexer (Node/TypeScript).
- programs/blender: Anchor program.
- packages/shared: Shared types/constants/reward math utilities.
- packages/db: Prisma schema and client for Postgres.
- docs: Specs, tokenomics, threat model.
- scripts: Deploy and verification scripts.
- tests: Anchor/TS tests.
- infra: docker-compose and env examples.
- Derive PDAs with seeds:
config,global_rewards,intake,reward_pool,user_rewards. - Both Intake and Reward Pool token accounts must be owned by the program PDA and use Config.reward_mint.
- Stake mint must show no mint or freeze authority.
- Observe events:
CreatorRewardsDeposited,BlendedToPool,RewardsIndexUpdated,RewardsClaimed,ConfigUpdated.
Prereqs: pnpm, Rust toolchain, Anchor, Solana CLI, Docker.
pnpm install
# Start Postgres
docker compose -f infra/docker-compose.yml up -d
# Generate Prisma client
cd packages/db && pnpm generate && cd ../..
# Build Anchor program
anchor build
# Run tests
pnpm test
# Run web (in another shell)
cd apps/web && pnpm dev
# Run worker (scaffold loop)
cd apps/worker && pnpm dev- Set
Anchor.tomlprovider cluster to devnet and configure~/.config/solana/id.jsonwith funds. - Build and deploy program:
anchor build && anchor deploy --program-name blender. - Record the program ID and update
PROGRAM_IDin env files and shared constants if needed. - Initialize config with reward mint, stake mint (authorities revoked), blend authority, thresholds, and cooldown slots.
- Fund Intake Vault with the reward mint and let the keeper run.
- Rust unit tests for reward math (tests/src/lib.rs).
- TypeScript tests for worker threshold logic and dashboard claimable math (tests/ts/*).
- docs/spec.md: protocol specification and instruction behaviors.
- docs/tokenomics.md: fixed-supply tokenomics and constraints.
- docs/threat-model.md: risks, mitigations, and assumptions.
- Buyback module directing a portion of intake to purchase BLENDER before blending.
- Burn module for purchased BLENDER.
- Multi-asset reward routing via indexed pools.