A trustless, transparent, and decentralized prediction market for XLM price movements built on Stellar blockchain using Soroban smart contracts.
Xelma is a blockchain-based prediction market with dual prediction modes:
- Up/Down Mode: Bet on whether XLM price will go UP or DOWN
- Precision Mode (Legends): Predict the exact price - closest guess wins!
Unlike traditional prediction markets, Xelma is:
- ๐ Permissionless - Anyone with a Stellar wallet can participate
- ๐ Transparent - All bets, rounds, and payouts are verifiable on-chain
- โก Instant - Claim your winnings immediately after round resolution
- ๐ก๏ธ Secure - Smart contract logic ensures fair, automated payouts
- ๐ฐ Low-cost - Stellar's minimal transaction fees (~0.00001 XLM)
| Issue | Traditional Markets | Xelma Solution |
|---|---|---|
| Centralization | Single point of failure, can be shut down | Runs on blockchain, unstoppable |
| Transparency | Opaque calculations, potential manipulation | All logic on-chain, fully auditable |
| Access | Requires KYC, bank accounts, specific locations | Just need a Stellar wallet |
| Payout Speed | Days or weeks to withdraw | Instant claims after resolution |
| Trust | Must trust the operator won't steal funds | Trustless smart contract execution |
| Fees | High fees (5-10%+) | Minimal blockchain fees (~0.00001 XLM) |
- Financial Inclusion: No KYC barriers, anyone globally can participate
- Verifiable Fairness: Every bet, pool, and payout is transparent
- No Counterparty Risk: Smart contract holds funds, not a company
- Educational: Learn prediction markets without real money risk (virtual tokens)
- Building Block: Foundation for decentralized derivatives/prediction markets
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Users (Bettors) โ
โ - Mint virtual tokens (1000 vXLM) โ
โ - Place bets (UP/DOWN on XLM price) โ
โ - Track stats (wins, losses, streaks) โ
โ - Claim winnings โ
โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Interacts via Frontend/SDK
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ TypeScript Bindings (SDK) โ
โ - Type-safe contract calls โ
โ - All contract functions exposed โ
โ - Error handling with custom types โ
โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Calls via Stellar SDK
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Soroban Smart Contract (Rust) โ
โ โ
โ [Virtual Token System] โ
โ โข Mint 1000 vXLM per new user โ
โ โข Track balances on-chain โ
โ โ
โ [Round Management] โ
โ โข Admin creates rounds (start price + mode + duration) โ
โ โข Mode 0 (Up/Down): Bet UP or DOWN โ
โ โข Mode 1 (Precision): Predict exact price โ
โ โข Oracle resolves rounds (final price) โ
โ โ
โ [Payout Logic - Dual Mode] โ
โ โข Up/Down: Winners split losers' pool proportionally โ
โ โข Precision: Closest guess wins full pot (ties split) โ
โ โข Unchanged price โ everyone gets refund โ
โ โข Claim-based withdrawal (user controlled) โ
โ โ
โ [User Statistics] โ
โ โข Track wins, losses, streaks โ
โ โข On-chain leaderboard data โ
โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Stellar Blockchain (Storage) โ
โ - Persistent storage for all contract data โ
โ - Ledger: ~5 seconds per block โ
โ - Network: Testnet (development) / Mainnet (future) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- Alice connects wallet โ Receives 1000 vXLM automatically
- Admin creates round โ Start price: 1.0 XLM, Duration: 60 ledgers (~5 min)
- Alice bets 100 vXLM UP, Bob bets 200 vXLM UP, Charlie bets 150 vXLM DOWN
- Oracle resolves โ Final price: 1.5 XLM (price went UP!)
- Payouts calculated:
- Winning pool (UP): 300 vXLM
- Losing pool (DOWN): 150 vXLM
- Alice gets: 100 + (100/300) ร 150 = 150 vXLM (50% profit!)
- Bob gets: 200 + (200/300) ร 150 = 300 vXLM (50% profit!)
- Charlie loses his 150 vXLM
- Alice & Bob claim winnings โ Instant balance update
- Language: Rust 1.92.0
- Framework: Soroban SDK 23.0.1
- Blockchain: Stellar (Testnet)
- Testing: 80/80 tests passing (100% coverage)
- โ Custom error handling (20 error types)
- โ Overflow protection (checked arithmetic)
- โ Role-based access control (Admin, Oracle, User)
- โ Input validation on all functions
- โ Claim-based withdrawal pattern
- โ Proportional payout algorithm
- โ User statistics tracking
- โ Precision remainder policy (first-winner receives dust)
When multiple users tie in Precision Mode, the total pot is split evenly using integer division. Any remainder (dust) from the division is awarded to the first winner (by prediction order).
Example:
- Total pot: 100 vXLM
- 3-way tie (Alice, Bob, Charlie)
- Division: 100 รท 3 = 33.33...
- Payouts:
- Alice: 33 + 1 (remainder) = 34 vXLM
- Bob: 33 vXLM
- Charlie: 33 vXLM
- Total distributed: 100 vXLM โ (no dust lost)
This ensures:
- โ Zero dust loss - Every stroops is accounted for
- โ Simple & predictable - First predictor gets the remainder
- โ Fair distribution - Close to equal split, minimal advantage
- Language: TypeScript 5.6.2
- SDK: Stellar SDK v13
- Package:
@tevalabs/xelma-bindings - Types: Fully typed contract interface
Xelma-Blockchain/
โโโ contracts/ # Main prediction market contract
โ โโโ src/
โ โ โโโ lib.rs # Crate root and module declarations
โ โ โโโ contract.rs # Core contract implementation (~820 lines)
โ โ โโโ errors.rs # Custom error types (20 variants)
โ โ โโโ types.rs # Contract types and storage keys
โ โ โโโ tests/ # Test suite (80 tests)
โ โ โโโ mod.rs
โ โ โโโ betting.rs
โ โ โโโ edge_cases.rs
โ โ โโโ initialization.rs
โ โ โโโ lifecycle.rs
โ โ โโโ mode_tests.rs
โ โ โโโ property_invariants.rs
โ โ โโโ resolution.rs
โ โ โโโ security.rs
โ โ โโโ windows.rs
โ โโโ Cargo.toml # Rust dependencies
โ โโโ test_snapshots/ # Test execution records
โ
โโโ bindings/ # TypeScript bindings (auto-generated)
โ โโโ src/
โ โ โโโ index.ts # Contract types & client (~640 lines)
โ โโโ dist/ # Compiled JavaScript
โ โโโ package.json # NPM package config
โ โโโ README.md # Bindings usage guide
โ
โโโ target/ # Build artifacts
โ โโโ wasm32-unknown-unknown/
โ โโโ release/
โ โโโ xelma_contract.wasm # Compiled contract
โ
โโโ SECURITY_REVIEW.md # Comprehensive security audit
โโโ Cargo.toml # Workspace configuration
โโโ README.md # This file
- Rust 1.92.0+
- Stellar CLI (soroban-cli)
- Node.js 18+ (for bindings)
git clone https://github.com/TevaLabs/Xelma-Blockchain.git
cd Xelma-Blockchaincd contracts
cargo build --target wasm32-unknown-unknown --releasecargo test
# Output: 80 passed; 0 failedcd ../../
stellar contract bindings typescript \
--wasm target/wasm32-unknown-unknown/release/xelma_contract.wasm \
--output-dir ./bindings \
--overwrite
cd bindings
npm install
npm run buildimport { Client, BetSide } from '@tevalabs/xelma-bindings';
const client = new Client({
contractId: 'YOUR_CONTRACT_ID',
networkPassphrase: Networks.TESTNET,
rpcUrl: 'https://soroban-testnet.stellar.org'
});
// Mint initial tokens
await client.mint_initial({ user: userAddress });
// Place a bet
await client.place_bet({
user: userAddress,
amount: 100_0000000n, // 100 vXLM (in stroops)
side: BetSide.Up
});
// Check stats
const stats = await client.get_user_stats({ user: userAddress });
console.log(`Wins: ${stats.total_wins}, Streak: ${stats.current_streak}`);We take security seriously. The contract has undergone comprehensive hardening:
- โ 20 Custom Error Types - Clear, debuggable error codes
- โ
Checked Arithmetic - All math operations use
checked_*to prevent overflow - โ Role-Based Access - Admin creates rounds, Oracle resolves, Users bet
- โ Input Validation - All parameters validated (amount > 0, round active, etc.)
- โ No Reentrancy Risk - CEI pattern (Checks-Effects-Interactions)
- โ State Consistency - Prevents double betting, validates round lifecycle
- โ 80/80 Tests Passing - Full coverage of edge cases and attack vectors
- SECURITY_REVIEW.md - Complete security analysis
Status: โ
Production-ready for testnet
Recommendation: External audit recommended before mainnet deployment
All major state transitions emit standardized events for indexers and frontend consumers. Events follow a consistent format: (topic_1, topic_2) โ (payload...).
Emitted when admin creates a new prediction round.
Topic: ("round", "created")
Payload: (
round_id: u64, // Unique round identifier
start_price: u128, // Initial XLM price (4 decimals: 2297 = $0.2297)
start_ledger: u32, // Ledger when round begins
bet_end_ledger: u32, // Last ledger to place bets
end_ledger: u32, // Ledger when round can be resolved
mode: u32 // 0 = Up/Down, 1 = Precision
)Use Case: Index new rounds, display active games, trigger notifications.
Emitted when user places a bet in Up/Down mode.
Topic: ("bet", "placed")
Payload: (
user: Address, // User who placed the bet
round_id: u64, // Round identifier
amount: i128, // Bet amount in stroops (1 vXLM = 10^7 stroops)
side: u32 // 0 = Up, 1 = Down
)Use Case: Track user bets, calculate pool sizes, display live betting activity.
Emitted when user submits a price prediction in Precision/Legends mode.
Topic: ("predict", "price")
Payload: (
user: Address, // User who made prediction
round_id: u64, // Round identifier
predicted_price: u128, // Predicted price (4 decimals: 2297 = $0.2297)
amount: i128 // Stake amount in stroops
)Use Case: Track predictions, show leaderboard before resolution, display user guesses.
Emitted when oracle resolves a round with final price.
Topic: ("round", "resolved")
Payload: (
round_id: u64, // Round identifier
final_price: u128, // Actual final price (4 decimals)
mode: u32 // 0 = Up/Down, 1 = Precision
)Use Case: Trigger winner calculations, update leaderboards, notify users of results.
Emitted when user claims their pending winnings.
Topic: ("claim", "winnings")
Payload: (
user: Address, // User claiming winnings
amount: i128 // Amount claimed in stroops
)Use Case: Track payouts, display claim history, calculate platform volume.
Emitted when admin updates bet/run window durations.
Topic: ("windows", "updated")
Payload: (
bet_window_ledgers: u32, // Number of ledgers for betting phase
run_window_ledgers: u32 // Total ledgers until resolution
)Use Case: Update frontend timers, recalculate round schedules.
Emitted when new user mints their first 1000 vXLM.
Topic: ("mint", "initial")
Payload: (
user: Address, // New user address
amount: i128 // Minted amount (1000 * 10^7 stroops)
)Use Case: Track new users, display welcome messages, analytics.
import { SorobanRpc } from '@stellar/stellar-sdk';
const server = new SorobanRpc.Server('https://soroban-testnet.stellar.org');
// Get transaction events
const txResult = await server.getTransaction(txHash);
const events = txResult.events;
// Parse round created event
const roundCreatedEvent = events.find(e =>
e.topic[0] === 'round' && e.topic[1] === 'created'
);
if (roundCreatedEvent) {
const [roundId, startPrice, startLedger, betEnd, endLedger, mode] = roundCreatedEvent.value;
console.log(`New round ${roundId} created at price ${startPrice}`);
}// Poll for new rounds
async function watchForNewRounds(contractId: string) {
const latestLedger = await server.getLatestLedger();
const events = await server.getEvents({
startLedger: latestLedger.sequence - 100,
filters: [{
type: 'contract',
contractIds: [contractId],
topics: [['round'], ['created']]
}]
});
return events.events.map(parseRoundCreatedEvent);
}- Event Ordering: Events are emitted in transaction order within each ledger.
- Uniqueness: Use
(round_id, user, event_type)for deduplication. - Decimal Handling: All prices use 4 decimal places (divide by 10000 for display).
- Stroops: All amounts are in stroops (1 vXLM = 10^7 stroops).
- Address Format: Stellar addresses are 56-character G-prefixed strings.
mint_initial(user)- Get 1000 vXLM on first usebalance(user)- Query current balanceplace_bet(user, amount, side)- Bet on UP or DOWN (Mode 0)place_precision_prediction(user, amount, predicted_price)- Predict exact price (Mode 1)predict_price(user, guessed_price, amount)- Alias forplace_precision_predictionclaim_winnings(user)- Withdraw pending winningsget_user_stats(user)- View wins, losses, streaksget_user_position(user)- Check bet in current round (Mode 0)get_user_precision_prediction(user)- Check prediction in current round (Mode 1)
initialize(admin, oracle)- One-time contract setupcreate_round(start_price, mode)- Start new betting round (mode: 0=Up/Down, 1=Precision)set_windows(bet_ledgers, run_ledgers)- Configure round timing windows
resolve_round(payload)- Resolve round and trigger payouts (requiresOraclePayloadwith price, timestamp, and round ID)
get_active_round()- View current round details (includes mode)get_last_round_id()- Query the latest round IDget_admin()- Query admin addressget_oracle()- Query oracle addressget_pending_winnings(user)- Check claimable amountget_precision_predictions()- View all predictions in current Precision roundget_updown_positions()- View all positions in current Up/Down round
- Short-term price predictions (5-15 minute rounds)
- Friendly competition and leaderboards
- Track and improve prediction skills
- Learn prediction markets risk-free (virtual tokens)
- Understand blockchain interactions
- Practice trading psychology
- Expand to real money markets (with proper licensing)
- Multi-asset predictions (BTC, ETH, stocks)
- Longer time horizons (hourly, daily rounds)
- Tournament modes with prizes
- Virtual token system
- Dual-mode round management (Up/Down + Precision)
- Hybrid resolution logic
- Up/Down betting mechanism with proportional payouts
- Precision prediction mechanism (closest guess wins)
- User statistics tracking
- Comprehensive testing (80/80)
- Security hardening
- TypeScript bindings
- Deploy to Stellar testnet
- Oracle service (price feed integration)
- Backend API
- Monitoring & analytics
- React/Next.js web app
- Wallet integration (Freighter, Albedo)
- Real-time round updates
- User dashboard & leaderboards
- External security audit
- Mainnet deployment
- Mobile app (React Native)
- Community features (social betting, tournaments)
We welcome contributions from the community! Here's how you can help:
- Report Bugs - Open an issue with reproduction steps
- Suggest Features - Share your ideas for improvements
- Submit PRs - Fix bugs or add features
- Improve Docs - Help make documentation clearer
- Write Tests - Expand test coverage
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
This repository contains both source files and generated artifacts. Understanding which files are generated and how to regenerate them is essential for contributions.
contracts/src/**- Rust source code (manually written)bindings/src/index.ts- TypeScript bindings source (auto-generated but committed for convenience)Cargo.toml,package.json- Dependency manifests- Configuration files -
.gitignore,tsconfig.json, etc.
target/- Rust build outputs (WASM binaries, compiled Rust)bindings/dist/- Compiled TypeScript output (JavaScript + type definitions)node_modules/- npm dependenciescontracts/test_snapshots/- Test execution records (generated during tests)contracts/proptest-regressions/- Property test regression files (generated during tests).soroban/- Soroban CLI artifacts
1. Build the Smart Contract:
cd contracts
cargo build --target wasm32-unknown-unknown --release2. Regenerate TypeScript Bindings: After building the contract, generate the bindings from the WASM file:
cd ../
stellar contract bindings typescript \
--wasm target/wasm32-unknown-unknown/release/xelma_contract.wasm \
--output-dir ./bindings/src \
--overwrite3. Build TypeScript Bindings: Compile the TypeScript bindings to JavaScript:
cd bindings
npm install
npm run build4. Run Tests (regenerates test artifacts):
cd ../contracts
cargo testNote: Test snapshots and proptest regressions are automatically generated when running tests. These files help ensure test consistency but should not be committed.
-
Verify no build artifacts are staged:
git status # Ensure target/, bindings/dist/, node_modules/, test_snapshots/, proptest-regressions/ are not listed -
If you modified the contract, regenerate bindings:
# Build contract cargo build --target wasm32-unknown-unknown --release --package xelma-contract # Regenerate bindings stellar contract bindings typescript \ --wasm target/wasm32-unknown-unknown/release/xelma_contract.wasm \ --output-dir ./bindings/src \ --overwrite # Build bindings cd bindings && npm run build && cd ..
-
Commit only source files, not build artifacts:
- โ
Commit:
bindings/src/index.ts(regenerated bindings source) - โ Don't commit:
bindings/dist/(compiled output)
- โ
Commit:
Check issues labeled good-first-issue to get started!
- Smart Contract - Modular Rust code (contract, types, errors)
- Security Review - Security analysis and best practices
- Bindings Guide - TypeScript integration guide
- Test Suite - Comprehensive test examples (80 tests)
- Xelma-Frontend - React web application for users
- Xelma-Backend - Oracle service and API
- Xelma-Mobile - React Native mobile app
This project is licensed under the MIT License - see the LICENSE file for details.
- GitHub: @TevaLabs
- Repository: Xelma-Blockchain
- Issues: Report bugs or request features
When making contract changes, update the following to keep this README in sync:
- Test count โ re-run
cargo testand update badge + inline counts - Error types โ if new
ContractErrorvariants are added, update the error-type count - Function list โ add/remove entries under Contract Functions section
- Build artifact name โ if the crate name changes, update
Cargo.toml, CI workflow, and the binding generation command - SDK version โ after bumping
soroban-sdk, update the Soroban badge and Technical Stack section - Repository structure โ reflect any new source files or directories
- Stellar Development Foundation - For the Soroban platform
- Rust Community - For excellent tooling and support
- Contributors - Thank you to everyone who helps improve Xelma!
Built with โค๏ธ on Stellar Blockchain