Brute is a Solana devnet perpetuals trading platform built for a hackathon-style demo. A user connects a wallet, mints devnet BRUTE collateral from the app faucet, deposits collateral into the protocol vault, and opens long or short perpetual positions against Pyth-backed markets.
This repo includes the on-chain Anchor program, Next.js frontend, API routes, Pyth price streaming, BRUTE faucet, Postgres-backed event indexer, TP/SL trigger-order keeper, and an OpenCode-powered AI signal agent.
| Item | Value |
|---|---|
| Product | Brute |
| Network | Solana devnet |
| Program ID | P5cZ4zoxU7XJiKuYyarXgrnXDWjkPSqontfwTm4hrWL |
| BRUTE mint | n5q7mdopFVkQMRH7FP8Y99sDckJi2rd2Yk714DV5eL2 |
| Latest deploy signature | 3B91JH4uMEFXuLe5Npcu2QAcUzNfbmmuvFBz45hgx12Gi8a8n9pC8rDanNKWe69tdnEqqMeUcGSCbDtztPiJN9uc |
| Deploy slot | 466210026 |
- Anchor perps program with protocol config, markets, BRUTE vault custody, user collateral accounts, positions, funding, liquidation, fee accounting, and admin controls.
- Next.js trading app with wallet connect, live ticker, Pyth price cards, market chart, trade ticket, order confirmation, positions table, portfolio, settings, architecture view, and devnet status panel.
- BRUTE faucet and deposit/withdraw flows.
- Pyth Hermes SSE display pricing and on-chain Pyth verified settlement pricing.
- Postgres/Prisma indexer for Anchor trade events.
- Off-chain TP/SL order storage plus keeper execution script.
- AI signal endpoint powered by OpenCode-compatible chat completions, with a deterministic fallback for demos.
The app is configured for devnet markets with Pyth-backed feeds:
XAU/USDGoldXAG/USDSilverEUR/USDEuroAAPL/USDApple equity price feedTSLA/USDTesla equity price feedBTC/USDBitcoinETH/USDEthereumSOL/USDSolana
Market-open state is respected in the UI. When traditional markets are closed or a feed is stale, the app shows the market as closed/stale and the contract freshness checks prevent settlement with old oracle data.
flowchart LR
Wallet["User Wallet"] --> App["Next.js Brute App"]
App --> Hermes["Pyth Hermes SSE"]
App --> Api["Next.js API Routes"]
App --> Program["Anchor Program on Solana Devnet"]
Program --> PythSolana["Pyth Solana Price Account"]
Program --> Vault["BRUTE Token Vault"]
Api --> Db["Postgres / Prisma"]
Api --> OpenCode["OpenCode AI Endpoint"]
Indexer["Event Indexer"] --> Program
Indexer --> Db
Keeper["TP/SL Keeper"] --> Db
Keeper --> Program
Display prices stream from Pyth Hermes so the UI updates without refresh. Settlement uses the on-chain Pyth price account passed into the Anchor instruction, where the program verifies owner, discriminator, feed ID, freshness, confidence, and price normalization before using the value.
- Connect a Solana devnet wallet.
- Use Settings or the trade sidebar faucet to mint devnet
BRUTE. - Deposit
BRUTEinto the protocol vault. - Pick a market and review live oracle price, feed age, confidence, leverage, and estimated liquidation price.
- Open a long or short position.
- Track positions with entry, mark, liquidation price, margin ratio, PnL, and funding.
- Close manually, set TP/SL trigger orders, or let a keeper/liquidator close eligible positions.
- Withdraw free collateral back to the wallet.
The AI signal endpoint is:
POST /api/agent/signal
Content-Type: application/json
{ "marketKey": "BTCUSD" }Implementation file:
app/src/app/api/agent/signal/route.ts
UI location: the agent is in the Trade tab, right sidebar, inside the Brute AI Signal card. It is not in the Portfolio page. Press Analyze and the app sends the selected market to /api/agent/signal.
The endpoint reads recent candles from /api/candles, pulls the current Pyth price, computes lightweight momentum features, and calls:
${LLM_BASE_URL}/chat/completions
using LLM_MODEL. If OPENCODE_API_KEY is missing or the provider is unavailable, the route returns a deterministic fallback signal. Agent responses are currently stateless request/response results and are not stored as chat history in the database.
| Route | Purpose |
|---|---|
GET /api/health |
Devnet status panel data: RPC, Pyth, program ID, BRUTE mint. |
GET /api/architecture |
Architecture data used by the architecture page. |
GET /api/candles |
Historical candle data for charts and AI features. |
GET /api/trades |
Indexed trade events from Postgres, with RPC fallback. |
POST /api/faucet |
Mint devnet BRUTE to the connected wallet. |
GET /api/orders |
List TP/SL trigger orders. |
POST /api/orders |
Create a TP/SL trigger order in Postgres. |
PATCH /api/orders |
Cancel/update trigger order status. |
POST /api/agent/signal |
OpenCode-powered perps signal for the selected market. |
| Instruction | What it does |
|---|---|
initialize |
Creates protocol config and stores authority, BRUTE mint, vault, fee state, insurance state, and pause flag. |
set_paused |
Lets authority pause or unpause trading. |
create_market |
Creates a market PDA with symbol, Pyth feed ID, max leverage, fees, margin, OI, and funding indexes. |
set_market_active |
Enables or disables trading for one market. |
create_user_account |
Creates the user PDA that tracks deposited collateral and reserved collateral. |
deposit_collateral |
Transfers BRUTE from user ATA to protocol vault and credits user collateral. |
withdraw_collateral |
Transfers free BRUTE from vault to user ATA after reserved-collateral checks. |
open_position |
Verifies oracle price, checks leverage and risk limits, charges taker fee, reserves collateral, and creates a position PDA. |
close_position |
Verifies oracle price, realizes PnL/funding, releases collateral, settles user account, and closes the position. |
keeper_close_position |
Devnet helper for off-chain trigger-order execution. Settlement still goes to the owner PDA. |
liquidate |
Closes unhealthy positions, pays liquidation bonus, handles bad debt through insurance accounting, and releases reserve. |
update_funding |
Updates market funding indexes from long/short open interest skew. |
collect_fees |
Moves accrued protocol fees from pending accounting into fee-vault accounting. |
withdraw_fees |
Lets authority withdraw collected protocol fees from vault to a fee receiver token account. |
For the full contract walkthrough, PDA seeds, instruction-level behavior, oracle verification, PnL/funding/liquidation math, Anchor events, indexer behavior, TP/SL keeper flow, and AI signal architecture, see:
All USD-style values use micro units:
MICRO = 1_000_000
$1.00 = 1_000_000
Opening a position:
notional = size_usd
required initial check: collateral_usd * max_leverage >= size_usd
taker_fee = size_usd * taker_fee_bps / 10_000
position_collateral = collateral_usd - taker_fee
PnL:
price_delta = exit_price - entry_price
raw_pnl = price_delta * size_usd / entry_price
long_pnl = raw_pnl
short_pnl = -raw_pnl
Funding:
total_oi = long_open_interest + short_open_interest
skew = long_open_interest - short_open_interest
funding_delta ~= skew / total_oi * max_funding_rate * elapsed / 8h
funding_payment = (current_funding_index - entry_funding_index) * size_usd / FUNDING_SCALE
Liquidation:
effective_collateral = position_collateral + pnl - funding_payment
maintenance_margin = size_usd * maintenance_margin_bps / 10_000
liquidatable = effective_collateral < maintenance_margin
liquidation_bonus = size_usd * 50 / 10_000
Install dependencies:
npm install
npm --prefix app installRun checks:
cargo test
npm --prefix app run typecheck
npm --prefix app run buildRun the frontend:
npm --prefix app run devRun database setup:
npm --prefix app run db:generate
npm --prefix app run db:pushBackfill program events:
npm --prefix app run indexer:backfillRun the TP/SL keeper once:
npm --prefix app run keeper:ordersDeploy the program to devnet:
anchor deploy --provider.cluster devnetCreate app/.env.local for local development and configure these names in Vercel/Railway/Render for deployed services:
NEXT_PUBLIC_SOLANA_RPC_URL=
NEXT_PUBLIC_BRUTE_PROGRAM_ID=
NEXT_PUBLIC_BRUTE_MINT=
NEXT_PUBLIC_PYTH_HERMES_URL=
DATABASE_URL=
POSTGRES_URL=
PRISMA_DATABASE_URL=
FAUCET_AUTHORITY_KEYPAIR=
OPENCODE_API_KEY=
LLM_PROVIDER=opencode
LLM_BASE_URL=https://opencode.ai/zen/v1
LLM_MODEL=kimi-k2.6Do not commit .env, .env.local, private keypairs, or faucet authority secrets.
- Frontend/API routes: Vercel is the easiest free option for the Next.js app.
- Database: Prisma Postgres, Supabase Postgres, Neon, or another hosted Postgres.
- Indexer and keeper: Railway or Render background worker/cron jobs. On a free tier, run them on an interval rather than expecting always-on uptime.
- Program: deployed separately with Anchor/Solana CLI to devnet.
See DEPLOYMENT.md for service-by-service deployment notes.
This is a devnet/hackathon product, not a mainnet-audited protocol. The code includes important safety checks such as PDA seed validation, oracle verification, stale price rejection, confidence checks, fee accounting, market pause controls, max open interest, max skew, max position size, and tests for core math/oracle behavior.
Before mainnet, Brute needs a professional audit, stronger keeper authorization design, durable indexer infrastructure, richer economic simulations, and production-grade monitoring.