npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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 faucet

Mainnet 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/submit

Demo 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/airdrop

Using 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=devnet

Complete 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:

  1. Production API → Build Create Game Transaction
  2. (Sign with Phantom - do this manually or in your app)
  3. Production API → Submit Signed Transaction
  4. Production API → Get Game Info

Environment Variables

Required:

SOLANA_NETWORK=https://api.devnet.solana.com    # or mainnet-beta
PROGRAM_ID=8DJTkgk6MDr6tPtw4v2VzYAz9WWvmCg6786vZrEK3o5q

Optional:

PORT=3001  # Heroku sets this automatically

Set 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-dev

Deployment

Devnet (Current)

# Already deployed!
# URL: https://dubs-server-dev-55d1fba09a97.herokuapp.com

To redeploy:

git add .
git commit -m "Update"
git push heroku-dev main

Mainnet (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 main

Features

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

  1. Create Game with Voting:

    {
      "creatorAddress": "...",
      "buyIn": 0.5,
      "maxPlayers": 4,
      "votingEnabled": true  ← Enable voting!
    }
  2. Players Join:

    • Standard join flow
    • All players can vote
  3. Players Vote:

    POST /api/v1/prod/transaction/build/cast-vote
    {
      "voterAddress": "PlayerAddress",
      "gameId": "uuid",
      "votedFor": "AnotherPlayerAddress"
    }
  4. Check Voting Progress:

    GET /api/v1/prod/game/:gameId
       
    Response includes:
    {
      "votes": [
        {"voter": "Player1", "votedFor": "Player2"},
        {"voter": "Player2", "votedFor": "Player2"}
      ],
      "votingEnabled": true
    }
  5. 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.md in 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 cli for interactive testing
  • Issues: Check Heroku logs with heroku logs --tail -a dubs-server-dev

Built with ❤️ on Solana