Fornex - what it is, what proves it.
Solana devnet only. Multi-agent AI vault with caps enforced inside an Anchor program and per-trade streaming payments to the agent operator. Every claim on this page resolves to a real on-chain account. No staging server, no mock data.
TL;DR
A non-custodial Solana vault where three specialized AI agents (BULL, BEAR, ZEN) debate every 15 minutes and a constrained executor opens a perp position. Every cap is enforced inside an Anchor program; the agent cannot break them.
Each cycle writes a MultiAgentDecision PDA with the full BULL/BEAR/ZEN reasoning, a SyntheticPosition PDA price-marked against Pyth, a NavRecord PDA on close, and a real treasury → agent SOL transfer (pay.sh stream).
We are not a CEX bot, not a custodial yield product, not an audited mainnet protocol, and not running real money. Devnet only. Every claim on this page is verifiable on Solana Explorer.
Multi-agent governance + on-chain caps + Pyth-marked synthetic perps + per-trade streaming agent payments, all on one Solana program. We did not find another submission with all four primitives wired together.
Built on
- SolanaDevnet · chain runtime
- Anchor 0.30Program framework
- PythSOL/USD price oracle for synthetic perps
- Drift ProtocolLive perp execution path (gated by env)
- GPT-4o (Azure)Three parallel system prompts per cycle
- Phantom + SolflareWallet adapter on the dashboard
- HeliusRPC + (planned) WebSocket decision feed
- Next.js + VercelFrontend + API routes
- PM2Agent runtime supervisor
- @fornex/sdkRead-only TS client (packages/sdk)
FAQ
What stops the agent from breaking the leverage cap?
The Anchor program.log_multi_agent_decisionrejects any BULL vote with leverage > 3, any BEAR or ZEN vote > 2, and any consensus with confidence < 60%.update_navrejects any write outside ±10% per cycle.record_trade_outcomerejects any single-trade PnL beyond ±50% of NAV. Caps live in the program, not the agent - seeprograms/fornex/src/errors.rs.Why synthetic perps instead of just Drift?
Drift devnet has been intermittent. We built a self-containedSyntheticPositionPDA that opens with a Pyth-stamped entry price, closes against a Pyth-stamped exit, and computes realized PnL directly in the Anchor program. No external dex dependency. The Drift executor is wired and switchable viaFORNEX_EXECUTOR=driftwhen devnet is healthy.Where does pay.sh money come from? Is it a self-transfer?
Real on-chainSystemProgram::transferfrom a separate treasury keypair to the agent wallet, on every executed trade. The treasury is funded once on devnet; if the env var is missing the code refuses to fake a self-transfer (seeagent/src/paysh.ts). Click any pay.sh tx on the proof page - theFromaccount is treasury, not the agent.What does the agent wallet hold?
On devnet, the agent wallet holds a small float of SOL it uses to execute Drift orders and to pay tx fees for on-chain logging. User deposits live in the Vault PDA, not the agent wallet. The mainnet plan is for the Vault PDA to CPI into Drift via signer seeds so the agent never custodies user funds.Is the AI reasoning stored on-chain or just hashed?
Stored, not hashed. EachAgentVotereserves 200 bytes for reasoning text, and everyMultiAgentDecisionPDA carries three of them - BULL, BEAR, ZEN - plus the consensus. That's the wall on /proof. Truncation is documented inagent/src/config.ts.Why does the win-rate stat actually mean something?
It's derived fromrecord_trade_outcome, which only increments on closed positions with realized PnL. Deposits never count toward win-rate. The inception NAV is stamped on-chain at first deposit so every PnL number on the dashboard is anchored to a real on-chain start point.Can I run this myself?
Yes.git clone,npm install,anchor build, fund a devnet keypair, set the env vars listed in.env.local.exampleandagent/.env.example, thennpm run devandnpm run agent. Single-cycle and force-direction flags are documented inDEMO_SCRIPT.md.What happens if the LLM goes down?
The cycle returns a safe FLAT vote per agent, the consensus comes out FLAT, and the on-chain log records that explicitly. No order is placed. Operational status (Pyth, RPC, agent heartbeat) is surfaced on the dashboard topbar.Does the dashboard ever invent numbers?
No. NAV, share supply, decision count, win-rate, executed-trade count, and pay.sh streamed are all decoded directly from the Vault PDA + program account list. Source:lib/chain.tsandcomponents/TrustStrip.tsx.How does the dashboard get live updates without a backend?
The dashboard opens alogsSubscribeWebSocket directly to the configured Solana RPC and filters for log lines that mention Fornex instructions (`log_multi_agent_decision`, `record_trade_outcome`, `update_agent_reputation`, synthetic open/close). When a match arrives, the relevant page re-fetches. Auto-reconnects with capped exponential backoff. Source:hooks/useDecisionStream.ts.Can I read Fornex state from my own app?
Yes. The repo ships@fornex/sdkatpackages/sdk/- a tiny read-only TypeScript client with peer dep@solana/web3.jsonly.getVault,getDecisions,getNavHistory,getAgentReputation, andgetVaultStrategycover every Fornex PDA in one line.
On-chain proof table
Every row opens Solana Explorer on devnet at the exact account.
Treasury safety
Single signer (FORNEX_TREASURY_KEYPAIR) topped up via the Solana faucet. Audit-friendly: every transfer is on chain, the wallet is publicly known, no real-money exposure.
- Devnet: hot keypair signer · 0.001 SOL per executed trade · audit by clicking the "pay.sh streamed" tile on /app.
- Mainnet plan: same keypair, but funded by a Squads multisig that signs a monthly top-up. Compromise of the hot key bounds blast radius to the residual budget, never the multisig vault.
- Verification: every
SystemProgram::transferis signed by the treasury keypair, not the agent. Source code:agent/src/paysh.ts.