Traditional prediction markets often suffer from a lack of transparency, high fees, and centralized resolutions that are open to manipulation. Predict-IO addresses this by being a genuinely trustless, decentralized platform built on the Stellar (Soroban) network. It lets anyone create, trade, and settle prediction markets automatically and securely, using an on-chain oracle (Reflector Network) so that outcomes cannot be tampered with by a central party. All prices are handled as fixed-point integers (i128) rather than floating-point numbers, so micro-fluctuations in asset prices are compared without rounding loss.
- Smart Contracts & Blockchain: Rust, Stellar Network (Soroban), and the Reflector Oracle Network (SEP-40).
- Frontend & UI: Next.js 16 (App Router) with React 19, Tailwind CSS, and shadcn/ui. Wallet connection through Stellar Wallets Kit (Freighter, xBull, Rabet, Albedo, Lobstr, Hana). Server state with TanStack Query, client state with Zustand.
- Backend & API: Node.js, Fastify, Prisma ORM, Zod for validation, and
node-cronfor the settlement worker. - Database: PostgreSQL (hosted on Supabase, though any Postgres instance works).
- Languages: TypeScript (frontend and backend) and Rust (smart contracts).
contracts/ Soroban smart contracts (Cargo workspace rooted at ./Cargo.toml)
prediction_market/ operator-settled markets, N outcomes, parimutuel
reflector_prediction_market/ oracle-settled binary markets (Up/Down/Draw)
reflector_mock/ mock SEP-40 oracle for local and testnet runs
backend/ Fastify API + Prisma indexer + settlement cron worker
frontend/ Next.js app (market discovery, trading, admin dashboard)
- Node.js 20+ and
pnpm - Rust 1.80+ with the
wasm32v1-nonetarget (rustup target add wasm32v1-none) stellar-cli(cargo install --locked stellar-cli)- A PostgreSQL database — either a Supabase project or a local instance (Docker works)
-
Clone the repository:
git clone https://github.com/jorgesoares2997/predict_io cd predict_io -
Build and deploy the smart contracts: Run the tests, then build and deploy to the Stellar Testnet.
cargo test # from the repo root cd contracts/prediction_market stellar contract build --optimize stellar contract deploy \ --wasm ../../target/wasm32v1-none/release/prediction_market.wasm \ --source admin --network testnet
Save the returned contract ID — both the backend and the frontend need it. Deploy
reflector_prediction_marketthe same way if you want oracle-settled markets, and call itsinitfunction once after deploying. Seecontracts/prediction_market/DEPLOYMENT_GUIDE.mdfor the full walkthrough, including identity creation and CLI invocation examples.Note: the two market contracts are not interchangeable — they expose different
create_marketandplace_betsignatures. Whichever WASM you deploy at the address you configure asMARKET_CONTRACT_ADDRESSdetermines which market type the platform can create. -
Set up the backend:
cd backend pnpm install # runs `prisma generate` automatically cp .env.example .env # then fill in the values described below
Point
DATABASE_URLat your database, setJWT_SECRET, and fill in the Stellar settings (STELLAR_HORIZON_URL,STELLAR_NETWORK_PASSPHRASE,SOROBAN_RPC_URL), the contract addresses (MARKET_CONTRACT_ADDRESS,USDC_CONTRACT_ADDRESS,REFLECTOR_CONTRACT_ID), and the operator keypair (OPERATOR_PUBLIC_KEY,OPERATOR_SECRET_KEY)..env.exampledocuments every variable, including the testnet and mainnet values for each network setting. SetENABLE_KYC=falsein development to skip identity verification.If you are using Supabase, link the project first:
npx supabase login npx supabase link --project-ref <YOUR_PROJECT_REF>
Apply the schema, seed it, and start the server:
npx prisma db push pnpm seed pnpm dev
-
Set up the frontend:
cd frontend pnpm install pnpm devThe frontend reads its configuration from
frontend/.env.local(no template is committed, so create the file yourself):NEXT_PUBLIC_API_URL=http://localhost:8080/api NEXT_PUBLIC_HORIZON_URL=https://horizon-testnet.stellar.org NEXT_PUBLIC_SOROBAN_RPC_URL=https://soroban-testnet.stellar.org NEXT_PUBLIC_NETWORK_PASSPHRASE=Test SDF Network ; September 2015 NEXT_PUBLIC_MARKET_CONTRACT_ID=<your market contract id> NEXT_PUBLIC_USDC_CONTRACT_ID=<USDC SAC address> NEXT_PUBLIC_REFLECTOR_CONTRACT_ID=<Reflector oracle contract id> # Optional — only needed to exercise the KYC flow NEXT_PUBLIC_DIDIT_VERIFICATION_URL=
Make sure
NEXT_PUBLIC_API_URLmatches the port the backend actually listens on (PORTinbackend/.env), and that the network passphrase and contract IDs match the backend's — otherwise transactions will be simulated against the wrong network. Then openhttp://localhost:3000.workthoughtat the repo root is a step-by-step manual test script covering every major UI flow end to end.
- Dual market types: standard markets, settled by the operator from an external
resolution_source, and oracle markets, settled entirely on-chain against the Reflector Network. - Trustless oracle settlement:
settle_marketon the oracle contract takes only a market ID — no winning-outcome argument and no admin authorization. The contract queries Reflector itself, prefers the historical price at the market'send_time, rejects stale data, and derives the winner from the market's stored target price and comparison operator. The backend cron can only trigger settlement; it cannot influence the result. - Precise price handling: oracle prices are stored and compared as fixed-point
i128integers with per-asset decimal precision, and never pass through JavaScript floating-point numbers, so tiny price differences don't collapse into false ties. - Refunds on draws: if an oracle market closes exactly at its reference price, the contract marks the outcome as a draw and
claimreturns each participant's full stake from both sides of the pool. - Custody stays with the contract: the backend never holds user keys. Trades and claims use a prepare → sign → execute flow — the API returns an unsigned transaction, the user's wallet signs it, and the API verifies that the returned transaction hash matches the one it prepared before submitting.
- Parimutuel payouts: winnings are computed on-chain as
stake × total_pool / winning_poolusing integer arithmetic, with an optional protocol fee in basis points on oracle markets. - Workers and indexing: a cron worker locks markets whose betting window has closed, resolves those past their liquidation time, and retries on-chain settlement until it succeeds. The database acts as a fast read cache over on-chain state.
- Admin dashboard and KYC: an admin area for creating and managing markets and categories, plus optional identity verification through DIDIT, gated behind the
ENABLE_KYCflag.
- Clean architecture (DDD): the backend is organized into presentation, application, and infrastructure layers, with use cases depending on port interfaces rather than concrete implementations. Everything is wired explicitly in
src/server.ts, which keeps the API testable and makes it straightforward to swap out the Stellar or persistence layer. - Real decentralization with Reflector: in production the system reads consensus prices from the official Reflector network through the SEP-40 interface (
Asset::Stellar(Address)/Asset::Other(Symbol)), so market data is not sourced from a single trusted party. A mock oracle contract is included for local development. - Resolution that degrades safely: if on-chain settlement fails, the database still records the resolution so the UI stays accurate, and the worker keeps retrying settlement on every tick — both
settle_marketandcreate_marketare idempotent. If the price fetch fails, the market deliberately stays locked instead of resolving on incomplete data. - Separation of responsibilities: the frontend handles discovery and transaction signing, the backend acts as a fast gateway and indexer, and the blockchain holds all funds and business logic in immutable contracts.
- Wallet-signature authentication: login proves key ownership instead of relying on a password. Because wallets sign transactions rather than arbitrary bytes, the challenge is embedded as a hash in a
manageDataoperation, verified server-side, and exchanged for a JWT.
- Live deploy: https://predi-ct-io.vercel.app/
- Repository: https://github.com/jorgesoares2997/predict_io
Application screenshots
- Multiple oracle integrations: extend support to other oracle networks in the Stellar ecosystem to cover non-crypto markets.
- User analytics dashboard: build a richer dashboard so users can track their betting history, PnL, and statistics.
- Liquidity provision: incentivize liquidity providers to seed markets with more capital, reducing slippage for bettors.
- Decentralized governance (DAO): introduce governance tokens so the community can decide platform fees and new market types.
- Automated backend tests: the contracts have a Rust test suite, but the API currently has no test runner configured.
Released under the MIT License — you are free to use, copy, modify, and distribute this project, including commercially, as long as the copyright notice is preserved.
The software is provided "as is", without warranty of any kind. Prediction markets that handle real funds are regulated differently across jurisdictions; if you deploy this to mainnet, that compliance is your responsibility.


