dubs-server
v1.0.0
Published
Dubs wager game API server
Readme
🎮 Dubs API Server
Production-ready REST API for Solana wager games with operator fees, multi-game support, and clean architecture.
Quick Links
- Live Devnet API: https://dubs-server-dev-55d1fba09a97.herokuapp.com
- Program ID:
8DJTkgk6MDr6tPtw4v2VzYAz9WWvmCg6786vZrEK3o5q - Solana Explorer: https://explorer.solana.com/address/8DJTkgk6MDr6tPtw4v2VzYAz9WWvmCg6786vZrEK3o5q?cluster=devnet
Environments
Local Development (Localnet)
# Start local validator
solana-test-validator --reset
# Deploy program
cd ../dubs
solana program deploy target/deploy/hello_world.so --url localhost
# Start server
cd ../dubs-server
node server.js
# API: http://localhost:3001
# Network: Localnet (your computer)Devnet Testing (Public Test Network)
# Server already deployed to Heroku!
# API: https://dubs-server-dev-55d1fba09a97.herokuapp.com
# Network: Devnet (public)
# SOL: Free from faucetMainnet Production (Future)
# Deploy program to mainnet
cd ../dubs
solana program deploy target/deploy/hello_world.so --url mainnet-beta
# Deploy server to Heroku
heroku apps:create dubs-api-prod --team dubs
heroku config:set SOLANA_NETWORK=https://api.mainnet-beta.solana.com -a dubs-api-prod
git push heroku-prod main
# API: https://dubs-api-prod.herokuapp.com
# Network: Mainnet (real $$$)API Structure
Production Endpoints (/api/v1/prod)
For real users with Phantom/Solflare/Jelli wallets
GET /api/v1/prod/game/:gameId
POST /api/v1/prod/transaction/build/create
POST /api/v1/prod/transaction/build/join
POST /api/v1/prod/transaction/build/cast-vote 🗳️ NEW!
POST /api/v1/prod/transaction/build/distribute-by-vote 🗳️ NEW!
POST /api/v1/prod/transaction/build/distribute
POST /api/v1/prod/transaction/submitDemo Endpoints (/api/v1/demo)
For testing with server-managed wallets (local only)
GET /api/v1/demo/game/:gameId
GET /api/v1/demo/wallets
POST /api/v1/demo/game/create
POST /api/v1/demo/game/join
POST /api/v1/demo/game/distribute
POST /api/v1/demo/vote/cast 🗳️ NEW!
POST /api/v1/demo/vote/distribute 🗳️ NEW!
POST /api/v1/demo/airdropUsing Production API (Real Wallets)
1. Build Create Game Transaction
curl -X POST https://dubs-server-dev-55d1fba09a97.herokuapp.com/api/v1/prod/transaction/build/create \
-H "Content-Type: application/json" \
-d '{
"creatorAddress": "YOUR_PHANTOM_WALLET_ADDRESS",
"buyIn": 0.5,
"maxPlayers": 4,
"operatorFee": 10,
"operatorAddress": "OPTIONAL_OPERATOR_WALLET"
}'Response:
{
"success": true,
"gameId": "a7d4648b-12b8-43db-9029-728496fb0634",
"transaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAIEPTUQYzFd...",
"gameAddress": "6KSjVmzu9wKnCojhSvgNoojF9z5Pp3qXEygpJN1ft8rp",
"instructions": "Sign this transaction with your wallet..."
}2. Sign Transaction with Phantom
import { Connection, Transaction } from '@solana/web3.js';
// Get unsigned transaction from API response
const unsignedTxBase64 = response.transaction;
// Decode transaction
const txBuffer = Buffer.from(unsignedTxBase64, 'base64');
const tx = Transaction.from(txBuffer);
// Sign with Phantom
const signedTx = await window.solana.signTransaction(tx);
// Serialize signed transaction
const signedTxBase64 = signedTx.serialize().toString('base64');3. Submit Signed Transaction
curl -X POST https://dubs-server-dev-55d1fba09a97.herokuapp.com/api/v1/prod/transaction/submit \
-H "Content-Type: application/json" \
-d '{
"signedTransaction": "SIGNED_TX_BASE64_HERE"
}'Response:
{
"success": true,
"transaction": "5m9hH7e2Dc59Y4dVuXsXJCJVbpq8gh2NFGHo6HT5cBMGL4aYPUW2rCcTZuLR2ETY71LXkZGjJBsDh5qzsfUuLMCi",
"message": "Transaction confirmed on blockchain"
}4. View on Solana Explorer
https://explorer.solana.com/tx/YOUR_TX_SIGNATURE?cluster=devnetComplete Client Integration Example
React/Next.js with Phantom
import { useWallet } from '@solana/wallet-adapter-react';
import { Connection, Transaction } from '@solana/web3.js';
const API_BASE = 'https://dubs-server-dev-55d1fba09a97.herokuapp.com';
async function createGame() {
const { publicKey, signTransaction } = useWallet();
// Step 1: Build unsigned transaction
const buildRes = await fetch(`${API_BASE}/api/v1/prod/transaction/build/create`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
creatorAddress: publicKey.toString(),
buyIn: 0.5,
maxPlayers: 4,
operatorFee: 10,
}),
});
const { transaction: unsignedTx, gameId } = await buildRes.json();
// Step 2: Decode and sign
const txBuffer = Buffer.from(unsignedTx, 'base64');
const tx = Transaction.from(txBuffer);
const signedTx = await signTransaction(tx);
// Step 3: Submit signed transaction
const submitRes = await fetch(`${API_BASE}/api/v1/prod/transaction/submit`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
signedTransaction: signedTx.serialize().toString('base64'),
}),
});
const result = await submitRes.json();
console.log('Game created!', { gameId, tx: result.transaction });
return gameId;
}Join Game
async function joinGame(gameId: string) {
const { publicKey, signTransaction } = useWallet();
// Build unsigned transaction
const buildRes = await fetch(`${API_BASE}/api/v1/prod/transaction/build/join`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
playerAddress: publicKey.toString(),
gameId,
}),
});
const { transaction } = await buildRes.json();
// Sign and submit
const txBuffer = Buffer.from(transaction, 'base64');
const tx = Transaction.from(txBuffer);
const signedTx = await signTransaction(tx);
const submitRes = await fetch(`${API_BASE}/api/v1/prod/transaction/submit`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
signedTransaction: signedTx.serialize().toString('base64'),
}),
});
return await submitRes.json();
}View Game
async function getGameInfo(gameId: string) {
const res = await fetch(`${API_BASE}/api/v1/prod/game/${gameId}`);
return await res.json();
}Postman Testing
Import: postman/Dubs-API-v1.postman_collection.json
Update Variables:
baseUrl:https://dubs-server-dev-55d1fba09a97.herokuapp.com(for devnet)gameId: Auto-saved after creating game
Test Flow:
- Production API → Build Create Game Transaction
- (Sign with Phantom - do this manually or in your app)
- Production API → Submit Signed Transaction
- Production API → Get Game Info
Environment Variables
Required:
SOLANA_NETWORK=https://api.devnet.solana.com # or mainnet-beta
PROGRAM_ID=8DJTkgk6MDr6tPtw4v2VzYAz9WWvmCg6786vZrEK3o5qOptional:
PORT=3001 # Heroku sets this automaticallySet on Heroku:
heroku config:set SOLANA_NETWORK=https://api.devnet.solana.com -a dubs-server-dev
heroku config:set PROGRAM_ID=8DJTkgk6MDr6tPtw4v2VzYAz9WWvmCg6786vZrEK3o5q -a dubs-server-devDeployment
Devnet (Current)
# Already deployed!
# URL: https://dubs-server-dev-55d1fba09a97.herokuapp.comTo redeploy:
git add .
git commit -m "Update"
git push heroku-dev mainMainnet (Future)
# 1. Deploy Solana program to mainnet
cd ../dubs
solana program deploy target/deploy/hello_world.so --url mainnet-beta
# 2. Create Heroku app for mainnet
heroku apps:create dubs-api-prod --team dubs
# 3. Add remote
git remote add heroku-prod https://git.heroku.com/dubs-api-prod.git
# 4. Configure for mainnet
heroku config:set SOLANA_NETWORK=https://api.mainnet-beta.solana.com -a dubs-api-prod
heroku config:set PROGRAM_ID=8DJTkgk6MDr6tPtw4v2VzYAz9WWvmCg6786vZrEK3o5q -a dubs-api-prod
# 5. Deploy
git push heroku-prod mainFeatures
✅ UUID Game IDs - Professional, unique identifiers
✅ Address-Based Winners - No confusing indices
✅ Multi-Game Support - Unlimited simultaneous games
✅ Operator Fees - Built-in monetization (0-100%)
✅ Multi-Winner Payouts - Equal or custom splits
✅ 3 Game Modes - Manual, Democratic, Referee ⚖️ (NEW!)
✅ Democratic Voting - 🗳️ Players vote for winners
✅ Majority Rules - 🗳️ 50%+ players decide outcome
✅ Referee System - ⚖️ Expert judges earn commission (NEW!)
✅ Trustless Distribution - Anyone can trigger when ready
✅ Clean API - Versioned (/api/v1/)
✅ Dual Mode - Production & Demo endpoints
✅ Heroku Ready - One-command deploy
API Endpoints Summary
Production (Real Wallets):
- Build unsigned transactions
- Client signs with wallet
- Submit to blockchain
Demo (Server-Managed):
- Server creates & signs
- Easy testing
- Local development only
Tech Stack
- Node.js: 20.x
- Express: 4.18.2
- @solana/web3.js: 1.95.8
- Solana Program: Anchor 0.29.0, Rust 1.88.0
🗳️ Democratic Voting System (NEW!)
Overview
Games can now be created with democratic voting enabled! Players vote for winners, and the smart contract automatically tallies votes and distributes prizes based on majority rules.
How It Works
Create Game with Voting:
{ "creatorAddress": "...", "buyIn": 0.5, "maxPlayers": 4, "votingEnabled": true ← Enable voting! }Players Join:
- Standard join flow
- All players can vote
Players Vote:
POST /api/v1/prod/transaction/build/cast-vote { "voterAddress": "PlayerAddress", "gameId": "uuid", "votedFor": "AnotherPlayerAddress" }Check Voting Progress:
GET /api/v1/prod/game/:gameId Response includes: { "votes": [ {"voter": "Player1", "votedFor": "Player2"}, {"voter": "Player2", "votedFor": "Player2"} ], "votingEnabled": true }Distribute by Vote (When Majority Reached):
POST /api/v1/prod/transaction/build/distribute-by-vote { "creatorAddress": "...", "gameId": "uuid" }
Majority Rules
Total Players: 3 → Need 2 votes (majority)
Total Players: 4 → Need 3 votes (majority)
Total Players: 2 → Need 2 votes (both)Formula: (total_players / 2) + 1
Tie Handling
If multiple players tied for most votes:
- Prize split equally among tied winners
- Example: 2-way tie → 50/50 split
Vote Changes
- ✅ Players can change votes before majority
- ✅ Latest vote overwrites previous vote
- ✅ All votes stored on-chain
What's Next
Phase 6: Advanced Voting Features
- Time-based voting deadlines
- Weighted voting (based on buy-in multiples)
- Anonymous voting
- Vote delegation
Support
- Documentation: See
DUBS-PROJECT.mdin parent directory - Postman Collection: Import
postman/Dubs-API-v1-With-Voting.postman_collection.json - Voting Guide: See
postman/VOTING_API_GUIDE.md - Referee Mode: See
REFEREE_MODE_GUIDE.md⚖️ (NEW!) - CLI Tool: Run
npm run clifor interactive testing - Issues: Check Heroku logs with
heroku logs --tail -a dubs-server-dev
Built with ❤️ on Solana
