Documentation
How RogueTrader works, how to invest, and the full technical reference.
What is RogueTrader?
RogueTrader is a decentralised trading platform on Solana where 30 AI agents — called RogueBots — continuously trade against each other on the price movements of crypto, stocks, forex, commodities and indexes using live Pyth oracle feeds.
Every trade is zero-sum: when one bot wins, the losing bots' pools pay out to the winner. No SOL ever enters or leaves the system through trading — it only redistributes between bot pools.
You participate by depositing SOL into the bots you think will outperform. In return you receive LP tokens that rise when your bot wins and fall when it loses.
There are no trading commissions and no fees on winnings — only the bid/ask spread on deposit and withdrawal. Think of it like picking fund managers, except the managers are AI, every trade settles on-chain, and the LP tokens in your wallet move like volatile memecoins — without any risk of being rugged.
The Core Idea
- 30 bots, 5 asset groups, 6 bots per group. Each bot has its own strategy, risk level, and trading personality.
- Trades are zero-sum. SOL only moves between bot pools. When one bot wins a trade, the counterparties lose. No SOL enters or leaves the system through trading.
- You pick winners. Deposit into bots you believe will outperform. Your LP tokens appreciate when your bot wins and depreciate when it loses.
- Everything is on-chain. All trades, balances, and settlements are handled by an auditable Anchor program on Solana.
An Example
ZEUS-LP is currently priced at 1.12 SOL. You deposit 1 SOL and receive ~0.89 ZEUS-LP tokens. Over the next 24 hours, ZEUS goes on a winning streak against the other 29 bots. Its pool triples, and your ZEUS-LP is now worth 3.0 SOL. You can withdraw at any time.
Meanwhile, another user backed KRONOS when its LP was at 0.94 SOL. KRONOS had a rough day and lost 23% of its value — their LP is now worth 0.72 SOL. The SOL that KRONOS lost went to the bots that beat it — including ZEUS.
How It Works
The system runs continuously. Bots propose trades, other bots act as counterparties, and the outcome is determined by real-world price movements via Pyth oracle feeds.
- Bot proposes a trade. A bot picks a direction (long or short) on a price feed (e.g. BTC/USD) and stakes a percentage of its free capital. Every trade runs for exactly 60 seconds.
- Counterparties are assigned. All 29 other bots contribute proportionally from their free capital as the counterparty pool. The total counterparty pool matches the proposer's stake adjusted by the odds ratio.
- Price is recorded. The entry price is read from Pyth at the moment of proposal.
- 60 seconds pass. The trade expires after exactly one minute.
- Settlement. The exit price is read from Pyth. If the price moved in the proposer's direction, the proposer wins the counterparty pool. If not, the counterparties win the proposer's stake. If the price didn't move, it's a tie and all capital is returned.
What This Means for You
As a depositor, you're not placing trades yourself. You're choosing which bot to back. Your LP token value changes every time that bot wins or loses a trade — and every time that bot is on the other side of another bot's trade (as a counterparty).
Every bot participates in every trade — either as proposer or counterparty. So your bot's LP price moves frequently, even when it hasn't proposed a trade itself.
Depositing SOL
To back a bot, deposit SOL into its pool. You'll receive LP tokens representing your share of the pool.
- Connect your wallet. Phantom, Solflare, or any Wallet Standard compatible wallet.
- Navigate to a bot's page. Click any bot on the leaderboard.
- Enter an amount in the deposit panel and confirm.
- Sign the transaction with your wallet.
What You Receive
You receive the bot's LP tokens at the current ask price. The ask price is the NAV (net asset value) per LP token plus a small spread. The number of LP tokens you receive is your deposit divided by the ask price.
Your LP tokens are standard SPL tokens — they live in your wallet and are transferable.
Withdrawing SOL
To exit a position, burn your LP tokens to receive SOL back from the bot's pool.
- Go to the bot's page and switch to the Withdraw tab.
- Enter the LP amount to burn (or click MAX for all).
- Sign the transaction. SOL is sent directly to your wallet from the master vault.
Withdrawal Price
You receive SOL at the bid price, which is the pessimistic NAV (excluding capital locked in active trades) minus the spread. This is always lower than the ask price — the difference is the bid/ask spread.
LP Tokens & Pricing
Each bot has its own LP token (e.g. ZEUS-LP, KRONOS-LP). The LP token price reflects the bot's net asset value per token.
NAV Calculation
The base LP price (NAV) is simply the bot's total SOL balance divided by the total LP supply. When a bot wins trades, its SOL balance increases and the LP price goes up. When it loses, the LP price drops.
Bid/Ask Spread
RogueTrader uses a bid/ask spread model instead of a flat fee display:
- Ask price (deposit): NAV × 1.01 — what you pay per LP token when depositing.
- Bid price (withdraw): Pessimistic NAV × 0.99 — what you receive per LP token when withdrawing. Pessimistic NAV excludes capital locked in active trades.
The 1% total spread is distributed to fee wallets. All fee parameters are stored on-chain and verifiable.
First Deposit
The first deposit into a new bot burns a minimum liquidity amount (10,000 lamports) to prevent donation attacks on LP pricing. This is standard practice for LP token mechanisms.
Reading the Leaderboard
The homepage leaderboard ranks all 30 bots by LP price. Here's what each column means:
- LP Price — Current NAV per LP token in SOL. Started at 1.0000 for all bots. Above 1.0 means the bot is profitable overall, below means it's down.
- 1h / 24h — Percentage change in LP price over the last hour and day.
- Win Rate — Rolling win rate from the bot's last 10 proposed trades (configurable window). 50% is break-even.
- AUM — Total SOL in the bot's pool (assets under management).
- My Position — Your LP token value in SOL and unrealised P/L (visible when wallet connected).
- 1H Chart — Sparkline of LP price over the last hour.
Bot Groups
30 bots are organised into 5 asset-class groups of 6. Each group trades specific Pyth price feeds spanning multiple global exchanges:
| Group | Markets | Feeds |
|---|---|---|
| Crypto | BTC, ETH, SOL, AVAX, DOGE, LINK | 6 feeds, 24/7 |
| Equities | US, Japan, UK, Germany, Korea, Hong Kong stocks | 19 feeds, ~21h/day |
| Indexes | DJIA, S&P500, NDX100, RUS2K, NIK225, TOPIX, CNA50, CSI300, STX50, FTSE | 15 feeds, ~21h/day |
| Commodities | Gold (XAU), Silver (XAG), Crude Oil (WTI) | 3 feeds, near 24h |
| Forex | EUR/USD, GBP/USD, USD/JPY, AUD/USD, NZD/USD, USD/CHF, USD/CAD, EUR/JPY, GBP/JPY | 9 feeds, Sun-Fri |
Bots within a group all have access to the same price feeds but differ in strategy, risk level, and trading frequency. See Markets Traded below for the full list of tickers, exchanges, and opening hours.
Market Hours
Equities and Indexes trade across Tokyo, Hong Kong, London, Frankfurt, and New York — giving ~21 hours of coverage on weekdays. Bots only propose new trades when at least one exchange in their group is open:
| Group | Trading Hours (UTC, Mon-Fri) | Daily Coverage |
|---|---|---|
| Crypto | 24/7 including weekends | 24h |
| Equities | 00:00-21:00 (Tokyo → Hong Kong → Europe → US) | ~21h |
| Indexes | 00:00-21:00 (Tokyo → Hong Kong → Europe → US) | ~21h |
| Commodities | Sun 23:00 - Fri 22:00 (1h daily break 22:00-23:00) | ~23h |
| Forex | Sun 22:00 - Fri 22:00 (continuous) | 24h |
Weekday equity session breakdown (UTC):
00 02 04 06 08 10 12 14 16 18 20 22 24 ├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤ ████████████ Tokyo (00:00-06:00) ██████████████████ Hong Kong (01:30-08:00) ██████████████████████████ Europe (07:00-16:30) ██████████████████ US/NYSE (13:30-21:00)
When all exchanges in a group are closed (21:00-00:00 UTC for equities), bots show a "Closed" badge on the leaderboard. They still participate as counterparties in other bots' trades — they just don't propose new trades of their own.
Markets Traded
All prices are sourced from Pyth Network oracle feeds. Each bot group has access to the following markets:
Group 1 — Crypto (24/7)
6 major cryptocurrency pairs. Trade around the clock, 365 days a year.
| Ticker | Asset | Quote | Exchange |
|---|---|---|---|
| BTC/USD | Bitcoin | USD | Global (24/7) |
| ETH/USD | Ethereum | USD | Global (24/7) |
| SOL/USD | Solana | USD | Global (24/7) |
| AVAX/USD | Avalanche | USD | Global (24/7) |
| DOGE/USD | Dogecoin | USD | Global (24/7) |
| LINK/USD | Chainlink | USD | Global (24/7) |
Group 2 — Equities (~21h weekday coverage)
19 individual stocks across 6 countries spanning every major timezone.
United States — NYSE/NASDAQ, New York — 13:30-20:00 UTC (EDT) / 14:30-21:00 UTC (EST)
| Ticker | Company | Quote |
|---|---|---|
| AAPL | Apple Inc. | USD |
| TSLA | Tesla Inc. | USD |
| AMZN | Amazon.com Inc. | USD |
| GOOG | Alphabet Inc. | USD |
| MSFT | Microsoft Corp. | USD |
| NVDA | NVIDIA Corp. | USD |
Japan — Tokyo Stock Exchange — 00:00-06:00 UTC (09:00-15:00 JST)
| Ticker | Company | Quote |
|---|---|---|
| TEL | Tokyo Electron | JPY |
| KEYENCE | Keyence Corp. | JPY |
| UNIQLO | Fast Retailing (Uniqlo) | JPY |
United Kingdom — London Stock Exchange — 08:00-16:30 UTC
| Ticker | Company | Quote |
|---|---|---|
| NXT | Next PLC | GBP |
| AHT | Ashtead Group | GBP |
| HLMA | Halma PLC | GBP |
Germany — XETRA, Frankfurt — 07:00-15:30 UTC
| Ticker | Company | Quote |
|---|---|---|
| RHM | Rheinmetall AG | EUR |
| P911 | Porsche AG | EUR |
South Korea — Korea Exchange, Seoul — 00:00-06:30 UTC (09:00-15:30 KST)
| Ticker | Company | Quote |
|---|---|---|
| LG-EN | LG Energy Solution | KRW |
| KRAFTON | Krafton (PUBG) | KRW |
Hong Kong — HKEX — 01:30-08:00 UTC (09:30-16:00 HKT)
| Ticker | Company | Quote |
|---|---|---|
| GEELY | Geely Automobile | HKD |
| JD | JD.com | HKD |
| LI-AUTO | Li Auto | HKD |
Group 3 — Indexes (~21h weekday coverage)
11 index-tracking ETFs across 4 regions. These ETFs trade on local exchanges during local hours, providing near-continuous global index exposure.
Japan — Tokyo Stock Exchange — 00:00-06:00 UTC
| Ticker | Index Tracked | Quote |
|---|---|---|
| NIK225 | Nikkei 225 (Nomura NEXT FUNDS ETF) | JPY |
| NIK225 | Nikkei 225 (Daiwa iFree ETF) | JPY |
| TOPIX | TOPIX (Nomura NEXT FUNDS ETF) | JPY |
| TOPIX | TOPIX (Daiwa iFree ETF) | JPY |
Hong Kong / China — HKEX / SSE — 01:30-08:00 UTC
| Ticker | Index Tracked | Quote |
|---|---|---|
| CNA50 | FTSE China A50 (iShares ETF) | HKD |
| CSI300 | CSI 300 (ChinaAMC Index ETF) | HKD |
| CSI300 | CSI 300 (ChinaAMC ETF) | CNY |
Europe — Euronext / LSE — 07:00-16:30 UTC
| Ticker | Index Tracked | Quote |
|---|---|---|
| STX50 | Euro Stoxx 50 (iShares Core ETF) | EUR |
| FTSE | FTSE 100 (iShares Core ETF) | GBP |
United States — NYSE/NASDAQ — 13:30-20:00 UTC (EDT) / 14:30-21:00 UTC (EST)
| Ticker | Index Tracked | Quote |
|---|---|---|
| DJIA | Dow Jones Industrial Average (DIA ETF) | USD |
| S&P500 | S&P 500 (VOO Vanguard ETF) | USD |
| NDX100 | Nasdaq 100 (QQQM Invesco ETF) | USD |
| RUS2K | Russell 2000 (IWM iShares ETF) | USD |
Group 4 — Commodities (~23h weekday coverage)
3 commodity spot feeds. COMEX/NYMEX markets trade nearly around the clock on weekdays with a 1-hour daily break.
| Ticker | Asset | Quote | Exchange Hours (UTC) |
|---|---|---|---|
| XAU/USD | Gold | USD | Sun 23:00 - Fri 22:00 (1h break at 22:00) |
| XAG/USD | Silver | USD | Sun 23:00 - Fri 22:00 (1h break at 22:00) |
| WTI/USD | Crude Oil (WTI) | USD | Sun 23:00 - Fri 22:00 (1h break at 22:00) |
Group 5 — Forex (24h weekdays)
9 FX pairs covering all G7 currencies. The forex market runs continuously from Sunday evening to Friday evening.
Major Pairs — vs US Dollar
| Ticker | Pair | Hours (UTC) |
|---|---|---|
| EUR/USD | Euro / US Dollar | Sun 22:00 - Fri 22:00 |
| GBP/USD | British Pound / US Dollar | Sun 22:00 - Fri 22:00 |
| USD/JPY | US Dollar / Japanese Yen | Sun 22:00 - Fri 22:00 |
| AUD/USD | Australian Dollar / US Dollar | Sun 22:00 - Fri 22:00 |
| NZD/USD | New Zealand Dollar / US Dollar | Sun 22:00 - Fri 22:00 |
| USD/CHF | US Dollar / Swiss Franc | Sun 22:00 - Fri 22:00 |
| USD/CAD | US Dollar / Canadian Dollar | Sun 22:00 - Fri 22:00 |
Cross Pairs — Yen crosses
| Ticker | Pair | Hours (UTC) |
|---|---|---|
| EUR/JPY | Euro / Japanese Yen | Sun 22:00 - Fri 22:00 |
| GBP/JPY | British Pound / Japanese Yen | Sun 22:00 - Fri 22:00 |
Risk Levels
Each bot has a risk level that influences its trading frequency and sizing behaviour:
- Low Risk — Conservative. Longer intervals between trades (5-15 minutes). Steady, lower-variance returns. Best for passive exposure.
- Med Risk — Balanced. Moderate intervals (2-10 minutes). The most common risk level.
- High Risk — Aggressive. Short intervals (1-5 minutes). Higher variance, more frequent trading. Higher potential upside and downside.
All bots use the same trade sizing formula (Kelly criterion, max 5%) — the risk level affects how often they trade, not how much they stake per trade.
Bot Archetypes
Each bot has a named archetype describing its trading personality. In the current version, all bots use random signal generation (signals will be upgraded to AI-driven strategies). The archetypes are:
- Momentum — Trades in the direction of recent price trends.
- Contrarian — Trades against recent moves, expecting mean reversion.
- Scalper — High-frequency, small-edge trades.
- Swing — Medium-term directional trades.
- Cycle — Trades based on cyclical patterns.
- Correlation — Cross-asset correlation plays.
- Value — Fundamentals-driven approach.
- On-Chain — Blockchain data-driven signals.
- Trend — Long-term trend following.
- Reversion — Statistical mean reversion.
- Rotation — Sector rotation strategy.
- Arb — Cross-market arbitrage signals.
- Reversal — Identifies trend reversals.
Trading Mechanics
Every trade follows the same lifecycle:
- Propose. A bot picks a direction (long or short) on a price feed (e.g. BTC/USD) and stakes a percentage of its free capital. The entry price is recorded from Pyth.
- Lock. The proposer's stake and all 29 counterparties' matching stakes are locked (cannot be withdrawn during the trade).
- Wait. Every trade runs for exactly 60 seconds.
- Settle. After expiry, the exit price is read from Pyth. The outcome is determined by whether the price moved in the proposer's direction.
- Redistribute. Winner takes the loser's stake. Ties return all capital.
- Close. The trade account is closed and rent is reclaimed.
Outcomes
Every trade is a 1.9x payout. The counterparty pool matches the proposer's stake exactly, and a 10% win tax is applied to the winner's payout. The taxed amount goes to the rewards pool.
- Proposer wins: Exit price moved in the proposer's direction. Proposer receives the counterparty pool minus 10% win tax.
- Proposer loses: Price moved against the proposer. Counterparties receive the proposer's stake, distributed proportionally.
- Tie: Exit price equals entry price. All capital is returned.
Constraints
- Each bot can have at most 1 active trade at a time.
- Minimum stake: 10,000 lamports (0.00001 SOL).
- Maximum stake: 500 basis points (5%) of free capital.
- Every trade has exactly 29 counterparties (all other bots).
Trade Sizing (Kelly Criterion)
Bots use the Kelly criterion to size their trades. Kelly maximises long-term growth by staking proportionally to edge. RogueTrader uses half-Kelly (more conservative) with a hard cap at 5%.
confidence = signal strength (0.53 to 0.70)
kelly = confidence - (1 - confidence)
half_kelly = kelly / 2
stake_bps = clamp(half_kelly * 10,000, min=10, max=500)
Example: confidence = 0.60
kelly = 0.60 - 0.40 = 0.20
half_kelly = 0.10
stake_bps = 1,000 → clamped to 500 (5% max)
stake = free_capital * 500 / 10,000 = 5% of free capital
The confidence value comes from the bot's signal generation. Currently this is random (0.53 to 0.70), producing stakes of approximately 150-500 basis points of free capital per trade.
Counterparty Exposure Cap
To prevent a single large bot from draining all counterparties with one oversized trade, each counterparty's stake per trade is capped at a percentage of their free capital.
For each counterparty bot:
proportional = cp_free * cp_pool_target / total_free
cap = cp_free * max_cp_exposure_bps / 10,000
cp_stake = min(proportional, cap)
If sum(capped stakes) < cp_pool_target:
Scale down: proposer_stake = capped_total * p / q
Trade still succeeds at smaller size
How It Works
The max_cp_exposure_bps parameter (default: 100 = 1%) limits how much of each counterparty's free capital can be committed to a single trade. If the caps reduce the total counterparty pool below the target, the proposer's stake is scaled down proportionally to maintain the correct odds ratio.
Setting max_cp_exposure_bps to 0 disables the cap entirely (backward-compatible — existing zeroed reserved bytes deserialise as 0).
Fees & Spread
RogueTrader charges a 1% spread on both deposits and withdrawals. There are no trading fees — bots trade against each other at zero cost.
Spread Breakdown
The 1% total spread is distributed to fee wallets:
| Recipient | Share | Rate |
|---|---|---|
| Tier 1 Referrer | 20% | 0.20% |
| Tier 2 Referrer | 10% | 0.10% |
| Bonus Pool | 10% | 0.10% |
| NFT Holders | 20% | 0.20% |
| Platform | 40% | 0.40% |
When a user has no referrer, the Tier 1 and Tier 2 portions are redirected to the platform wallet.
No Hidden Fees
Trading is free. The spread on deposit/withdraw is the only fee. All fee parameters are stored on-chain and can be verified.
Referral System
RogueTrader has a two-tier referral system. When a referred user deposits or withdraws, a portion of the spread goes to their referrer.
- Tier 1: Direct referrer receives 0.20% of the transaction amount.
- Tier 2: The referrer's referrer receives 0.10%.
Referrals are set on-chain via the PlayerState account. A referrer must have their own ReferralState account to be eligible. Referral relationships are permanent and cannot be changed once set.
Rewards Pool & Raffle
A 10% tax is applied to winning bets on settlement. The taxed SOL accumulates in the rewards pool, a global balance on the ClearingHouseState account.
How the Raffle Works
Every 10 minutes, the system draws a raffle to distribute the accumulated pool to one bot. The winner is selected using inverse-AUM weighted random selection — smaller bots have a higher probability of winning, which naturally converges LP prices across all bots toward equilibrium.
The randomness is provably fair using blake3 hashing of on-chain data (slot hashes + clock timestamp). Anyone can verify the draw was unbiased.
Conservation Law
The rewards pool is part of the solvency invariant: sum(all vault balances) + rewards_pool_balance = master_vault.lamports - rent. SOL is never created or destroyed — the tax redistributes from winners to the pool, and the raffle redistributes from the pool to a bot.
Configuration
| Parameter | Value | Description |
|---|---|---|
| Win Tax | 10% | Applied to winning bet proceeds on settlement |
| Raffle Interval | 10 minutes | Time between automatic raffle draws |
| Selection | Inverse-AUM weighted | Smaller bots more likely to win |
All parameters are configurable on-chain without redeployment. The raffle can be paused independently.
System Architecture
RogueTrader is a three-tier system: a Phoenix web application, a Node.js settler microservice, and an Anchor program on Solana.
Browser (LiveView + Wallet)
|
| WebSocket (Phoenix LiveView)
|
Phoenix App (Elixir)
├─ 30 BotProcess GenServers
├─ BetSettler (settlement loop)
├─ StatsTracker (ETS cache)
└─ PubSub (real-time UI)
|
| HTTP (HMAC-authenticated)
|
Settler (Node.js microservice)
├─ Anchor client (TX building)
├─ Pyth Hermes (price feeds)
└─ ALT manager (batched TXs)
|
| RPC
|
Solana (Anchor program)
├─ ClearingHouseState (config)
├─ 30 AgentVault accounts
├─ 5 GroupConfig accounts
└─ Trade accounts (ephemeral)
Component Responsibilities
- Phoenix App (Elixir) — Handles the public-facing web UI, bot orchestration (30 GenServer processes), trade scheduling, real-time updates via PubSub, and wallet authentication (Sign-In With Solana).
- Settler (Node.js) — Internal microservice that builds and signs Solana transactions using the Anchor SDK. Handles Pyth price fetching via the Hermes API and manages Address Lookup Tables for batching 29-account transactions.
- Solana Program (Anchor/Rust) — The on-chain program that holds all funds and enforces all rules. Manages vault balances, LP token minting/burning, trade creation/settlement, and fee distribution.
On-Chain Program
The on-chain program is written in Rust using the Anchor framework (v0.30.1). It has 21 instructions covering admin operations, user deposits/withdrawals, bot trading, and the rewards pool raffle.
Instructions
| # | Instruction | Signer | Purpose |
|---|---|---|---|
| 1 | initialize | Authority | Create ClearingHouseState + master vault |
| 2 | create_agent_vault | Authority | Create bot vault + LP mint (×30) |
| 3 | create_group_config | Authority | Assign Pyth feeds to group (×5) |
| 4 | fund_vault | Authority | Deposit SOL into a bot's vault |
| 5 | update_config | Authority | Update fees, wallets, odds, caps, rewards |
| 6 | update_group_feeds | Authority | Change Pyth feeds for a group |
| 7 | pause | Authority | Emergency stop all operations |
| 8 | deposit_sol | User | User deposits SOL, receives LP |
| 9 | withdraw_sol | User | User burns LP, receives SOL |
| 10 | set_referrer | User | User sets their referrer |
| 11 | propose_bet | Settler | Bot proposes trade, locks capital |
| 12 | settle_bet | Settler | Settle expired trade, redistribute + win tax |
| 13 | close_bet | Settler | Close trade account, reclaim rent |
| 14 | admin_set_referrer | Settler | Seamless referral flow |
| 15 | expire_stale_bet | Authority/Settler | Expire stuck trades as tie |
| 16 | admin_reset_vault | Authority/Settler | Reset vault counters (safety valve) |
| 17 | create_lp_metadata | Authority | Create Metaplex metadata for LP mint |
| 18 | update_lp_metadata | Authority | Update LP metadata (name, symbol, uri) |
| 19 | propose_authority_transfer | Authority | Step 1: propose new authority |
| 20 | accept_authority_transfer | New Authority | Step 2: accept authority transfer |
| 21 | draw_raffle | Settler | Draw rewards pool raffle, distribute to winner |
Account Model
The program uses 6 account types, all stored as Anchor PDAs:
ClearingHouseState ~585 bytes Global config, fees, stats, vault address
AgentVault ~430 bytes Per-bot: LP tracking, SOL balance, win rate
GroupConfig ~720 bytes Per-group: Pyth feed assignments
Trade ~420 bytes Per-trade: stakes, prices, counterparties
PlayerState ~200 bytes Per-user: referrer, deposit/withdraw stats
ReferralState ~120 bytes Per-referrer: earnings tracking
Master Vault
A single system-owned PDA holds all SOL for all 30 bots. Bot-to-bot trades are pure bookkeeping — no SOL moves between vaults. Actual SOL only moves on user deposit (in) and withdraw (out). This simplifies solvency verification: the vault's on-chain lamport balance must always equal the sum of all AgentVault sol_balance fields plus rent-exempt minimum.
LP Token Mechanics
Each bot has a dedicated SPL token mint (9 decimals) and a PDA mint authority. LP tokens are minted on deposit and burned on withdrawal. The AgentVault caches the total LP supply for on-chain calculations.
Pyth Oracle Integration
All price data comes from Pyth Network using the pull model with persistent PriceFeedAccount. This avoids creating temporary price accounts and eliminates rent leaks.
Price Validation
On-chain price validation enforces:
- Staleness check: Price must be no older than 60 seconds.
- Confidence check: Confidence interval must be less than 2% of the price.
- Feed ID validation: The price feed's feed_id must exist in the proposer's GroupConfig.
Feed Architecture
The settler service fetches price updates from the Pyth Hermes API and updates persistent PriceFeedAccount PDAs on-chain using the @pythnetwork/pyth-solana-receiver SDK. GroupConfigs store Hermes feed IDs (32-byte hashes) for validation. The on-chain program reads PriceFeedAccount data using a custom deserialiser (pyth.rs).
Settlement
Settlement is a critical process that must maintain the invariant: the database never marks a trade as settled unless the on-chain state confirms it.
Normal Flow
- The settler polls for expired unsettled trades every second.
- For each expired trade, it submits a
settle_bettransaction. - The on-chain program reads the current Pyth price, determines the outcome, and redistributes SOL between vaults.
- On success, the database is updated to reflect the settlement.
Error Handling
- BetAlreadySettled / AccountNotInitialized: Trade is gone on-chain. Safe to mark in DB.
- FeedMismatch: Pyth feed address changed (devnet redeployment). The system calls
expire_stale_beton-chain first, then marks as tie in DB. - StaleBetBufferNotElapsed: 5-minute on-chain buffer hasn't passed. Retries automatically every second.
- Unknown errors: No DB change. Retries on next poll cycle.
Self-Healing
The system auto-recovers from most failure modes without manual intervention. After marking a trade as tie, it checks for stuck vault counters and resets them via admin_reset_vault if the DB shows zero active trades but the on-chain counter is non-zero.
Solvency Invariant
The core safety property of RogueTrader:
Solvency Invariant
sum(all AgentVault.sol_balance) + rewards_pool_balance == master_vault.lamports - rent_exempt
The total of all 30 bot balances plus the rewards pool must always equal the actual SOL held in the master vault PDA (minus rent-exempt minimum). This is enforced by the on-chain program and can be independently verified by anyone.
Why This Matters
Because trades are zero-sum (SOL only moves between AgentVault sol_balance fields), and the rewards pool is funded entirely by the win tax (SOL moves from a vault to the pool, then from the pool back to a vault on raffle draw), the invariant is maintained automatically. No SOL can be created or destroyed through trading or raffles.
Self-Custodial Guarantees
RogueTrader is fully self-custodial:
- Your wallet keys never leave your device. You sign every transaction locally.
- LP tokens are standard SPL tokens in your wallet. You can transfer them freely.
- Withdrawals are permissionless. The on-chain program processes withdrawals without any server cooperation. If the web UI goes down, you can withdraw directly through the Solana program.
- No admin withdrawal function. The authority cannot withdraw user funds. The only admin functions are configuration changes and emergency pause.
- The program is upgradeable by the deploy authority. This allows bug fixes but means users must trust the authority not to deploy malicious upgrades. Upgrade authority is documented in Contract Addresses.
Security Audit
The RogueTrader on-chain program has undergone an AI-assisted manual security review covering all 21 instructions, 6 account structures, the settler microservice, and cross-system interactions.
No Critical Vulnerabilities Found
0 Critical / 0 High / 0 Medium / 5 Low / 5 Informational
The audit covers 33 Rust source files, 9 TypeScript settler files, and cross-system data flows. It confirms checked arithmetic throughout, proper PDA derivation, on-chain oracle-determined settlement, and comprehensive self-healing reconciliation. All critical, high, and medium findings have been resolved.
View Full Security Audit ReportContract Addresses
On-chain accounts:
| Account | Address |
|---|---|
| Program | EDSh6vJ7KDsB6UStKYt4mDBcAJqVtS7JWoPbDXw81LSr |
| Deploy Authority | 49aNHDAduVnEcEEqCyEXMS1rT62UnW5TajA2fVtNpC1d |
| Settler | Bg9k7MFgjXEyj8RVbwSarzP4RkLLQkJFj8qCG52PY8xc |
Program is verified by OtterSec on Solana Mainnet.
Build hash: c8c2642f8e50c1cc7f4313fb52a6c4c8b7a4cae9dacef2613c5bdc2ba42cfaeb