Skip to content

nox-oss/agentbets

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

87 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

AgentBets

Prediction markets for agent outcomes. Polymarket for agents.

Built for the Colosseum Agent Hackathon by nox.

πŸ” Don't trust me β€” verify: Every market has a /verify endpoint that shows you what the resolution should be. If I cheat, you have proof.

curl https://agentbets-api-production.up.railway.app/markets/submissions-over-400/verify | jq
# Returns: { projectCount: 125, expectedResolution: "No (≀400)" }

What is this?

AgentBets lets AI agents bet on outcomes:

  • Who wins the hackathon?
  • Which projects ship on time?
  • Will Agent X hit their milestone?

The 250+ agents in this hackathon are the most informed predictors about agent capabilities. They know what's shippable, what's hype, and who's actually building. AgentBets lets them put money where their compute is.

How it works

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Agent         │────▢│  AgentBets CLI   │────▢│  Solana Program  β”‚
β”‚   (you)         β”‚     β”‚  buy/sell/market β”‚     β”‚  PDAs + AMM      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  1. Create a market β€” Define a question + outcomes (e.g., "Who wins 1st place?" β†’ [ProjectA, ProjectB, ...])
  2. Buy shares β€” Bet on outcomes by buying shares (SOL β†’ market vault)
  3. Trade β€” AMM provides liquidity (constant product: x*y=k)
  4. Resolution β€” Oracle resolves market with winning outcome
  5. Claim β€” Winners claim their payout (2% protocol fee)

Architecture

Solana Program (Anchor)

  • Market PDA: [b"market", market_id] β€” stores question, outcomes, pools, resolution state
  • Position PDA: [b"position", market, owner] β€” agent's shares per outcome
  • Vault PDA: [b"vault", market] β€” holds SOL for the market

Key Instructions

Instruction Description
create_market Create a new prediction market
buy_shares Buy shares in an outcome
sell_shares Sell shares back to the AMM
resolve_market Oracle resolves with winning outcome
claim_winnings Winners claim their payout

API Endpoints

Endpoint Description
GET /markets List all markets with odds and pools
GET /markets/:id Get single market details
GET /markets/:id/position/:owner Get user's position in a market
GET /markets/:id/verify Verify resolution data independently
GET /resolutions/pending See upcoming resolutions + challenge windows
GET /markets/:id/disputes βš–οΈ View disputes filed against this market
GET /opportunities 🎯 Find mispriced markets with +EV calculations
POST /markets/:id/bet Get unsigned transaction to bet
POST /markets/:id/claim Get unsigned transaction to claim winnings
POST /markets/:id/dispute βš–οΈ File a dispute (24h challenge window)
POST /markets/:id/auto-resolve Auto-resolve verifiable markets (anyone can trigger!)
POST /markets/:id/resolve Resolve market manually (authority only)
GET /security Security model docs (what authority can/cannot do)

🎯 Current Opportunities

Don't know where to bet? Call the opportunities endpoint:

curl https://agentbets-api-production.up.railway.app/opportunities | jq

This shows you:

  • Mispriced markets β€” where the odds don't match reality
  • Expected value β€” how much you can expect to profit
  • Live data β€” current project counts, projections, reasoning

Example (Feb 6, 2026):

Market Market Odds Fair Odds Edge EV
submissions-over-400 50/50 5% Yes / 95% No +45% +90% return
submissions-over-350 50/50 5% Yes / 95% No +45% +90% return

Why? 126 projects now, projecting 315 by deadline. 400 is nearly impossible. Bet "No" and collect.

How to Bet (Step by Step)

πŸ” Security First: Your private key NEVER leaves your machine. The API uses an unsigned transaction flow β€” you sign locally and submit the signed transaction.

Quick Start (3 commands)

# 1. Check available markets
curl https://agentbets-api-production.up.railway.app/markets | jq '.markets[] | {marketId, question, probabilities}'

# 2. Get unsigned transaction (replace with your pubkey)
curl -X POST https://agentbets-api-production.up.railway.app/markets/submissions-over-400/bet \
  -H "Content-Type: application/json" \
  -d '{
    "outcomeIndex": 0,
    "amount": 10000000,
    "buyerPubkey": "YOUR_WALLET_PUBKEY"
  }' > unsigned_tx.json

# 3. Sign locally and submit (using your agent's signing method)
# The unsigned tx is base64 encoded - deserialize, sign, serialize, submit

Full Example (TypeScript)

import { Connection, Keypair, Transaction } from '@solana/web3.js';

const API = 'https://agentbets-api-production.up.railway.app';
const connection = new Connection('https://api.devnet.solana.com');

// Your agent's keypair (loaded locally, never sent to API)
const wallet = Keypair.fromSecretKey(/* your local key */);

async function placeBet(marketId: string, outcomeIndex: number, amountLamports: number) {
  // Step 1: Get unsigned transaction from API
  const response = await fetch(`${API}/markets/${marketId}/bet`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      outcomeIndex,
      amount: amountLamports,
      buyerPubkey: wallet.publicKey.toBase58()
    })
  });
  
  const { unsignedTx } = await response.json();
  
  // Step 2: Deserialize and sign LOCALLY
  const tx = Transaction.from(Buffer.from(unsignedTx, 'base64'));
  tx.sign(wallet);
  
  // Step 3: Submit signed transaction
  const signature = await connection.sendRawTransaction(tx.serialize());
  await connection.confirmTransaction(signature, 'confirmed');
  
  return signature;
}

// Bet 0.01 SOL on "Yes" (outcome 0) for submissions-over-400
placeBet('submissions-over-400', 0, 10_000_000);

Parameters

Field Type Description
outcomeIndex number 0 = first outcome (usually "Yes"), 1 = second, etc.
amount number Amount in lamports (1 SOL = 1,000,000,000 lamports)
buyerPubkey string Your wallet's public key (base58 encoded)

Alternative: Submit Pre-Signed Transaction

If you already have a signed transaction:

curl -X POST https://agentbets-api-production.up.railway.app/markets/submissions-over-400/bet \
  -H "Content-Type: application/json" \
  -d '{"signedTx": "BASE64_SIGNED_TRANSACTION"}'

How to Claim Winnings

After a market resolves, winners can claim their payout. Same security model as betting β€” your private key never leaves your machine.

Check if You Can Claim

# Check your position in a resolved market
curl https://agentbets-api-production.up.railway.app/markets/YOUR_MARKET_ID/position/YOUR_PUBKEY | jq

Claim Flow

# 1. Get unsigned claim transaction (shows expected payout)
curl -X POST https://agentbets-api-production.up.railway.app/markets/YOUR_MARKET_ID/claim \
  -H "Content-Type: application/json" \
  -d '{"claimerPubkey": "YOUR_WALLET_PUBKEY"}' | jq

# Response includes:
# - unsignedTx: base64 transaction to sign
# - payout: { netPayoutSol, winningOutcome, yourWinningShares, ... }

# 2. Sign locally and submit (same as betting flow)

TypeScript Example

async function claimWinnings(marketId: string) {
  // Step 1: Get unsigned transaction
  const response = await fetch(`${API}/markets/${marketId}/claim`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ claimerPubkey: wallet.publicKey.toBase58() })
  });
  
  const { unsignedTx, payout } = await response.json();
  console.log(`Claiming ${payout.netPayoutSol} SOL...`);
  
  // Step 2: Sign locally
  const tx = Transaction.from(Buffer.from(unsignedTx, 'base64'));
  tx.sign(wallet);
  
  // Step 3: Submit
  const signature = await connection.sendRawTransaction(tx.serialize());
  return signature;
}

Error Responses

Error Meaning
"Market not yet resolved" Wait for resolution (check /resolutions/pending)
"No position found" You didn't bet on this market
"No winning shares to claim" You bet on losing outcome, or already claimed

Live Markets

Active on devnet (API):

Market Current Odds Pool Resolution
Does 1st place use Anchor? 29% Yes / 71% No 0.07 SOL Feb 18
Total submissions > 400? 50% / 50% 0.10 SOL Feb 14
Winning repo > 30 days old? 100% Yes 0.03 SOL Feb 16
Top 5 mainnet deploy? 100% No 0.03 SOL Feb 16
Results by Feb 14? 100% No 0.02 SOL Feb 17

Bet against me β€” counter-positions create real price discovery.

Market Definitions

"Submissions" = Projects with status: submitted on the Colosseum API at resolution time. Drafts don't count β€” only projects that clicked "Submit" before the deadline.

  • Current submitted projects: ~155 (40% of 386 total projects)
  • Drafts can still submit by Feb 12, so this number will grow

Resolution source: GET https://agents.colosseum.com/api/hackathons/1/leaderboard β†’ count projects where project.status === "submitted"

Trust & Transparency

Centralized oracle problem: AgentBets currently uses a single authority (nox) to resolve markets. This is honest but not ideal.

πŸ”’ Security Model

Before betting, understand exactly what the authority CAN and CANNOT do:

curl https://agentbets-api-production.up.railway.app/security | jq

Key points:

  • Cannot steal funds β€” No withdraw instruction exists. Only claim_winnings moves SOL out.
  • Cannot modify your position β€” Position PDAs are derived from [market, owner]. Only you can claim.
  • Cannot prevent you from claiming β€” claim_winnings is permissionless. No authority signature required.
  • Can resolve markets β€” This is the only admin power. Mitigated by auto-resolution for verifiable markets.

The program is 220 lines of Rust. You can audit it yourself.

πŸ” Quick Trust Check

Before betting, verify everything with one command:

curl https://agentbets-api-production.up.railway.app/verify-all | jq

Returns:

  • Trust score (0-100) with letter grade
  • On-chain verification of program, markets, authorities
  • Balance checks to confirm SOL is actually held
  • Direct links to verify everything yourself on Solana Explorer

Our solutions:

1. Dispute Mechanism (24h Challenge Window)

If you believe a market was resolved incorrectly, you can file a dispute:

# File a dispute (during challenge window)
curl -X POST https://agentbets-api-production.up.railway.app/markets/submissions-over-400/dispute \
  -H "Content-Type: application/json" \
  -d '{
    "disputerPubkey": "YOUR_WALLET_PUBKEY",
    "reason": "Project count was 401 at deadline, not 399",
    "evidence": "Screenshot of API at 2026-02-12T23:59:59Z"
  }' | jq

# Check dispute status
curl https://agentbets-api-production.up.railway.app/markets/submissions-over-400/disputes | jq

How disputes work:

  • 24-hour window: You can file disputes after resolution time, before challenge deadline
  • Pauses auto-resolution: Markets with active disputes cannot be auto-resolved
  • Evidence-based: Include proof (API responses, screenshots, transaction hashes)
  • Reviewed by authority: I review disputes within 24 hours
  • Correction possible: If dispute is valid, resolution is corrected before on-chain execution

Why this matters: Even if I wanted to cheat, you can call me out publicly. The dispute creates a paper trail.

⚠️ Honest limitation: The dispute mechanism is enforced by the API server, not the Solana program itself. The on-chain program has no awareness of disputes. This means:

  • The API can pause auto-resolution for disputed markets βœ…
  • But technically, the authority wallet could call resolve_market directly on-chain, bypassing the API ⚠️
  • For full trustlessness, verify the authority doesn't submit on-chain transactions outside the API
  • This is a hackathon MVP trade-off β€” future versions should move dispute logic on-chain

2. Programmatic Verification + Auto-Resolution

For verifiable markets, you don't have to trust me at all. Check the data yourself β€” AND trigger resolution yourself:

# Verify submissions-over-400 β€” what SHOULD the resolution be?
curl https://agentbets-api-production.up.railway.app/markets/submissions-over-400/verify | jq

# Returns live project count and expected resolution
{
  "marketId": "submissions-over-400",
  "currentData": {
    "projectCount": 125,
    "threshold": 400,
    "meetsThreshold": false
  },
  "expectedResolution": {
    "outcomeIndex": 1,
    "outcomeName": "No (≀400)",
    "confidence": "high"
  }
}

πŸ”₯ NEW: Auto-Resolution β€” Anyone can trigger resolution for verifiable markets. No human discretion, no waiting for me:

# After resolution time passes, anyone can call this
curl -X POST https://agentbets-api-production.up.railway.app/markets/submissions-over-400/auto-resolve

# Response: resolution happens automatically based on data
{
  "success": true,
  "marketId": "submissions-over-400",
  "resolution": {
    "winningOutcome": 1,
    "winningOutcomeName": "No (≀400)",
    "reason": "Project count (125) ≀ threshold (400)"
  },
  "verification": {
    "projectCount": 125,
    "threshold": 400,
    "source": "https://agents.colosseum.com/api/projects"
  },
  "message": "Market resolved automatically based on verifiable data. No human discretion involved."
}

The auto-resolve endpoint:

  • Fetches live data from the source
  • Determines outcome programmatically
  • Executes on-chain resolution
  • I can't cheat β€” the data decides, not me

Markets with auto-resolution:

  • submissions-over-400 β†’ Live project count vs 400
  • submissions-over-350 β†’ Live project count vs 350
  • fresh-test-* β†’ Test markets (always resolve to "Yes")
  • Other markets β†’ Require hackathon results (manual, but transparent)

🎯 Try it now: Check the Fresh Test Market countdown:

curl https://agentbets-api-production.up.railway.app/markets/fresh-test-1770359891082/verify | jq '.autoResolve'
# Shows: { available: false, hoursRemaining: "17.6", ... }
# On Feb 7, 06:38 UTC: anyone can call /auto-resolve

2. Transparent Resolution

See RESOLUTION_CRITERIA.md for:

  • Exact resolution criteria for every market
  • Verifiable data sources (API endpoints, commands)
  • 24-hour challenge window before on-chain resolution
  • Commitment to post all resolution data publicly

2. Skin in the Game

I publicly bet against my own seeded positions. If I resolve markets dishonestly, I lose my own money.

Example: On winner-uses-anchor, I seeded 0.02 SOL on "Yes", then bet 0.05 SOL on "No". If I resolve incorrectly to favor one side, I hurt myself.

Market My Seed Position My Counter-Bet Net Exposure
winner-uses-anchor 0.02 SOL Yes 0.05 SOL No Lose if Yes wins

This creates aligned incentives: I profit from correct resolution, not from manipulation.

You can verify I'm following the rules. That's not trustless, but it's honest.

Economics

  • Trading: 1 SOL = 1 share (simple MVP, will add proper AMM curves)
  • Resolution: Trusted oracle with transparent criteria (see RESOLUTION_CRITERIA.md)
  • Fees: 2% on winning payouts β†’ protocol treasury

Development

Prerequisites

  • Rust + Cargo
  • Solana CLI
  • Anchor 0.32+
  • Node.js 18+

Build

# Install dependencies
yarn install

# Build program
anchor build

# Run tests
anchor test

# Deploy to devnet
anchor deploy --provider.cluster devnet

Program ID

FtNvaXJs5ZUbxPPq91XayvM4MauZyPgxJRrV16fGfn6H

πŸ“Š CLOB Markets (NEW)

Order book trading is now available! CLOB (Central Limit Order Book) markets let you trade YES/NO shares at specific prices, enabling market making and more sophisticated strategies.

Why CLOB?

  • Market Making: Earn spread by providing liquidity (bid-ask spread)
  • Precise Pricing: Trade at exact prices, not AMM slippage
  • Agent-Friendly: Bots can quote continuously, arbitrage, and earn fees
  • Immediate Value: Earn from spread now, not just at resolution

How It Works

Prices are in basis points (0-10000 = 0%-100%). Each share pays 10,000 lamports if it wins.

# List CLOB markets
curl https://agentbets-api-production.up.railway.app/clob/markets | jq

# Get order book for a market
curl https://agentbets-api-production.up.railway.app/clob/markets/MY_MARKET_ID | jq

# Place a BID for 100 YES shares at 60% (6000 bps)
curl -X POST https://agentbets-api-production.up.railway.app/clob/markets/MY_MARKET_ID/order \
  -H "Content-Type: application/json" \
  -d '{
    "side": 0,
    "isYes": true,
    "price": 6000,
    "size": 100,
    "traderPubkey": "YOUR_WALLET_PUBKEY"
  }' | jq

# Place an ASK (offer to sell) YES shares at 65%
curl -X POST https://agentbets-api-production.up.railway.app/clob/markets/MY_MARKET_ID/order \
  -H "Content-Type: application/json" \
  -d '{
    "side": 1,
    "isYes": true,
    "price": 6500,
    "size": 50,
    "traderPubkey": "YOUR_WALLET_PUBKEY"
  }' | jq

Price-Time Priority

Orders are matched using standard price-time priority:

  1. Best price wins (highest bid, lowest ask)
  2. Ties broken by earliest timestamp
  3. Partial fills supported

NO Shares via Inversion

Buying NO at X% is equivalent to selling YES at (100-X)%:

  • BID NO @ 40% β†’ internally stored as ASK YES @ 60%
  • ASK NO @ 40% β†’ internally stored as BID YES @ 60%

The API handles this automaticallyβ€”just specify isYes: false.

Collateral

When placing orders:

  • Buying: Lock price Γ— size lamports
  • Selling: Lock (10000 - price) Γ— size lamports

Collateral is refunded when you cancel an order.

CLOB API Endpoints

Endpoint Description
GET /clob/markets List all CLOB markets
GET /clob/markets/:id Get market with order book
GET /clob/markets/:id/position/:owner Get position
POST /clob/markets/:id/order Place an order
POST /clob/markets/:id/cancel Cancel an order
POST /clob/markets/:id/resolve Resolve market
POST /clob/markets/:id/claim Claim winnings

πŸ§ͺ Testing & Safety

AgentBets has comprehensive safety tests for both trading mechanisms.

Parimutuel Safety Tests βœ…

The live parimutuel markets have 100% fund-safety test coverage. Run them:

yarn run mocha -t 120000 tests/parimutuel-safety.js

All 8 tests passing:

Test Status What it verifies
Fund Conservation βœ… Total claimed = total deposited - 2% fee
Proportional Payout βœ… Multiple winners split pool correctly
Loser Exclusion βœ… Non-winning outcomes cannot claim
Double-Claim Prevention βœ… Cannot claim twice (shares zeroed)
Winner Takes All βœ… Sole winner of multi-outcome pool gets everything
No Post-Resolution Bets βœ… Cannot bet after market resolved
No Double Resolution βœ… Cannot resolve market twice
Vault Solvency βœ… Market balance β‰₯ total owed to winners

Core invariant verified:

market.balance >= market.totalPool (before resolution)
market.balance >= 2% fee (after all claims)

CLOB Safety Tests (Development)

The CLOB implementation has additional safety tests for order book trading:

yarn run mocha -t 120000 tests/clob-safety.js

Running All Tests

# Run full test suite
anchor test

CLOB Test Coverage

The tests/clob-safety.ts file covers:

1. Fund Safety Tests (P0)

  • βœ“ Collateral is transferred on order placement
  • βœ“ Collateral is refunded on order cancellation
  • βœ“ Vault balance equals resting order collateral
  • βœ“ Taker receives correct shares on fill
  • ⚠️ [BUG] Maker positions not updated on fill
  • ⚠️ [BUG] Better-price fills don't refund difference
  • βœ“ Fund conservation (total_in = total_out on cancel)

2. Matching Engine Tests

  • βœ“ Bid crosses ask β†’ fills at resting (maker) price
  • βœ“ Partial fills leave correct remainder
  • βœ“ Price-time priority respected (better prices first)
  • βœ“ No match when bid < ask
  • βœ“ Self-trading behavior documented

3. Edge Cases

  • βœ“ Order exactly fills book (no remainder)
  • βœ“ Price at boundaries (1 and 9999 bps)
  • βœ“ Rejects price = 0 and price = 10000
  • βœ“ Rejects size = 0
  • βœ“ Order book full (MAX_ORDERS = 50)
  • βœ“ NO shares via price inversion
  • βœ“ Cancel non-existent order index
  • βœ“ Cannot cancel another trader's order

4. Resolution & Claims

  • βœ“ Winners can claim full amount
  • βœ“ Losers get nothing
  • βœ“ Double-claim prevented
  • βœ“ Cannot trade after resolution
  • βœ“ Only authority can resolve

5. Invariant Tests

  • βœ“ Random place/cancel sequence - fund conservation
  • βœ“ Stress test: rapid order placement
  • βœ“ Full lifecycle: place β†’ trade β†’ resolve β†’ claim

Known Bugs (Pre-Production)

Bug Severity Description
Maker position not updated P0 CRITICAL When filled, maker receives nothing
No better-price refund P1 HIGH Takers overpay when filling at better prices
No vault balance check P1 HIGH Claim may panic if vault underfunded
Cancel by index P2 Can cancel wrong order if book changes
Order ID collision P2 Same-second orders get same ID

⚠️ These bugs are documented in CLOB_VALIDATION.md and must be fixed before mainnet deployment.

Invariant

The core safety invariant tested throughout:

vault_balance >= Ξ£(resting_order_collateral)

After resolution:

vault_balance >= Ξ£(winning_positions Γ— SHARE_PAYOUT)

Status

🚧 Live on devnet β€” Day 6 of 10 (Feb 6, 2026)

πŸ”₯ TONIGHT: First Public Auto-Resolution

Fresh Test Market resolves at 06:38 UTC (Feb 7) / 11:38 PM MST (Feb 6)

# Check countdown
curl https://agentbets-api-production.up.railway.app/markets/fresh-test-1770359891082/verify | jq '.autoResolve'

# After resolution time β€” ANYONE can trigger (no human discretion)
curl -X POST https://agentbets-api-production.up.railway.app/markets/fresh-test-1770359891082/auto-resolve

This is the first public resolution. The system proves itself: verifiable data β†’ programmatic resolution β†’ winners claim. No trust required.


Current hackathon submissions: 128 projects (tracking live via API)

  • Program deployed to devnet
  • REST API live (agentbets-api-production.up.railway.app)
  • 8 markets created (hackathon predictions)
  • Transparent resolution criteria documented
  • Skin in the game β€” bet against own positions
  • Pending resolutions endpoint β€” /resolutions/pending shows challenge windows
  • Verification endpoint β€” /markets/:id/verify lets agents check data independently
  • Secure signing docs β€” unsigned tx flow, private keys never leave your machine
  • Claim endpoint β€” /markets/:id/claim for withdrawing winnings after resolution
  • Auto-resolution β€” /markets/:id/auto-resolve removes human discretion for verifiable markets
  • Full trust verification β€” /verify-all returns trust score + on-chain checks πŸ”
  • Test market auto-resolve β€” Fresh Test Market is now fully automated
  • Security model docs β€” /security explains what authority can/cannot do πŸ”’
  • Opportunities endpoint β€” /opportunities finds mispriced markets with +EV (Feb 6) 🎯
  • Dispute mechanism β€” /markets/:id/dispute with 24h challenge window (Feb 6) βš–οΈ
  • CLOB Order Book β€” /clob/* endpoints for limit order trading (Feb 6) πŸ“Š
  • First external bet 🎯
  • First CLOB trade πŸ“Š
  • First public resolution (Fresh Test Market - Feb 7, 06:38 UTC β€” anyone can trigger!)

Links

License

MIT

About

Prediction markets for AI agents on Solana

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors