Bitcoin Prediction Markets Proof of Concept using CSFS and Taproot
Markstr is an advanced proof of concept for decentralized prediction markets on Bitcoin, leveraging Nostr for oracle communication and CSFS (CheckSigFromStack) for oracle outcome signature onchain verification.
Note: This project requires Bitcoin opcodes (CSFS) that are not currently enabled on Bitcoin mainnet. It is designed as a research prototype to demonstrate technical feasibility.
- Decentralized Markets: Create binary prediction markets with no central authority
- Bitcoin Native: Built on Bitcoin Taproot with CSFS for secure settlement
- Nostr Oracles: Decentralized oracle communication via Nostr protocol
- Multi-Platform: Rust core library, WebAssembly bindings, React webapp, and CLI
- Cryptographic Verification: Oracle signatures verified via CSFS scripts
- Proportional Payouts: Winners receive proportional shares of the total pool
- Rust: Install from rustup.rs
- Node.js: For the webapp (v18+)
- Git: For cloning the repository
# Clone the repository
git clone https://github.com/AbdelStark/markstr.git
cd markstr
# Build all components
cargo build --release
# Run the CLI
cargo run --bin markstr -- --help
# Create a new prediction market
cargo run --bin markstr -- create \
--question "Will Bitcoin reach $100k by 2024?" \
--outcome-a "Yes" \
--outcome-b "No" \
--oracle "your_oracle_pubkey_hex" \
--settlement 1735689600
# This will output a Bitcoin address where bets can be sent
markstr/
βββ markstr-core/ # Core Rust library
βββ markstr-wasm/ # WebAssembly bindings
βββ markstr-cli/ # Command-line interface
βββ webapp/ # React web application
βββ docs/ # Documentation
βββ examples/ # Example implementations
βββ Cargo.toml # Workspace configuration
- markstr-core: Pure Rust library containing all prediction market logic
- markstr-wasm: WebAssembly bindings for browser/Node.js usage
- markstr-cli: Command-line interface for market creation and management
- webapp: React frontend providing a complete user interface
graph LR
A[Create Market] --> B[Generate Taproot Address]
B --> C[Participants Place Bets]
C --> D[Settlement Time Reached]
D --> E[Oracle Signs Outcome]
E --> F[Winners Claim Funds]
F --> G[Market Settled]
- Bitcoin: Taproot addresses with CSFS scripts
- Nostr: Decentralized oracle communication
- Rust: Core logic and cryptographic operations
- WebAssembly: Browser-compatible bindings
- React: Modern web interface
- TypeScript: Type-safe frontend development
The heart of the system, providing:
- PredictionMarket: Core market struct with betting and settlement logic
- NostrClient: Oracle communication via Nostr events
- CSFS Verification: Cryptographic verification of oracle signatures
- Taproot Integration: Bitcoin script generation and transaction handling
use markstr_core::PredictionMarket;
// Create a new market
let market = PredictionMarket::new(
"Will it rain tomorrow?".to_string(),
"Yes".to_string(),
"No".to_string(),
"oracle_pubkey_hex".to_string(),
1735689600, // Settlement timestamp
)?;
// Get the market address for betting
let address = market.get_market_address()?;
println!("Send bets to: {}", address);
Browser-compatible bindings for web applications:
import init, { WasmPredictionMarket, generate_market_id } from './pkg/markstr_wasm.js';
// Initialize WASM module
await init();
// Create a market
const market = new WasmPredictionMarket(
generate_market_id(),
"Will Bitcoin reach $100k?",
"Yes", "No",
"oracle_pubkey_hex",
1735689600, 2 // Signet network
);
// Calculate live odds
const oddsA = market.get_odds_a(100000n, 200000n); // 100k vs 200k sats
console.log(`Odds for "Yes": ${oddsA}%`);
Full-featured CLI for power users:
# Create a market
markstr create \
--question "Who will win the election?" \
--outcome-a "Candidate A" \
--outcome-b "Candidate B" \
--oracle "abc123..." \
--settlement 1735689600
# Generate a market ID
markstr generate-id
# Validate an address
markstr validate-address bc1q... --network 0
# Convert units
markstr convert 1.5 btc
markstr convert 150000000 sat
Modern React interface with:
- Market Creation: Intuitive market creation flow
- Live Betting: Real-time odds and betting interface
- Role Management: Switch between Oracle, Bettor, and Viewer roles
- Transaction History: Complete transaction and payout tracking
- Analytics Dashboard: Market performance and statistics
- Election Predictions: Presidential, congressional, and local elections
- Sports Betting: Football, basketball, soccer, esports
- Economic Indicators: GDP growth, inflation rates, stock prices
- Cryptocurrency: Price predictions, adoption metrics
- Technology: Product launches, company announcements
- Weather: Temperature, precipitation, natural disasters
- Social Events: Award shows, celebrity news, cultural events
- Research: Scientific discoveries, academic achievements
- Corporate Forecasting: Internal company predictions
- Community Decisions: Local governance, resource allocation
- Academic Research: Crowdsourced expertise aggregation
- Risk Assessment: Insurance, investment, project planning
- CSFS Scripts: Oracle signatures verified on-chain
- Taproot Privacy: Enhanced privacy through script aggregation
- Schnorr Signatures: Efficient signature verification
- Hash Commitments: Tamper-evident outcome messages
- No Central Authority: Markets operate without intermediaries
- Censorship Resistance: Nostr's decentralized relay network
- Oracle Independence: Multiple oracle support
- Open Source: Full code transparency and auditability
- Proportional Payouts: Fair distribution based on bet size
- Fee Transparency: Clear fee structure and deduction
- Market Efficiency: Real-time odds reflect true probabilities
- Slippage Protection: Transparent pricing mechanisms
// Create a weather prediction market
let weather_market = PredictionMarket::new(
"Will it rain in NYC tomorrow?".to_string(),
"Yes, it will rain".to_string(),
"No, it will not rain".to_string(),
"weather_oracle_pubkey".to_string(),
1735689600, // Tomorrow at noon
)?;
// Get the betting address
let address = weather_market.get_market_address()?;
println!("Weather market address: {}", address);
# Create an election market via CLI
markstr create \
--question "Who will win the 2024 Presidential Election?" \
--outcome-a "Democratic Candidate" \
--outcome-b "Republican Candidate" \
--oracle "election_oracle_pubkey_hex" \
--settlement 1730419200 # November 1, 2024
// Create a sports market in the webapp
const sportsMarket = new WasmPredictionMarket(
"SPORT001",
"Will the Lakers beat the Celtics tonight?",
"Lakers Win",
"Celtics Win",
"sports_oracle_pubkey",
Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
2 // Signet network
);
// Calculate current odds
const lakersOdds = sportsMarket.get_odds_a(75000n, 125000n); // 75k vs 125k sats
console.log(`Lakers odds: ${lakersOdds}%`);
# Clone and build
git clone https://github.com/AbdelStark/markstr.git
cd markstr
# Build all Rust components
cargo build --release
# Build WebAssembly module
cd markstr-wasm
wasm-pack build --target web --out-dir pkg
# Build and run webapp
cd ../webapp
npm install
npm run dev
# Run all tests
cargo test
# Run specific component tests
cargo test -p markstr-core
cargo test -p markstr-wasm
cargo test -p markstr-cli
# Run webapp tests
cd webapp
npm test
- Core Development: Modify
markstr-core
for business logic changes - WASM Updates: Rebuild
markstr-wasm
when core changes - CLI Updates: Modify
markstr-cli
for command-line interface - Frontend Updates: Develop in
webapp
for user interface - Testing: Run comprehensive tests across all components
- Documentation: Update README and inline documentation
// Main market struct
pub struct PredictionMarket {
pub market_id: String,
pub question: String,
pub outcome_a: String,
pub outcome_b: String,
pub oracle_pubkey: String,
pub settlement_timestamp: u64,
pub network: Network,
// ... additional fields
}
// Individual bet
pub struct Bet {
pub payout_address: String,
pub amount: u64,
pub txid: String,
pub vout: u32,
}
impl PredictionMarket {
// Create a new market
pub fn new(/* ... */) -> Result<Self>;
// Get the market's Bitcoin address
pub fn get_market_address(&self) -> Result<String>;
// Place a bet on an outcome
pub fn place_bet(&mut self, /* ... */) -> Result<()>;
// Settle the market with oracle signature
pub fn settle_market(&mut self, /* ... */) -> Result<()>;
// Calculate payouts
pub fn calculate_payout(&self, /* ... */) -> u64;
// Get current odds
pub fn get_odds_a(&self) -> f64;
pub fn get_odds_b(&self) -> f64;
}
// TypeScript definitions for WASM bindings
export class WasmPredictionMarket {
constructor(/* ... */);
get_market_address(): string;
get_odds_a(bets_a: bigint, bets_b: bigint): number;
calculate_payout(bet: bigint, winning: bigint, total: bigint): bigint;
settle_market(outcome: string): void;
// Readonly properties
readonly market_id: string;
readonly question: string;
readonly settled: boolean;
// ... additional properties
}
IMPORTANT: This project cannot run on Bitcoin mainnet as it requires CSFS opcodes that are not currently enabled.
- Testnet: Bitcoin test network (limited functionality)
- Signet: Signed test network (recommended for development)
- Regtest: Local regression testing with custom rules
- Public Relays: Connect to public Nostr relays
- Private Relays: Use custom relay infrastructure
- Relay Discovery: Automatic relay discovery and connection
- Redundancy: Multiple relay support for reliability
- Basic prediction market implementation
- CSFS script generation
- Taproot address creation
- WebAssembly bindings
- CLI interface
- Web application
- Multi-outcome markets (more than binary)
- Market categories and tagging
- Oracle reputation system
- Advanced analytics dashboard
- Mobile-responsive webapp
- REST API for integrations
- Liquidity pools and market makers
- Institutional trader tools
- Professional oracle services
- Advanced analytics and reporting
- Plugin architecture
- Developer tools and SDKs
- Educational resources
- Research publications and documentation
We welcome contributions! Please see our Contributing Guide for details.
# Fork the repository
git clone https://github.com/YOUR_USERNAME/markstr.git
cd markstr
# Create a feature branch
git checkout -b feature/your-feature-name
# Make your changes
# ... develop ...
# Run tests
cargo test
# Submit a pull request
git push origin feature/your-feature-name
- Rust: Follow standard Rust conventions with
cargo fmt
- JavaScript: Use Prettier for consistent formatting
- Documentation: Update README and inline docs for new features
- Tests: Add tests for new functionality
This project is licensed under the MIT License - see the LICENSE file for details.
- Bitcoin Core: For the robust Bitcoin implementation
- Nostr: For the decentralized communication protocol
- Rust Community: For exceptional tooling and libraries
- WebAssembly: For enabling Rust in browsers
- React: For the modern web framework
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Research prototype for Bitcoin prediction markets using advanced cryptographic techniques