Architecture
Veil uses three cooperating layers to make recurring payouts usable without publishing the full recipient set on-chain.
Overview
┌─────────────────────────────────────────────────────────┐
│ Solana Base Layer │
│ • Vault accounts (token storage) │
│ • Schedule accounts (timing + payout totals) │
│ • Merkle roots for recipient membership │
│ • Final settlement state │
└─────────────────────────────────────────────────────────┘
│
↓ Delegate Schedule
┌─────────────────────────────────────────────────────────┐
│ MagicBlock Ephemeral Rollup │
│ (TEE Execution) │
│ • Private claim_payment execution │
│ • Recipient mapping stays off-chain │
│ • Batch processing │
└─────────────────────────────────────────────────────────┘
│
↓ Commit State
┌─────────────────────────────────────────────────────────┐
│ Coordinator Service │
│ • Monitors schedules for execution │
│ • Delegates to ER │
│ • Executes claims │
│ • Stores proofs and execution history │
└─────────────────────────────────────────────────────────┘Components
1. Solana Program
The Anchor program manages:
- Vaults - token-specific balances per employer
- Schedules - recurring payout state with Merkle roots
- Claims - verification and settlement of individual payouts
- Config - governance, ER authority, whitelist, and batch limits
Key instructions:
init_vaultdeposit/withdrawcreate_schedulepause_schedule/cancel_scheduleclaim_paymentcommit
2. MagicBlock Ephemeral Rollup
The ER layer provides:
- TEE execution for private claim flow
- batch processing across recipients in a scheduled run
- state handoff back to Solana through commit
Flow:
- Coordinator delegates schedule state to ER
- ER executes
claim_paymentattempts - Commit final state back to Solana
- Undelegate schedule / vault state
3. Coordinator Service
The coordinator automates execution and exposes the operational API:
- registration API - stores recipient payloads and Merkle proofs off-chain
- polling - checks for schedules due for execution
- delegation - moves state into ER when needed
- execution - drives payout attempts
- commitment - commits final state back to Solana
- observability - health checks, metrics, and execution history
- abuse protection - request body caps, idempotent registration, and rate limiting
Current API surface:
POST /api/schedulesGET /api/schedules/:schedulePdaGET /api/schedules/:schedulePda/executionsGET /api/healthGET /api/metrics
Payment Flow
1. Schedule Creation
Employer → Create Schedule
├─ Build Merkle tree from recipients
├─ Store Merkle root on-chain
├─ Reserve funds in vault
└─ Set execution interval2. Execution Cycle
Coordinator → Poll for due schedules
├─ Delegate schedule to ER
├─ Execute claim_payment (private in TEE)
│ ├─ Verify Merkle proof
│ ├─ Transfer tokens
│ └─ Update paid bitmap
├─ Commit final state to Solana
└─ Undelegate schedule3. Batch Completion
When all recipients are paid or the batch times out:
- reserved amount is decremented
- next execution time is advanced
- the paid bitmap is reset for the next run
Privacy Model
What’s Public
- vault addresses
- schedule PDAs
- Merkle roots
- total recipients count
- execution interval
- reserved amount
- per-execution amount
- schedule status and next execution timestamp
What’s Private
- individual recipient addresses
- individual payment amounts
- recipient ordering
- Merkle proofs
- recipient-to-amount mapping
Security Considerations
- Merkle proof verification ensures only valid recipients can claim
- TEE execution reduces exposure of recipient payloads
- reserved balances keep promised funds locked for active schedules
- batch timeout prevents indefinite execution windows
- rate limiting protects the coordinator’s public API from abuse