A production-grade decentralized prediction market application built on BNB Chain, upgraded with GenLayer AI analysis and an Apple-inspired design system.
Trade prediction markets. Analyze with AI. Own your positions.
- Features
- Architecture
- Tech Stack
- Prerequisites
- Getting Started
- Environment Variables
- GenLayer Contract Deployment
- Project Structure
- API Reference
- How to Use
- Security
- Deployment
- Troubleshooting
- License
- Wallet Integration — MetaMask, WalletConnect, Rainbow, Coinbase Wallet via RainbowKit
- Market Discovery — Browse active prediction markets with live data
- Limit Orders — Buy/sell shares at your price with full order lifecycle
- Portfolio Management — View positions, track P&L, redeem winnings
- Smart Approvals — Automatic ERC-20 and ERC-1155 token approvals via SDK helpers
- NegRisk & Yield-Bearing — Full support for advanced market types
- Redeem Positions — One-click redemption of winning positions via SDK helper
- Real Intelligent Contract — Deployed GenLayer Python contract with native LLM access
- Optimistic Democracy Consensus — Multiple AI validators reach agreement on analysis
- Structured Output — Sentiment, confidence score, risk level, key factors, recommendations
- Native GEN Payments — Pay for analysis in GenLayer's native token
- On-Chain History — All analyses stored permanently on GenLayer with analyst attribution
- MetaMask Integration — Separate wallet connection for GenLayer studionet
- Apple-Inspired UI — Minimal, premium aesthetic with cinematic section pacing
- Glass Navigation — Translucent blur nav bar (
backdrop-filter: blur(20px)) - Typography — Inter font with Apple-style optical sizing and negative tracking
- Responsive — Optimized from 320px mobile to 1440px+ desktop
- Accessibility — ARIA labels, focus rings, semantic HTML, reduced-motion support
┌─────────────────────────────────────────────────────────────────────────────┐
│ FRONTEND (React 19) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ │
│ │ MarketsList │ │ TradeModal │ │ AnalyzeModal │ │ UserPositions │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └────────┬────────┘ │
│ │ │ │ │ │
│ ┌──────▼───────┐ ┌──────▼───────┐ ┌──────▼───────┐ ┌────────▼────────┐ │
│ │ predictAPI │ │ usePredictSDK│ │ useGenLayer │ │ usePredictSDK │ │
│ │ (REST) │ │ (OrderBuilder│ │ (writeContract│ │ (redeemPositions│ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └────────┬────────┘ │
│ │ │ │ │ │
└─────────┼─────────────────┼──────────────────┼────────────────────┼──────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ predict.fun │ │ BNB Chain │ │ GenLayer │ │ BNB Chain │
│ REST API │ │ Mainnet │ │ Studionet │ │ Mainnet │
│ │ │ │ │ │ │ │
│ /markets │ │ Conditional │ │ MarketAnaly-│ │ Conditional │
│ /orders │ │ Tokens │ │ zer Contract│ │ Tokens │
│ /positions │ │ CTF Exchange│ │ (Python IC) │ │ CTF Exchange│
│ /auth │ │ USDT │ │ │ │ USDT │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
| Layer | Technology |
|---|---|
| Framework | React 19 + TypeScript 5.9 |
| Build Tool | Vite 7 |
| Web3 (BNB) | Wagmi 2 + RainbowKit 2 + Viem 2 |
| Web3 (GenLayer) | genlayer-js 1.1.2 |
| SDK | @predictdotfun/sdk 1.2.4 |
| Ethers | ethers v6 (peer dependency of Predict SDK) |
| Styling | Custom CSS (Apple Design System) |
| State | React Hooks + Context API |
| Linting | ESLint 9 + typescript-eslint |
- Node.js 18+ and npm
- MetaMask browser extension
- BNB tokens for gas fees on BNB Chain Mainnet
- USDT on BNB Chain for trading
- GEN tokens on GenLayer for AI analysis (get from GenLayer Faucet)
- Predict.fun API Key (join Discord and request in #api-access)
git clone https://github.com/PhiBao/predictify.git
cd predictify
npm installcp .env.example .envEdit .env with your credentials:
# Required — Predict.fun
VITE_WALLETCONNECT_PROJECT_ID=your_walletconnect_project_id
VITE_API_KEY=your_predict_api_key
# Required — GenLayer AI Analysis
VITE_GENLAYER_RPC=https://studio.genlayer.com/api
VITE_GENLAYER_ANALYSIS_CONTRACT=0xYOUR_DEPLOYED_CONTRACT_ADDRESSGet credentials:
- WalletConnect Project ID: cloud.walletconnect.com
- Predict API Key: Join Discord → open support ticket
- GenLayer Contract: Deploy the included contract (see below)
npm run devnpm run build
npm run preview| Variable | Required | Description |
|---|---|---|
VITE_WALLETCONNECT_PROJECT_ID |
Yes | WalletConnect Cloud project ID |
VITE_API_KEY |
Yes | Predict.fun REST API key |
VITE_GENLAYER_RPC |
No | GenLayer RPC endpoint (default: https://studio.genlayer.com/api) |
VITE_GENLAYER_ANALYSIS_CONTRACT |
Yes | Deployed MarketAnalyzer contract address |
The app includes a real GenLayer Intelligent Contract for AI market analysis.
This contract uses GenLayer v0.1.x syntax (compatible with Studio):
- Accepts native GEN payments (
@gl.public.write.payable) - Uses
gl.nondet.exec_prompt()for LLM market analysis - Runs
gl.vm.run_nondet_unsafe()for Optimistic Democracy consensus - Stores results on-chain in
TreeMap - Returns structured JSON with sentiment, confidence, risk, factors
- Open GenLayer Studio
- Create a new contract and paste the contents of
contracts/MarketAnalyzer.py - Deploy the contract — Studio will assign an address
- Copy the contract address into your
.env:VITE_GENLAYER_ANALYSIS_CONTRACT=0x09c7fF6DbaF4dA1A826eCa3B2D46cF11Dab9f064
- Get GEN tokens from the Studio faucet for testing
# Install GenLayer CLI
npm install -g genlayer
# Login
genlayer login
# Select network
genlayer network
# → Choose studionet
# Deploy
genlayer deploy contracts/MarketAnalyzer.py| Method | Type | Description |
|---|---|---|
analyze_market(question, description, outcomes) |
write.payable |
Submit market for AI analysis (costs GEN) |
get_analysis(id) |
view |
Retrieve stored analysis by ID |
get_analysis_count() |
view |
Total analyses performed |
get_min_fee() |
view |
Current minimum fee in wei |
set_min_fee(new_fee) |
write |
Update minimum fee |
{
"sentiment": "bullish",
"confidence": 75,
"summary": "Market indicators suggest a favorable outcome...",
"key_factors": ["Increasing social engagement", "Strong on-chain metrics"],
"risk_level": "medium",
"recommended_action": "Consider taking a position",
"timestamp": "2026-04-24T12:00:00Z",
"analyst": "0x..."
}predictify/
├── contracts/
│ └── MarketAnalyzer.py # GenLayer Intelligent Contract
├── src/
│ ├── components/
│ │ ├── AnalyzeModal.tsx # GenLayer AI analysis modal
│ │ ├── MarketCard.tsx # Market card with analyze button
│ │ ├── MarketSkeleton.tsx # Skeleton loading states
│ │ ├── MarketsList.tsx # Market grid + fetch logic
│ │ ├── ScrollToTop.tsx # Floating scroll-to-top button
│ │ ├── SellModal.tsx # Sell position modal
│ │ ├── Toast.tsx # Notification component
│ │ ├── TradeModal.tsx # Buy/sell trade modal
│ │ ├── UserPositions.tsx # Portfolio + claim winnings
│ │ └── WalletConnect.tsx # RainbowKit connect button
│ ├── contexts/
│ │ └── ToastContext.tsx # Global toast notifications
│ ├── hooks/
│ │ ├── useGenLayer.ts # GenLayer analysis hook
│ │ └── usePredictSDK.ts # OrderBuilder initialization
│ ├── lib/
│ │ └── genlayer/
│ │ ├── client.ts # GenLayer client + MetaMask helpers
│ │ └── WalletProvider.tsx # GenLayer wallet React context
│ ├── services/
│ │ ├── genlayer.ts # Real GenLayer contract service
│ │ └── predictAPI.ts # Predict.fun REST API client
│ ├── types/
│ │ └── predict.ts # TypeScript definitions
│ ├── config/
│ │ └── wagmi.ts # Wagmi + RainbowKit configuration
│ ├── App.tsx # Main app shell
│ ├── App.css # Apple Design System styles
│ ├── index.css # Global design tokens
│ └── main.tsx # Entry point
├── .env.example # Environment template
├── vite.config.ts # Vite config with API proxy
└── README.md # This file
Base URL (proxied via Vite): /api → https://api.predict.fun/v1
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/markets |
GET | API Key | List markets |
/markets/:id |
GET | API Key | Get market details |
/orderbook/:id |
GET | API Key | Get orderbook |
/positions |
GET | JWT | Get user positions |
/orders |
GET | JWT | Get user orders |
/orders |
POST | JWT | Create order |
/orders/cancel |
POST | JWT | Cancel orders |
/auth/message |
GET | API Key | Get auth message |
/auth |
POST | API Key | Get JWT token |
// Initialize (once per signer)
const orderBuilder = await OrderBuilder.make(ChainId.BnbMainnet, signer);
// Set all approvals
await orderBuilder.setApprovals();
// Calculate amounts
const amounts = orderBuilder.getLimitOrderAmounts({ side, pricePerShareWei, quantityWei });
// Build, sign, and hash order
const order = orderBuilder.buildOrder('LIMIT', { maker, signer, side, tokenId, makerAmount, takerAmount, nonce, feeRateBps });
const typedData = orderBuilder.buildTypedData(order, { isNegRisk, isYieldBearing });
const signedOrder = await orderBuilder.signTypedDataOrder(typedData);
const hash = orderBuilder.buildTypedDataHash(typedData);
// Redeem positions
await orderBuilder.redeemPositions({ conditionId, indexSet, isNegRisk, isYieldBearing });
// Merge positions
await orderBuilder.mergePositions({ conditionId, amount, isNegRisk, isYieldBearing });// Create client with MetaMask account
const client = createGenLayerClient(metaMaskAddress);
// Write to contract (sends tx, returns hash)
const txHash = await client.writeContract({
address: contractAddress,
functionName: 'analyze_market',
args: [question, description, outcomes],
value: feeWei,
});
// Poll for transaction status
const tx = await client.getTransaction({ hash: txHash });
// Status: PENDING → PROPOSING → COMMITTING → REVEALING → ACCEPTED → FINALIZED- Connect Wallet — Click "Connect Wallet" in the top right
- Browse Markets — Scroll to the Markets section
- Select Outcome — Click any outcome button on a market card
- Set Price & Quantity — Enter your desired price (0.01–0.99 USDT) and share count
- Approve & Submit — The app auto-approves tokens and submits your order
- View Positions — Go to "Your Positions" to track holdings
- Find a Market — Any market card has an "Analyze with GenLayer" button
- Connect GenLayer — The modal will prompt you to connect MetaMask to GenLayer Studio
- Enter Fee — Minimum 1 GEN (adjustable by contract owner)
- Submit — The transaction is sent to GenLayer validators
- Wait for Consensus — Leader proposes, validators verify, result is finalized
- Review Results — Sentiment, confidence bar, key factors, risk level, recommendation
- Wait for Resolution — Markets resolve when the outcome is known
- Go to Positions — Winning positions show a green "Winner" badge
- Click Claim — Uses SDK's
redeemPositions()helper for one-click redemption
This codebase follows security best practices from Nemesis Auditor and Pashov Audit Group:
- Input Validation — All user inputs validated before use
- Error Handling — Comprehensive try/catch with meaningful messages
- Type Safety — Strict TypeScript, explicit interfaces, minimal
any - Effect Cleanup — Cancellation flags prevent race conditions in async effects
- No Secrets in Code — All sensitive config in
.env - Sanitized Outputs — No raw HTML injection, safe DOM operations
- ConditionalTokens:
0x22DA1810B194ca018378464a58f6Ac2B10C9d244 - CTF Exchange:
0x8BC070BEdAB741406F4B1Eb65A72bee27894B689 - NegRisk CTF Exchange:
0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E - USDT:
0x55d398326f99059fF775485246999027B3197955
- Push to GitHub
- Import in Vercel
- Add environment variables:
VITE_WALLETCONNECT_PROJECT_IDVITE_API_KEYVITE_GENLAYER_RPCVITE_GENLAYER_ANALYSIS_CONTRACT
- Deploy
The vercel.json and vite.config.ts already include API proxy rewrites to avoid CORS.
| Issue | Solution |
|---|---|
| Build fails | Check Node.js 18+. Run npm install |
| Wallet won't connect (BNB) | Verify you're on BNB Chain Mainnet (Chain ID 56) |
| Wallet won't connect (GenLayer) | Add GenLayer Studio network in MetaMask (Chain ID 61999, RPC: https://studio.genlayer.com/api) |
| Order fails | Ensure sufficient BNB for gas + USDT for trade. Check approvals succeeded |
| GenLayer analysis fails | Ensure wallet is connected to GenLayer network. Check GEN balance. Verify contract address is set |
| Positions not showing | Wait a few seconds after order confirmation. Refresh page |
| CORS errors | The dev server proxies /api to Predict.fun. In production, ensure Vercel rewrites are configured |
- Predict.fun
- Predict Docs
- Predict TypeScript SDK
- GenLayer Docs
- GenLayer JS SDK
- GenLayer Python SDK API
- Gotham Court Reference
MIT
Made with precision for the prediction markets community.