XBETPhilosophy · Protocol · Security · Anti-gaming · Oracles
This document describes the conceptual and technical foundations of XBET: a prediction exchange where the underlying outcome is view count on X (Twitter). Written for developers and protocol designers. No hand-holding.
XBET is not “bet on a number.” It is a virality exchange. The tradable object is will this post go viral within a time window? — with “viral” defined as crossing a view-count threshold. The oracle is deterministic: we use public view counts. No Twitter API, no trusted third party for the number itself; the only trust is in how we fetch and when we snapshot.
Design constraints we enforce: (1) markets are tied to a single tweet and a fixed window (e.g. 24h); (2) settlement is binary (YES/NO) against a baseline; (3) liquidity is pooled per market (CPMM-style exposure); (4) early liquidity and information are rewarded — you are trading information about virality before it’s obvious.
Markets. A market is identified by (tweetId, windowHours). Creation costs 0.05 SOL to the treasury; baseline views and multiplier define the threshold. Off-chain we store market metadata and aggregate bets; on-chain we have program accounts for vaults and positions where applicable.
Bets (current flow). In the quick-trade path, users send SOL to the treasury in one or two transfers: one for the stake (registered as the “bet”), one for the 2% protocol fee. The server verifies the transfer via verifyBetPayment(txSignature, user, pool, amountLamports) and appends a bet record keyed by (marketId, user, side, amountLamports). Positions are the sum of non-sold bets per (user, market, side).
Sell (exit). Selling is an off-chain operation: the backend computes position size, sends SOL from the treasury to the user, and marks the corresponding bets as sold (soldAt). No on-chain position closure in the current minimal design — treasury is the counterparty. So: we trust the server to pay out; the security is in correct accounting and treasury key handling.
// Store: position = sum of bet.amountLamports where soldAt == null
export function getPositionLamports(marketId, user, side) {
return getBets()
.filter(b => b.marketId === marketId && b.user === user && b.side === side && b.soldAt == null)
.reduce((s, b) => s + b.amountLamports, 0);
}Creating a market. To list a new market (tweet + window + target views), the creator pays a one-time 0.05 SOL to the treasury. The tx is verified on-chain; then the server registers the market. No refund. The creator becomes the “owner” of that market for fee-sharing (see below).
Trade fee (site fee). On every bet, the user is debited 2% of the stake on top of the stake itself. Example: to bet 1 SOL, the user sends 1 SOL (stake) + 0.02 SOL (fee) = 1.02 SOL. Only the 1 SOL is counted as position; the 0.02 SOL is the protocol fee. All of it goes to the treasury today; from there, shares can be attributed to creators and referrers (see Referral).
Who receives what. (1) Treasury — receives the full 0.05 SOL per market creation and the full 2% on every trade; it is the single collector. (2) Market creator — earns 25% of the fees generated by the site on that market (i.e. 25% of the 2% collected on trades on their market). (3) Referrer — when a user was referred, the referrer earns a bonus on first bet and a cut of fees on that user’s trades (see Referral). The rest stays in the treasury (protocol / ops).
So: creation = 0.05 SOL to treasury. Each trade = 2% to treasury; from that pool, creators and referrers get their share (25% per market for creator, referral cut for referrer). No fee on sell — only on the initial bet.
Users can generate a referral code (Personal Space) and share it. When a new user signs up or trades with that code attached, the referrer is rewarded.
Rewards. (1) When the referred user’s first bet reaches the equivalent of $50 in volume, the referrer earns $15 (one-time bonus). (2) On all subsequent activity, the referrer earns 20% of the fees generated on that referred user’s trades (i.e. 20% of the 2% = 0.4% of the referred user’s stake, in value).
Referral balance is tracked off-chain (or via a future token/claim flow) and displayed in Personal Space. The referred user enters the code once; the link wallet → referrer is stored so that all their trades count toward the referrer’s 20% fee share. No referral = no bonus; the 2% trade fee still goes to the treasury (and to market creators on their markets as above).
Payment verification. Every bet and market creation is gated by a verified on-chain transfer. We fetch the transaction by signature, parse instructions, and require an exact match: from = payer, to = treasury, amount = expected lamports. Double-spend is prevented by the uniqueness of the tx signature we store and the fact we only accept “confirmed” finality.
Treasury. The treasury keypair is server-side only (TREASURY_SECRET_KEY). It receives creation fees, the 2% trade fee, and pays out on sell. No program-derived logic touches this key — it’s a hot wallet under our control. Best practice: separate hot/cold and monitor balances.
No Twitter API. We do not rely on Twitter’s API for settlement. View counts are read from public endpoints or scraped in a way that does not require API keys. That removes API rate limits and key leakage from the trust model; the remaining risk is “what number did we actually see at cutoff?”
Anything that distorts the information content of the market or thefairness of settlement is in scope. Below we list vectors and mitigations.
Fake volume (wash trading). Users (or bots) trading with themselves to inflate volume or move prices. Mitigations: (1) volume is displayed but not used for rewards in a naive way; (2) we can add heuristics: same-wallet self-trades, rapid flip-flop on the same market, volume from wallets that never hold position. Future: exclude or downweight wallets that fail a “real user” score (e.g. age, diversity of markets, net PnL).
Sybil. Many wallets, one actor. Hard to solve without identity. We can at least cluster by funding source, IP (server-side), and behavior (same markets, same times). Documentation and future work: optional reputation or “verified” badge tied to a minimal proof (e.g. stake, history).
Fake views on X (bot views). The tweet’s view count can be gamed: bot networks, click farms, paid views. If we settle on raw view count, an attacker can buy views to push a YES over the line. Mitigations: (1) View-quality signals — we intend to integrate or model “organic” vs “inorganic” views (e.g. ratio of views to likes/replies, velocity curves, account-age distribution of viewers). (2) Delayed or time-weighted snapshots to smooth spikes. (3) A bot / fake-view detector: internal or third-party service that scores a post’s view count (e.g. “estimated organic views”) and we settle on that score instead of raw count, or we flag markets for manual review. The protocol should be built so that the “oracle value” can be swapped from “raw views” to “adjusted views” without changing the rest of the contract.
Non-viral / low-velocity posts. Markets on tweets that will never realistically hit the threshold create dead liquidity and noise. We already have a bot that discovers and creates markets from X; that same pipeline can filter by minimum engagement, follower count, or trend signals so we only list posts that have a non-trivial chance to go viral. This keeps the product focused and reduces “obvious NO” markets that nobody wants to trade.
Summary. Secured by on-chain payment verification and treasury controls; anti-gaming by design space (binary outcome, no naive volume-based rewards), and by future work: view-quality oracle, sybil heuristics, and listing filters so the system stays robust against fake volume and fake views.
Settlement is the moment we assign YES or NO to a market. Today: we snapshot view count at window end and compare to baseline (and multiplier). The “oracle” is whoever runs the job that (1) fetches the view count, (2) decides the outcome, (3) updates the store (and optionally on-chain state). To make this trust-minimal we want: (1) deterministic fetch (same input → same number), (2) optional multi-source or attestation, (3) a path to “adjusted views” (bot-filtered) as the settlement value.
// Conceptual: settlement
const viewCount = await fetchViewCount(tweetId); // or fetchAdjustedViews(tweetId)
const threshold = baselineViews * multiplier;
const outcome = viewCount >= threshold ? "yes" : "no";
setMarketOutcome(marketId, outcome);GET /api/markets — List markets with aggregated pools (yesSharesSol, noSharesSol, bettor counts). Activity array includes create_market, trade_sol, sell. Used for dashboard and live feed.
POST /api/markets — Register a new market after creator pays 0.05 SOL; body: tweetUrl, tweetId, windowHours, baselineViews, creator, txSignature. Verified via verifyCreationPayment.
POST /api/bets — Register a bet after user sends SOL; body: marketId, user, side, amountLamports, txSignature. Verified via verifyBetPayment (exact transfer amount).
GET /api/bets?user= — Bets for a wallet; used for “my positions” and sell flow.
POST /api/sell — Body: user, marketId, side. Server computes position, sends SOL from treasury to user, marks bets sold, appends to sales for live feed.
XBET — Trade Virality on Solana. No API. Deterministic oracle. Anti-gaming by design.
→ Back to Exchange