Skip to content
umara25Public

About

Winner @ Hack the Hill III, Paired prediction duels with tokenized stocks on Solana

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

51 Commits

Folders and files

Repository files navigation

Versus

Back a side. Get paid in what it is made of.

A duel is a head-to-head question with a date on it: "Will Apple be more valuable than Nvidia on December 31, 2026?" Two sides, YES and NO, each fully backed by USDC. Bet Apple and the fee on your trade is collected in tokenized Apple stock and paid to everyone holding the Apple side. Bet Nvidia, get paid in Nvidia. On the date, Pyth reads both prices, the winner redeems for one USDC a token, and the loser keeps the shares it was paid. One small Anchor program plus Meteora DAMM v2, Pyth, and xStocks.

How it works

  1. mint_set takes 1 USDC and mints 1 YES plus 1 NO; merge_set reverses it.
  2. YES trades in a Meteora DAMM v2 pool against AAPLx, NO against NVDAx. Both pools collect their fee in the stock token only.
  3. A crank claims each pool's fees, deposits them into that side's reward vault, snapshots holders, and pays out pro-rata in the stock token.
  4. After resolve_ts, anyone calls resolve with posted Pyth PriceUpdateV2 accounts. Price times stored share count decides it. Winning tokens redeem for one USDC each.

Details: docs/ARCHITECTURE.md.

Repo map

Path What Status
programs/duel Anchor 0.32.1 program, ID AN2TEyFH3zCsv5MENn2uo9LJx69J2EUC8iScAVeDbW25 Built in WSL; 39 mocha and 10 unit tests pass
packages/sdk TypeScript client: program, pools, Pyth, routing, odds, rewards, registry Verified on localnet
scripts validator, bootstrap, bet, crank, resolve, faucet, smoke Verified on localnet
apps/web Next.js 15 app: landing, board, duel, create, positions, how it works Complete; chain adapter in integration
docs Architecture, pitch, submission, prior art Written

Run it

Rust and Solana tooling in WSL Ubuntu; Node 22 and pnpm 9 on Windows. Cold start on localnet:

pnpm install

# terminal 1: validator, mainnet clones of DAMM v2 and Pyth, duel preloaded
pnpm --filter scripts validator -- --run --rpc-port 8999

# terminal 2: mock mints, pools, three duels, one resolvable test market
export RPC_URL=http://127.0.0.1:8999
pnpm --filter scripts bootstrap -- --with-test-market

# terminal 3: web app in chain mode
NEXT_PUBLIC_DEPLOYMENT=localnet NEXT_PUBLIC_RPC_URL=http://127.0.0.1:8999 pnpm --filter versus-web dev

# terminal 2, after a few bets: pay holders
pnpm --filter scripts crank -- --once

Open http://localhost:3000. On localnet and devnet the wallet picker offers a Burner test wallet, no extension needed; the rail faucet mints mock USDC. scripts/README.md has the full CLI run-through: bet, sell, ledger, resolve --manual, redeem. Stop the validator with wsl -d Ubuntu -- pkill -f solana-test-validator.

Demo mode. NEXT_PUBLIC_DEMO=1 pnpm --filter versus-web dev renders every route from fixtures with ticking odds and no network. Default on a fresh checkout.

Deploy

Every push deploys through GitHub Actions (.github/workflows/deploy.yml) with one shared Vercel token, so any collaborator's commit deploys, not only the Vercel project owner's. main goes to production; any other branch gets a preview URL in the run summary.

One-time setup by the Vercel project owner, who also needs admin on this repo:

vercel login
vercel link                                          # at the repo root; writes .vercel/project.json (gitignored)
gh secret set VERCEL_ORG_ID -R aayusha59/Versus      # paste orgId from .vercel/project.json
gh secret set VERCEL_PROJECT_ID -R aayusha59/Versus  # paste projectId from .vercel/project.json
gh secret set VERCEL_TOKEN -R aayusha59/Versus       # paste a token from vercel.com/account/tokens

Then disconnect the Git integration in the Vercel project (Settings, Git, Disconnect) so Vercel stops deploying alongside Actions. Env vars stay in the Vercel project settings; the workflow pulls them at build time.

Status

  • Program built and tested (39 mocha, 10 unit); IDL committed to packages/sdk/idl.
  • SDK and scripts verified end to end on localnet (Agave 3.0.13, Sept 26, 2026).
  • Web app complete, with a chain adapter and Burner wallet.
  • Deployed on devnet: the program, three duels, six outcome pools, and test markets. packages/sdk/deployments/devnet.json lists them. A Bitcoin vs Ethereum test market has been settled through Pyth on devnet, and another is left open for the demo:
RPC_URL=https://api.devnet.solana.com pnpm --filter scripts resolve -- --market 5AhqSroPQ2uZ7fB23huAzeFPfpeB22Hok8odV1DF9hE5

Known limits

  • The operator wallet owns the Meteora LP positions and claims their fees; duels created in the web app hand their positions to it.
  • Rewards accounting is off-chain; the payout is on-chain through distribute, which checks the crank key and the vault balance.
  • resolve_manual by the resolver after resolve_ts + grace_secs is the fallback for stale feeds.
  • Hermes now requires an API key (PYTH_API_KEY), and the key must be entitled to each feed. Crypto feeds settle through plain resolve; US equity feeds need a plan that includes them, otherwise resolve --manual.
  • xStocks are mocked on devnet and localnet; the registry maps each mock to its mainnet mint.
  • Share counts for CapCompare are placeholders set at creation.

Upgrade path for each: docs/ARCHITECTURE.md §8.

Docs

License

MIT. See LICENSE.

Disclaimer

Not offered in restricted jurisdictions, including the United States. Outcome tokens can go to zero. Fee rewards are a redistribution of other traders' fees. xStocks can be paused or seized by their issuer. Not legal or investment advice.

About

Winner @ Hack the Hill III, Paired prediction duels with tokenized stocks on Solana

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages