Terrace Architecture

On-chain football prediction markets · Solana · Full stack monorepo

Demo Video
🎬
Demo video coming soon
Replace the YOUTUBE_VIDEO_ID in the source with your YouTube video ID to embed the demo.
https://www.youtube.com/watch?v=YOUR_VIDEO_ID
Bet Types & On-chain Architecture
🎯 Single Market Bet
Binary Yes/No prediction on any open market.

place_bet(outcome, stake)
BetPDA
Market Vault (USDC ATA)

Market PDA BetPDA USDC Settlement
🔗 Parlay (2–8 Legs)
Chain multiple market outcomes. All legs must win for payout. Multiplied return.
create_parlay(legs[], stake)
Parlay PDA
settle_parlay
claim_parlay

Parlay PDA Parlay Vault remaining_accounts
⚔️ 1v1 Matchup
Challenge any wallet to a head-to-head on a market outcome. Both stake USDC; winner takes the pot.
challenge(market, outcome, stake)
accept_challenge
settle_matchup

Matchup PDA Matchup Vault challenger + opponent
⚡ Flash Market
Short-duration in-match markets. Same Market PDA with is_flash=true flag. Expires within minutes of creation.

is_flash: true Market PDA Short TTL
Arcium Private Market (Arcium)
Encrypted bet amounts via MPC. Positions are hidden until settlement — prevents front-running.
init_private_market_state
place_private_bet
reveal_private_market

Arcium MPC PrivateMarketState PDA encrypted_totals
Arcium Private Group Leagues
Weekly leaderboard competitions across a shared pool of markets. Private group entry with Arcium-encrypted standings, scored on encrypted data and revealed at settlement.

League PDA Arcium Private Compute USDC Prize Pool
Arcium MPC · Shipped Updates
Arcium
Encrypted picks. Private leaderboards. Verifiable settlement.
Live on devnet via arcium_anchor + arcium_macros, with RescueCipher / x25519 encryption end-to-end.
Private Markets (create + bet) Shipped
init_private_market_state + place_private_bet store positions as Enc<Shared, T> ciphertexts. Settlement vault wired to USDC.
Reveal + Settle Flow Shipped
reveal_private_market queues an Arcium computation that decrypts aggregates only. End-to-end script: reveal-then-settle runs the full lifecycle.
Private Group Leagues Shipped
Weekly leagues where every participant's picks are encrypted. Scoring runs on encrypted data, so the leaderboard is provably fair without anyone reading bets.
RescueCipher Verification Shipped
verify-rescue-cipher script validates client-side encryption matches the Arcis circuit expectations. Catches ciphertext mismatches before they hit the MPC cluster.
Devnet Scripts Shipped
create-private-markets, reveal-private-markets, settle-private-markets — reproducible end-to-end harness for the whole encrypted bet lifecycle.
App + SDK Integration In Progress
Mobile app hooks (usePrivateMarket, useLeague) talk to the SDK encryption layer. Wallet-bound x25519 keys handle the client side. Polish round before mainnet.
On-chain Programs — packages/programs (Anchor 0.30)
graph LR subgraph PROG["Terrace Program · 8dDXHX1x6didMogjFcMCNL6ZoY4XkP2RkSCKcCiaQssF"] direction TB subgraph MARKET["Market Instructions"] CM["create_market\n(question, expiry, is_flash, is_private)"] PB["place_bet\n(outcome, stake_usdc)"] SM["settle_market\n(outcome)"] CM --> PB --> SM end subgraph PARLAY_IX["Parlay Instructions"] CP["create_parlay\n(legs[], stake_usdc, nonce)"] SP["settle_parlay\n(remaining_accounts)"] CL["claim_parlay"] CP --> SP --> CL end subgraph MATCHUP_IX["Matchup Instructions"] CH["challenge\n(market, outcome, stake)"] AC["accept_challenge"] DEC["decline_challenge"] SET["settle_matchup"] CH --> AC --> SET CH --> DEC end subgraph PRIVATE_IX["Private Market (Arcium)"] IPM["init_private_market_state"] PPB["place_private_bet"] RPM["reveal_private_market"] IPM --> PPB --> RPM end subgraph PDAS["PDAs"] MPDA["Market PDA\n[market, creator, nonce]"] PPDA["Parlay PDA\n[parlay, creator, nonce]"] MUPDA["Matchup PDA\n[matchup, challenger, nonce]"] RPDA["Reputation PDA\n[reputation, wallet]"] PVPDA["PrivateMarketState PDA"] end end ARCIUM["Arcium MPC\narcium_anchor + arcium_macros"] PROG --- ARCIUM style PROG fill:#0a0a0a,stroke:#333,color:#e5e5e5 style MARKET fill:#052e16,stroke:#166534,color:#4ade80 style PARLAY_IX fill:#0c1a2e,stroke:#1e40af,color:#93c5fd style MATCHUP_IX fill:#1e1030,stroke:#6b21a8,color:#c084fc style PRIVATE_IX fill:#1c0505,stroke:#7f1d1d,color:#fca5a5 style PDAS fill:#111,stroke:#333,color:#ccc style ARCIUM fill:#1c0505,stroke:#7f1d1d,color:#fca5a5
Monorepo Packages — pnpm workspaces + Turborepo
📱 packages/app
React Native · Expo SDK 54 · Solana Mobile Stack

HomeScreen BetSheet ParlayBuilderScreen MatchupScreen ProfileScreen SocialScreen
useParlay useMatchup useFollowing useHeliusEvents useWallet usePushNotifications
⚙️ packages/sdk
@terrace/sdk · @solana/kit (not web3.js v1)

buildPlaceBetInstruction buildCreateParlayInstruction buildChallengeInstruction buildAcceptMatchupInstruction buildSettleMatchupInstruction Jupiter swap helpers deserializeMarketAccount deserializeParlayAccount deserializeMatchupAccount
Telegram packages/telegram-bot
Grammy · Node.js

/bet /me /sharp /challenge /link /league /wallet
Gemini AI 2.0 Flash\nreputation narratives Worker API calls On-chain reputation lookup
☁️ packages/notifications-worker
Cloudflare Workers · Hono

POST /api/link-token POST /link/verify GET /link/:token POST /api/notify GET /api/wallet/tg/:id
KV: link_token:{uuid} KV: tg_wallet:{tgId} KV: wallet_tg:{pubkey} KV: device:{pubkey}
Data & Event Flow
flowchart TD USER["👤 Fan (Mobile App)"] TG_USER["💬 Fan (Telegram)"] subgraph APP["📱 Mobile App"] HOOKS["React hooks\nuseParlay · useMatchup\nuseFollowing · useHeliusEvents"] SDK2["@terrace/sdk\nbuildInstruction helpers"] WALLET["Wallet Layer\nPrivy embedded · MWA/Phantom"] end subgraph INFRA["Infrastructure"] WORKER2["☁️ Cloudflare Workers\nREST API + KV"] KV2["Cloudflare KV\nWallet↔TG identity\nDevice push tokens"] end subgraph BOT["💬 Telegram Bot"] GRAMMY["Grammy handlers\n/bet /me /challenge /link"] GEMINI2["Gemini AI 2.0 Flash\nReputation narrative"] end subgraph CHAIN["⛓️ Solana Devnet"] PROGRAM2["Terrace Program\nAnchor 0.30"] HELIUS2["Helius RPC\n+ Websockets"] JUPITER2["Jupiter\nSwap aggregation"] ARCIUM2["Arcium MPC\nPrivate compute"] end subgraph EXTERNAL["External Data"] POLY["Polymarket\nMarket depth + liquidity"] PUSH["Push Notifications\nExpo / FCM / APNs"] end USER --> APP TG_USER --> BOT APP --> SDK2 --> WALLET --> PROGRAM2 APP --> HELIUS2 HOOKS --> HELIUS2 HELIUS2 -- "Real-time\non-chain events" --> HOOKS PROGRAM2 -- "PDAs · Vaults" --> HELIUS2 PROGRAM2 <--> ARCIUM2 SDK2 --> JUPITER2 BOT --> WORKER2 WORKER2 --> KV2 WORKER2 --> HELIUS2 GRAMMY --> GEMINI2 WORKER2 -- "deep link\n/link/:token" --> USER WORKER2 -- "DM via\nBot API" --> TG_USER HELIUS2 -- "settlement\nevents" --> WORKER2 WORKER2 --> PUSH --> USER POLY -- "day-one\nliquidity" --> APP style APP fill:#0c1a2e,stroke:#1e40af,color:#93c5fd style INFRA fill:#1c1300,stroke:#92400e,color:#fde68a style BOT fill:#1a1a0a,stroke:#713f12,color:#fcd34d style CHAIN fill:#052e16,stroke:#166534,color:#86efac style EXTERNAL fill:#1e1030,stroke:#6b21a8,color:#d8b4fe
Social & Identity Layer
🏅 On-chain Reputation PDA
Stored on Solana. Immutable, wallet-bound.

win_rate
total_bets
wins
badge_tier
streak
creator_revenue

Gemini AI narrates stats Composable across app + TG
👥 Follow / Unfollow
Follow sharpest bettors. Their market activity appears in your social feed.

useFollowing hook useFollowedSources hook useTerraceUsers hook

Helius websockets stream followed wallets' on-chain activity in real time. Cloudflare Workers push a notification on every placement or win.
🔗 Wallet ↔ Telegram Linking
One identity across app and group chat.

/link in TG
link_token (KV, 15m TTL)
Deep link opens app
App POSTs /link/verify
KV: tg_wallet + wallet_tg
TG DM confirms

Cloudflare KV Intent URL (Android) terrace:// deep link (iOS)
Integrations
Helius
RPC provider + websocket event streaming. Powers real-time market feed, settlement detection, and notification triggers.

devnet RPC getProgramAccounts accountSubscribe WS
🪐 Jupiter
Swap aggregation. Fans don't need USDC pre-loaded — Jupiter converts any token to USDC at bet time.

Swap API getQuote Token → USDC
Arcium Arcium
Multi-party computation for private markets. Bet positions encrypted until settlement — prevents front-running.

arcium_anchor crate arcium_macros 3 computation definitions
Gemini Gemini AI
2.0 Flash via REST API. Generates punchy 2–3 sentence reputation narratives for Telegram /me and /sharp commands.

gemini-2.0-flash REST API Natural language rep
Privy Privy
Embedded wallet + email auth. Abstracts seed phrases for non-crypto-native fans. Fallback to MWA/Phantom for power users.

Embedded wallet Email login useEmbeddedSolanaWallet
Solana Mobile Solana Mobile Stack
MWA protocol for native signing via Phantom, Seed Vault, and other MWA-compatible wallets on Android.

MWA v2 transact() signTransactions
☁️ Cloudflare Workers + KV
Edge backend for push notifications, wallet-TG identity linking, deep link routing, and internal bot API.

Workers (edge) KV (key-value store) wrangler.toml
Polymarket Polymarket
External prediction market source. Surfaces Polymarket markets in the app feed alongside native markets for day-one liquidity depth.

Unified market feed source: "polymarket" Day-one depth
Build & Deploy
📦 EAS (Expo Application Services)
preview profile → APK production → AAB OTA updates

Custom URL scheme terrace:// registered natively for deep links. Adaptive icon + splash configured.
⚙️ Turborepo + pnpm workspaces
packages/app packages/sdk packages/programs packages/telegram-bot packages/notifications-worker packages/landing
Solana Anchor + Solana
Anchor 0.30 Devnet deployed @solana/kit (not web3.js v1) USDC devnet mint

Program: 8dDXHX1x6didMogjFcMCNL6ZoY4XkP2RkSCKcCiaQssF