No-code treasury automation on Solana. Connect a wallet, deposit EURC, and an AI agent continuously allocates idle capital across the highest-yield DeFi protocols — automatically, on-chain, and MiCA-compliant.
Built for the Colosseum Frontier 2026 hackathon (April 6 – May 11, 2026).
Program ID (devnet): Fvs33of5snzzjFjgyY6id1RQ7sqgxX8WDvU2FMECaVqy
European SMEs hold an estimated $3.2 trillion in idle working capital that earns zero yield. VaultFlow lets a finance team create a treasury vault in minutes — no DeFi knowledge required:
- Connect a Phantom wallet
- Deposit EURC (Circle's MiCA-compliant euro stablecoin)
- AI agent monitors live APY across Kamino, Drift, and Raydium, rebalancing automatically when yields shift by more than 200 bps
- Payroll runs on a configurable schedule — recipients are paid automatically when the interval elapses
- Off-ramp back to a SEPA bank account via Transak's fiat widget
Each individual component has competitors. The intersection does not:
| Layer | What VaultFlow built | Why it matters |
|---|---|---|
| EU SME focus | EURC-native vaults, Transak SEPA on/off-ramp | 58% of EU institutions integrating stablecoins by 2026; USDT/EURT are delisted post-MiCA |
| AI-agentic reallocation | On-chain agent authorization, live APY oracle, bps-threshold rebalancing | Removes the DeFi knowledge barrier for SME finance teams |
| MiCA-compliant fiat rails | Transak widget — SEPA → EURC on-ramp and EURC → SEPA off-ramp | No KYB/KYC integration required; Transak handles regulatory compliance |
vault_flow/
├── programs/vault/ # Anchor smart contract (Rust)
│ └── src/
│ ├── instructions/ # 7 program instructions
│ ├── state/ # VaultAccount + PayrollSchedule PDAs
│ ├── protocols/ # Kamino / Drift / Raydium CPI stubs
│ ├── errors.rs
│ └── lib.rs
├── agents/ # AI agent engine (TypeScript)
│ └── src/
│ ├── yield-oracle.ts # Live APY fetcher (Kamino, Drift, Raydium)
│ ├── allocation-engine.ts
│ ├── vault-agent.ts # Poll loop + on-chain reallocate tx
│ ├── config.ts
│ ├── logger.ts
│ ├── retry.ts
│ ├── health.ts
│ └── main.ts
├── app/ # Next.js 16 frontend (App Router, Tailwind v4)
│ ├── app/ # Routes: /, /create, /positions, /payroll, /fiat, /report, /settings
│ ├── components/ # Vault dashboard, allocation sliders, payroll panel, fiat widgets
│ ├── hooks/ # useVault, usePayroll, useYieldRates, useEurRate
│ └── lib/ # Anchor setup, constants, demo helpers
├── tests/
│ └── vault.ts # 13 Anchor integration tests (Mocha)
├── scripts/
│ ├── smoke-devnet.ts # End-to-end devnet smoke test (6 steps)
│ └── set-upgrade-authority.sh
├── Anchor.toml
├── Cargo.toml
├── package.json # npm workspaces root
└── SUBMISSION.md
| Instruction | Who can call | Description |
|---|---|---|
initialize_vault |
Owner | Creates VaultAccount PDA ([b"vault", owner, mint]); validates allocation weights sum to 10,000 bps |
deposit |
Owner | SPL token transfer from owner into vault ATA; checked_add accounting |
withdraw |
Owner | PDA-signed transfer back to owner |
reallocate |
Agent only | Sets reentrancy guard (is_locked), computes allocation deltas, calls protocol CPIs (mainnet feature flag), updates tracking fields |
schedule_payroll |
Owner | Creates/updates PayrollSchedule PDA ([b"payroll", vault]) with recipients and interval |
execute_payroll |
Anyone (permissionless once due) | PDA-signed SPL transfers to each recipient; advances next_execution |
pause_vault / resume_vault |
Owner | Circuit breaker; withdrawals always remain available regardless of pause state |
VaultAccount (185 bytes) — owner, mint, token_account, agent, allocation weights (Kamino/Drift/Raydium bps), deposited_amount, yield_earned, kamino_deployed, drift_deployed, raydium_deployed, is_locked, is_active, bump
PayrollSchedule — vault, next_execution (Unix timestamp), interval_seconds, recipients (Vec, max 50), bump
CPIs to Kamino, Drift, and Raydium are gated behind --features mainnet-protocols. On localnet, reallocate only updates weights and tracking fields — all 13 integration tests pass without any external protocol programs deployed.
| Protocol | Program ID | Notes |
|---|---|---|
| Kamino | KLend2g3cP87fffoy8q1mQqGKjrxjC8boSyAYavgmjD |
deposit / withdraw via invoke_signed; discriminators verified against live IDL |
| Drift | dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH |
EURC spot market index 54; driftSigner account required for withdraw |
| Raydium CLMM | CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK |
increase_liquidity_v2 / decrease_liquidity_v2 (Token-2022 / EURC compatible) |
- Reentrancy guard —
is_lockedis set before any CPI and explicitly cleared on every error path; a failing CPI can never permanently lock a vault - Agent authorization — only the
agentpubkey stored inVaultAccountcan callreallocate; the owner cannot override this - Overflow protection —
deposited_amountuseschecked_add; payroll total usestry_fold+checked_add; all delta math usessaturating_* - ATA validation —
execute_payrollreads raw SPL token account bytes (mint @[0..32],owner @[32..64]) rather than trusting account labels — recipients cannot be spoofed - Events —
emit!()macros on all state-changing instructions (VaultDeposited,VaultWithdrawn,VaultReallocated,PayrollExecuted) for indexer / analytics
every 60 seconds (configurable):
1. fetchRates() — live APY from Kamino strategies API, Drift spot-markets API,
Raydium CLMM pools API (5-min TTL cache; stale fallback on failure)
2. computeAllocation()— proportional APY weighting; minReserveBps liquidity floor always kept liquid
3. fetchVaultState() — read current on-chain allocation via Anchor
4. if any field drifts > REALLOC_THRESHOLD_BPS (default 200):
send reallocate tx
Copy agents/.env.example to agents/.env and fill in:
# Required
AGENT_KEYPAIR_PATH=~/.config/solana/agent.json # must match VaultAccount.agent pubkey
VAULT_ADDRESSES=<vault-pda-1>,<vault-pda-2>
# Optional (defaults shown)
RPC_ENDPOINT=https://api.devnet.solana.com
TICK_INTERVAL_MS=60000
REALLOC_THRESHOLD_BPS=200
MIN_RESERVE_BPS=1000
DRIFT_EURC_MARKET_INDEX=54
LOG_LEVEL=info
HEALTHZ_PORT=8080
# Dead-man's-switch alerting via ntfy.sh (free, no account needed)
NTFY_TOPIC=vaultflow-agent-abc123- Structured JSON logging to stdout/stderr (configurable level)
/healthzHTTP endpoint for external monitoring- ntfy.sh push alerts if no successful reallocation in 4+ hours
- Exponential backoff with full jitter on all RPC and API failures
Next.js 16 (App Router, TypeScript, Tailwind v4, shadcn/ui).
| Route | Description |
|---|---|
/ |
Vault dashboard: balance, yield earned, protocol allocation bar, deposit/withdraw sidebar |
/create |
No-code vault creation: token selector, live allocation sliders (sum validated to 100%), agent pubkey input |
/positions |
All vault positions |
/payroll |
View, schedule, and execute payroll; recipient list editor |
/fiat |
SEPA on-ramp (buy EURC) and off-ramp (sell EURC → EUR wire) via Transak widget |
/report |
Yield and reallocation history |
/settings |
Vault and agent configuration |
/onboarding |
Guided wallet connect → first deposit flow |
Demo mode (NEXT_PUBLIC_DEMO_MODE=true) shows simulated APY data on devnet so the UI is always demonstrable without real on-chain state.
Copy app/.env.example to app/.env:
NEXT_PUBLIC_RPC_ENDPOINT=https://api.devnet.solana.com
NEXT_PUBLIC_DEMO_MODE=true
# Transak fiat widget (free sandbox — no approval needed)
NEXT_PUBLIC_TRANSAK_API_KEY=
NEXT_PUBLIC_TRANSAK_ENV=STAGING| Suite | Tests | Status |
|---|---|---|
Smart contract — Anchor/Mocha (tests/vault.ts) |
13 | Passing |
Agent engine — Jest (agents/src/__tests__/) |
31 | Passing |
Devnet smoke test (scripts/smoke-devnet.ts) |
6 steps | Passing |
Smart contract tests cover: initialize vault, deposit, withdraw, reallocate, agent auth rejection, allocation overflow, schedule payroll, execute payroll (valid + early + wrong recipient count + insufficient funds)
Agent unit tests cover: AllocationEngine (11), YieldOracle (6), VaultAgent (5), retry (6), integration (3)
Devnet smoke test golden path:
initialize vault → deposit 10,000 tokens → reallocate allocation →
schedule payroll → execute payroll (recipient receives 500 tokens) → withdraw 3,000 tokens
- Rust (stable)
- Solana CLI 1.18+
- Anchor CLI 0.31.1
- Node.js 18+
# Add Solana to PATH (add to ~/.zshrc for persistence)
export PATH="/Users/$USER/.local/share/solana/install/active_release/bin:$PATH"
# Verify setup
solana config get
solana config set --url devnet
solana airdrop 2 # fund devnet walletgit clone https://github.com/<your-handle>/vault_flow
cd vault_flow
npm install # installs all workspace deps (root + app + agents)anchor build # compile + generate IDL
anchor test # build + localnet + 13 tests
anchor deploy --provider.cluster devnet # deploy (already deployed — see Program ID above)
# Build with real protocol CPIs (devnet/mainnet only)
anchor build -- --features mainnet-protocolscp agents/.env.example agents/.env
# Edit: AGENT_KEYPAIR_PATH, VAULT_ADDRESSES, RPC_ENDPOINT
npm run agent:start # start agent engine
# or for development:
cd agents && npm run dev # ts-node-dev with hot reloadcp app/.env.example app/.env
npm run app:dev # Next.js dev server at http://localhost:3000
npm run app:build # production buildnpm run smoke:devnet
# Runs: initialize → deposit → reallocate → schedule payroll → execute payroll → withdrawWhy EURC over USDC/USDT? USDT and EURT are both delisted from EU exchanges post-MiCA enforcement. EURC is Circle's MiCA Electronic Money Institution-licensed euro stablecoin, valid across all 27 EU member states. EURC has seen 1000%+ growth since late 2025.
Why agent-authorized reallocation?
Storing a separate agent pubkey in VaultAccount and restricting reallocate to that key means the vault owner cannot accidentally override an in-flight rebalance, and a compromised owner wallet cannot drain via manipulated allocations.
Why --features mainnet-protocols gate?
Kamino, Drift, and Raydium programs are not deployed on localnet. Gating CPIs behind a feature flag means anchor test runs cleanly on a local validator without any external dependencies — the contract logic is fully testable in isolation.
Why Transak instead of Circle API directly? Transak's widget handles KYC, SEPA transfer instructions, and order status entirely client-side via an iframe — no server-side API routes, no webhook infrastructure, and no KYB approval wait before sandbox testing.
Devnet deployment — already live:
- Program ID:
Fvs33of5snzzjFjgyY6id1RQ7sqgxX8WDvU2FMECaVqy - Deploy signature:
5xzn89ZnadfTgYsxyYchpjbGSPUZgqkXEP1rwVDxfoswK9zFEQ9PvMD511BQic7QWZyQAdrnZRMLWFMvXge3HR1d - View on Solana Explorer
Agent hosting — render.yaml included for one-click deploy to Render. Also compatible with Railway and Fly.io.
Mainnet readiness (in progress):
- CPI smoke test against live Kamino/Drift/Raydium devnet deployments
- 2-of-3 Squads multi-sig upgrade authority before mainnet deploy
- Professional smart contract audit (Sec3, OtterSec, or Certik)
- Switch agent to paid Helius/QuickNode RPC endpoint
Production polish:
- Replace demo-mode mock data with live on-chain reads
- Mobile responsive audit (allocation sliders break below 768px)
- Global transaction status toast system
- Sentry/Axiom frontend error tracking
Legal & compliance:
- Terms of Service + Privacy Policy (GDPR-compliant)
- Legal consultation on MiCA CASP obligations for AI-managed treasury vaults
- EU/UK legal entity registration
| Layer | Technology |
|---|---|
| Smart contract | Rust, Anchor 0.31.1 |
| Token standard | SPL Token, EURC (Token-2022) |
| Yield protocols | Kamino Finance, Drift Protocol, Raydium CLMM |
| AI agent | TypeScript, Node.js, @coral-xyz/anchor, @solana/web3.js |
| Frontend | Next.js 16, React 19, Tailwind v4, shadcn/ui, Radix UI |
| Wallet | @solana/wallet-adapter (Phantom) |
| Fiat rails | Transak SDK v4 (SEPA on/off-ramp) |
| Stablecoin | EURC (Circle, MiCA EMI licensed) |
| Testing | Anchor/Mocha (smart contract), Jest (agent), ts-mocha |
MIT