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 sentmarkstr/
├── 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 marketlet 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 bettinglet address = market.get_market_address()?;println!("Send bets to: {}", address);Browser-compatible bindings for web applications:
importinit,{WasmPredictionMarket,generate_market_id}from'./pkg/markstr_wasm.js';// Initialize WASM moduleawaitinit();// Create a marketconstmarket=newWasmPredictionMarket(generate_market_id(),"Will Bitcoin reach $100k?","Yes","No","oracle_pubkey_hex",1735689600,2// Signet network);// Calculate live oddsconstoddsA=market.get_odds_a(100000n,200000n);// 100k vs 200k satsconsole.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 satModern 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 marketlet 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 addresslet 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 webappconstsportsMarket=newWasmPredictionMarket("SPORT001","Will the Lakers beat the Celtics tonight?","Lakers Win","Celtics Win","sports_oracle_pubkey",Math.floor(Date.now()/1000)+3600,// 1 hour from now2// Signet network);// Calculate current oddsconstlakersOdds=sportsMarket.get_odds_a(75000n,125000n);// 75k vs 125k satsconsole.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 modulecd markstr-wasm
wasm-pack build --target web --out-dir pkg
# Build and run webappcd ../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 testscd webapp
npm test- Core Development: Modify
markstr-corefor business logic changes - WASM Updates: Rebuild
markstr-wasmwhen core changes - CLI Updates: Modify
markstr-clifor command-line interface - Frontend Updates: Develop in
webappfor user interface - Testing: Run comprehensive tests across all components
- Documentation: Update README and inline documentation
// Main market structpubstructPredictionMarket{pubmarket_id:String,pubquestion:String,puboutcome_a:String,puboutcome_b:String,puboracle_pubkey:String,pubsettlement_timestamp:u64,pubnetwork:Network,// ... additional fields}// Individual betpubstructBet{pubpayout_address:String,pubamount:u64,pubtxid:String,pubvout:u32,}implPredictionMarket{// Create a new marketpubfnnew(/* ... */) -> Result<Self>;// Get the market's Bitcoin addresspubfnget_market_address(&self) -> Result<String>;// Place a bet on an outcomepubfnplace_bet(&mutself,/* ... */) -> Result<()>;// Settle the market with oracle signaturepubfnsettle_market(&mutself,/* ... */) -> Result<()>;// Calculate payoutspubfncalculate_payout(&self,/* ... */) -> u64;// Get current oddspubfnget_odds_a(&self) -> f64;pubfnget_odds_b(&self) -> f64;}// TypeScript definitions for WASM bindingsexportclassWasmPredictionMarket{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 propertiesreadonlymarket_id: string;readonlyquestion: string;readonlysettled: 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