One Solana program, three protocols.
The duel program mints outcome tokens, holds the USDC behind them and settles from Pyth. Trading runs in Meteora DAMM v2 pools against xStocks.
Why Solana
Atomic
One transaction, two swaps
A bet is two Meteora swaps in one Solana transaction. Both fill or nothing moves.
Fees
Fractions of a cent
Cheap enough to pay every holder their share of the fees, pro rata, a few times a day.
Speed
400 ms blocks
A swap confirms in about a second and the odds on the board move with it.
Tokens
Plain SPL tokens
YES, NO and xStocks show in any wallet and route through any Solana aggregator.
01
Mint a set
mint_set takes one USDC into the vault and returns one YES plus one NO. merge_set reverses it. A set always redeems for exactly one USDC.
02
Trade through the stock
YES trades against AAPLx and NO against NVDAx in Meteora pools that keep their fee in the stock. A bet is one Solana transaction: USDC to AAPLx, AAPLx to YES.
03
Read the odds
No order book. Each side's dollar price is its pool price times the stock's Pyth price, and the board scales the two to add up to one. Drift past a cent and minting or merging a set pulls it back.
yes_raw = P(YES in AAPLx) × P(AAPLx in USD) no_raw = P(NO in NVDAx) × P(NVDAx in USD) odds = yes_raw / (yes_raw + no_raw)
04
Fees become rewards
A crank claims each pool's fees, deposits them with deposit_rewards and pays every holder pro rata with distribute, 12 per call. Fees never leave the stock.
05
Settle from Pyth
After resolve_ts anyone posts the Pyth prices and calls resolve. The program checks the feed ids and a six-hour freshness window, then the template picks the winner. A quiet feed past the grace period falls back to the resolver.
Cap compare
price_a × shares_a > price_b × shares_b
Outperform
price_a / price_b > start_ratio
Price above
price > threshold
06
Redeem
redeem burns winning tokens for one USDC each. The losing token is worth zero. Any stock you were paid along the way stays yours.
Nine instructions
Everything the program does is mint, burn, transfer and read a Pyth account. The AMM, the oracle and the stock issuer are not ours.
| Instruction | Signer | Effect |
|---|---|---|
| create_market | anyone | Market PDA, YES and NO mints, collateral vault, two reward vaults. |
| set_pools | creator, once | Records the two Meteora pool addresses. |
| mint_set | anyone | USDC in, the same amount of YES and NO out. |
| merge_set | anyone | Burns a YES and a NO per USDC returned. |
| resolve | anyone, after resolve_ts | Reads the Pyth accounts, stores the winner. |
| resolve_manual | resolver, after the grace period | Stores the winner from printed prices. |
| redeem | anyone, once resolved | Burns winning tokens, pays one USDC each. |
| deposit_rewards | anyone | Moves stock tokens into a reward vault. |
| distribute | crank | Pays up to 12 holders, emits RewardsPaid. |
On devnet, USDC, AAPLx and NVDAx are mock mints. The registry maps each to its mainnet xStocks mint and the program runs unchanged.
Risks
Not available everywhere
Versus is not offered to persons in the United States or in any other restricted jurisdiction. Do not use it where prediction markets or tokenised stocks are not permitted.
Outcome tokens can go to zero
The losing side redeems for nothing at the bell. Only put in what you can lose in full.
Rewards are other traders' fees
Stock payouts are a redistribution of trading fees, not yield or interest. They depend on volume and can be small or nothing.
Stock tokens have an issuer
xStocks can be paused, frozen or seized by their issuer, including inside the pools and reward vaults. Collateral is USDC, so the one-dollar redemption is not affected.
Resolution has a fallback
Pyth prices decide each duel. If a feed is stale past the grace period, the resolver settles manually with the published prices.
Not advice
Nothing here is legal, tax or investment advice. Devnet and localnet use mock tokens with no value.
Ready when you are.
The board is live. Pick a side and the odds move with you.