Skip to main content

Whisky Core SDK

The Whisky Core SDK is a comprehensive TypeScript library that provides direct interaction with the Whisky Gaming Protocol smart contracts on Solana. It abstracts complex blockchain operations and provides type-safe interfaces for building gaming applications.

Overview

The Core SDK serves as the protocol layer, handling:
  • Smart Contract Calls: Direct blockchain interactions
  • Transaction Building: Creating and signing transactions
  • Account Management: PDA derivation and management
  • Protocol Logic: Mathematical calculations and validations

Installation

Prerequisites

  • Node.js 16.0.0 or higher
  • Solana CLI tools
  • Anchor framework
  • TypeScript 4.5.0 or higher

Install Dependencies

npm install @whisky-gaming/core

Anchor Program

anchor build
anchor deploy

Quick Start

Initialize SDK

import { WhiskySDK } from '@whisky-gaming/core';
import { Connection, Keypair } from '@solana/web3.js';

const sdk = new WhiskySDK({
  connection: new Connection('https://api.mainnet-beta.solana.com'),
  wallet: yourWallet,
  programId: WHISKY_PROGRAM_ID
});

Initialize Protocol

// Initialize protocol (one-time setup)
await sdk.initializeProtocol({
  authority: authorityPublicKey,
  rngProvider: rngProviderPublicKey,
  protocolFee: 200 // 2%
});

Create Gaming Pool

// Create USDC gaming pool
const poolAddress = await sdk.createPool({
  tokenMint: USDC_MINT_ADDRESS,
  minimumWager: 1_000_000, // 1 USDC
  poolAuthority: poolAuthorityKeypair
});

Add Liquidity

// Deposit 1000 USDC to earn fees from games
await sdk.depositLiquidity(poolAddress, 1000_000_000);

Play Game

// Simple coinflip game
const gameResult = await sdk.playGame({
  poolAddress,
  wager: 10_000_000, // 10 USDC
  bet: [50, 50], // Equal probability outcomes
  clientSeed: 'player_randomness_123',
  creatorFee: 100, // 1%
  jackpotFee: 50,  // 0.5%
  metadata: 'Coinflip Game #1'
});

// Wait for RNG settlement
await sdk.waitForSettlement(gameResult.gameAddress);

// Claim winnings if won
if (gameResult.won) {
  await sdk.claimWinnings(gameResult.gameAddress);
}

Core API Reference

WhiskySDK Class

Constructor

new WhiskySDK(config: WhiskySDKConfig)
Configuration:
interface WhiskySDKConfig {
  connection: Connection;
  wallet: Wallet;
  programId: PublicKey;
  commitment?: Commitment;
  confirmTransactionInitialTimeout?: number;
}

Gaming Methods

playGame(params: PlayGameParams): Promise<GameResult>

Initiates a new gaming session. Parameters:
interface PlayGameParams {
  poolAddress: PublicKey;
  wager: number;
  bet: number[];
  clientSeed: string;
  creatorFee: number;
  jackpotFee: number;
  metadata: string;
}
Returns:
interface GameResult {
  gameAddress: PublicKey;
  signature: string;
  won: boolean;
  payout?: number;
  multiplier?: number;
}
Example:
const result = await sdk.playGame({
  poolAddress: new PublicKey('POOL_ADDRESS'),
  wager: 1000000, // 1 USDC
  bet: [25, 25, 25, 25], // Four equal outcomes
  clientSeed: 'my_random_seed_123',
  creatorFee: 100, // 1%
  jackpotFee: 50,  // 0.5%
  metadata: 'Dice Roll Game'
});

waitForSettlement(gameAddress: PublicKey): Promise<GameSettlement>

Waits for game settlement and returns the result. Returns:
interface GameSettlement {
  gameAddress: PublicKey;
  result: number;
  payout: number;
  multiplier: number;
  won: boolean;
  signature: string;
}

claimWinnings(gameAddress: PublicKey): Promise<string>

Claims winnings from a settled game. Returns: Transaction signature

Pool Management

createPool(params: CreatePoolParams): Promise<PublicKey>

Creates a new liquidity pool for specified token. Parameters:
interface CreatePoolParams {
  tokenMint: PublicKey;
  minimumWager: number;
  maximumWager?: number;
  poolAuthority: Keypair;
  feeBps?: number;
}
Returns: Pool address Example:
const poolAddress = await sdk.createPool({
  tokenMint: new PublicKey('USDC_MINT_ADDRESS'),
  minimumWager: 1000000, // 1 USDC
  maximumWager: 1000000000, // 1000 USDC
  poolAuthority: poolAuthorityKeypair,
  feeBps: 100 // 1%
});

depositLiquidity(poolAddress: PublicKey, amount: number): Promise<string>

Deposits tokens into liquidity pool. Parameters:
  • poolAddress: Target pool address
  • amount: Token amount to deposit (in base units)
Returns: Transaction signature Example:
const signature = await sdk.depositLiquidity(
  new PublicKey('POOL_ADDRESS'),
  1000000000 // 1000 USDC
);

withdrawLiquidity(poolAddress: PublicKey, lpTokenAmount: number): Promise<string>

Withdraws liquidity from pool. Parameters:
  • poolAddress: Target pool address
  • lpTokenAmount: LP token amount to burn
Returns: Transaction signature

getPoolInfo(poolAddress: PublicKey): Promise<PoolInfo>

Gets pool information. Returns:
interface PoolInfo {
  poolAuthority: PublicKey;
  underlyingTokenMint: PublicKey;
  minWager: number;
  maxWager: number;
  totalLiquidity: number;
  totalPlays: number;
  totalVolume: number;
  lpTokenMint: PublicKey;
  feeBps: number;
}

Account Management

getWhiskyState(): Promise<WhiskyState>

Gets global protocol state. Returns:
interface WhiskyState {
  authority: PublicKey;
  rngAddress: PublicKey;
  whiskyFeeBps: number;
  playingAllowed: boolean;
  totalVolume: number;
  totalGames: number;
  totalFees: number;
}

getGameInfo(gameAddress: PublicKey): Promise<GameInfo>

Gets game information. Returns:
interface GameInfo {
  pool: PublicKey;
  player: PublicKey;
  wager: number;
  bet: number[];
  clientSeed: string;
  rngSeed: string;
  status: GameStatus;
  result?: number;
  payout?: number;
  multiplier?: number;
  timestamp: number;
}

Utility Functions

validateBet(bet: number[]): boolean

Validates betting structure for mathematical correctness.
// Valid examples
validateBet([50, 50]);           // Equal probability
validateBet([25, 25, 25, 25]);   // Four equal outcomes
validateBet([90, 10]);           // Asymmetric probability

// Invalid examples
validateBet([0, 0]);             // No winning outcomes
validateBet([]);                 // Empty bet array

calculatePayout(wager: number, bet: number[], outcome: number): number

Calculates payout for specific outcome.
const payout = calculatePayout(1000000, [50, 50], 0); // 2x multiplier

calculateJackpotOdds(wager: number, poolSize: number): number

Determines jackpot probability based on wager size.
const odds = calculateJackpotOdds(10000000, 1000000000); // 0.001% base odds

deriveGameAddress(poolAddress: PublicKey, player: PublicKey, nonce: number): PublicKey

Derives game account address.
const gameAddress = deriveGameAddress(poolAddress, player, nonce);

Advanced Usage Examples

Binary Prediction Market

// Create yes/no prediction market
const predictionGame = await sdk.playGame({
  poolAddress: usdcPool,
  wager: 50_000_000, // 50 USDC
  bet: [60, 40], // 60% probability for "Yes"
  clientSeed: 'prediction_12345',
  creatorFee: 200, // 2% to market creator
  jackpotFee: 0,   // No jackpot for predictions
  metadata: 'Election Outcome Prediction'
});

Multi-Outcome Casino Game

// Six-sided dice roll
const diceGame = await sdk.playGame({
  poolAddress: solPool,
  wager: 5_000_000_000, // 5 SOL
  bet: [16, 16, 16, 16, 16, 20], // Slightly favor outcome 6
  clientSeed: 'dice_roll_789',
  creatorFee: 300, // 3% house edge
  jackpotFee: 100, // 1% progressive jackpot
  metadata: 'Lucky Dice Roll'
});

Slot Machine Simulation

// Complex probability distribution
const slotGame = await sdk.playGame({
  poolAddress: bonkPool,
  wager: 1_000_000_000, // 1B BONK tokens
  bet: [
    500, // 50% - No win
    300, // 30% - Small win (2x)
    150, // 15% - Medium win (5x)
    40,  // 4% - Large win (20x)
    9,   // 0.9% - Huge win (100x)
    1    // 0.1% - Jackpot (1000x)
  ],
  clientSeed: 'slot_machine_456',
  creatorFee: 500, // 5% house edge
  jackpotFee: 200, // 2% progressive jackpot
  metadata: 'Triple 7s Slot Machine'
});

Batch Operations

// Create multiple pools
const poolAddresses = await Promise.all([
  sdk.createPool({
    tokenMint: USDC_MINT_ADDRESS,
    minimumWager: 1_000_000,
    poolAuthority: poolAuthority1
  }),
  sdk.createPool({
    tokenMint: SOL_MINT_ADDRESS,
    minimumWager: 1_000_000_000,
    poolAuthority: poolAuthority2
  })
]);

// Deposit liquidity to multiple pools
const depositSignatures = await Promise.all([
  sdk.depositLiquidity(poolAddresses[0], 1000_000_000), // 1000 USDC
  sdk.depositLiquidity(poolAddresses[1], 100_000_000_000) // 100 SOL
]);

Error Handling

try {
  const result = await sdk.playGame({
    poolAddress: new PublicKey('INVALID_POOL'),
    wager: 1000000,
    bet: [50, 50],
    clientSeed: 'test',
    creatorFee: 100,
    jackpotFee: 50,
    metadata: 'Test Game'
  });
} catch (error) {
  if (error instanceof WhiskyError) {
    switch (error.code) {
      case 'INSUFFICIENT_LIQUIDITY':
        console.error('Pool has insufficient liquidity');
        break;
      case 'INVALID_BET':
        console.error('Invalid betting structure');
        break;
      case 'WAGER_TOO_SMALL':
        console.error('Wager below minimum');
        break;
      default:
        console.error('Unknown error:', error.message);
    }
  } else {
    console.error('Unexpected error:', error);
  }
}

Mathematical Utilities

Probability Calculations

import { calculateMultiplier, validateProbabilityDistribution } from '@whisky-gaming/core';

// Calculate multiplier for outcome
const multiplier = calculateMultiplier([25, 25, 25, 25], 0); // 4.0

// Validate probability distribution
const isValid = validateProbabilityDistribution([50, 30, 20]); // true

House Edge Calculations

import { calculateHouseEdge, calculateExpectedValue } from '@whisky-gaming/core';

// Calculate house edge
const houseEdge = calculateHouseEdge([50, 50], 100); // 0% (fair game)
const unfairEdge = calculateHouseEdge([45, 55], 100); // 10% house edge

// Calculate expected value
const ev = calculateExpectedValue([50, 50], 1000000); // 1000000 (fair)

Transaction Management

Custom Transaction Options

const result = await sdk.playGame({
  poolAddress,
  wager: 1000000,
  bet: [50, 50],
  clientSeed: 'test',
  creatorFee: 100,
  jackpotFee: 50,
  metadata: 'Test Game'
}, {
  commitment: 'confirmed',
  preflightCommitment: 'processed',
  maxRetries: 3
});

Transaction Monitoring

const signature = await sdk.playGame(gameParams);

// Monitor transaction
const confirmation = await sdk.connection.confirmTransaction(signature, 'confirmed');

if (confirmation.value.err) {
  console.error('Transaction failed:', confirmation.value.err);
} else {
  console.log('Transaction confirmed');
}

Security Considerations

Input Validation

// Always validate inputs before sending transactions
if (!validateBet(bet)) {
  throw new Error('Invalid betting structure');
}

if (wager < minWager || wager > maxWager) {
  throw new Error('Wager out of range');
}

Error Handling

// Handle specific error types
try {
  await sdk.playGame(gameParams);
} catch (error) {
  if (error instanceof WhiskyError) {
    // Handle protocol-specific errors
    handleWhiskyError(error);
  } else if (error instanceof SolanaError) {
    // Handle Solana-specific errors
    handleSolanaError(error);
  } else {
    // Handle unexpected errors
    console.error('Unexpected error:', error);
  }
}

Transaction Safety

// Always verify transaction before sending
const transaction = await sdk.buildPlayGameTransaction(gameParams);
const simulation = await sdk.connection.simulateTransaction(transaction);

if (simulation.value.err) {
  console.error('Transaction simulation failed:', simulation.value.err);
  return;
}

// Send transaction only after successful simulation
const signature = await sdk.sendTransaction(transaction);

Performance Optimization

Connection Management

// Use connection pooling for high-frequency operations
const connection = new Connection('https://api.mainnet-beta.solana.com', {
  commitment: 'confirmed',
  wsEndpoint: 'wss://api.mainnet-beta.solana.com',
  confirmTransactionInitialTimeout: 60000
});

const sdk = new WhiskySDK({
  connection,
  wallet: yourWallet,
  programId: WHISKY_PROGRAM_ID
});

Batch Transactions

// Batch multiple operations in a single transaction
const instructions = [
  await sdk.buildPlayGameInstruction(gameParams1),
  await sdk.buildPlayGameInstruction(gameParams2),
  await sdk.buildClaimWinningsInstruction(gameAddress)
];

const transaction = new Transaction().add(...instructions);
const signature = await sdk.sendTransaction(transaction);

Testing

Unit Testing

import { WhiskySDK } from '@whisky-gaming/core';

describe('WhiskySDK', () => {
  let sdk: WhiskySDK;

  beforeEach(() => {
    sdk = new WhiskySDK({
      connection: new Connection('http://localhost:8899'),
      wallet: testWallet,
      programId: testProgramId
    });
  });

  test('should create pool successfully', async () => {
    const poolAddress = await sdk.createPool({
      tokenMint: testTokenMint,
      minimumWager: 1000000,
      poolAuthority: testAuthority
    });

    expect(poolAddress).toBeDefined();
  });
});

Integration Testing

describe('Game Flow', () => {
  test('should complete full game cycle', async () => {
    // Create pool
    const poolAddress = await sdk.createPool(poolParams);
    
    // Add liquidity
    await sdk.depositLiquidity(poolAddress, 1000000000);
    
    // Play game
    const gameResult = await sdk.playGame(gameParams);
    
    // Wait for settlement
    const settlement = await sdk.waitForSettlement(gameResult.gameAddress);
    
    // Claim winnings if won
    if (settlement.won) {
      await sdk.claimWinnings(gameResult.gameAddress);
    }
    
    expect(settlement).toBeDefined();
  });
});

Deployment

Mainnet Configuration

const MAINNET_CONFIG = {
  programId: new PublicKey('WHISKY_PROGRAM_ID'),
  rpcEndpoint: 'https://api.mainnet-beta.solana.com',
  wsEndpoint: 'wss://api.mainnet-beta.solana.com',
  commitment: 'confirmed' as Commitment
};

const sdk = new WhiskySDK({
  connection: new Connection(MAINNET_CONFIG.rpcEndpoint, {
    commitment: MAINNET_CONFIG.commitment,
    wsEndpoint: MAINNET_CONFIG.wsEndpoint
  }),
  wallet: yourWallet,
  programId: MAINNET_CONFIG.programId
});

Devnet Configuration

const DEVNET_CONFIG = {
  programId: new PublicKey('DEVNET_PROGRAM_ID'),
  rpcEndpoint: 'https://api.devnet.solana.com',
  wsEndpoint: 'wss://api.devnet.solana.com',
  commitment: 'confirmed' as Commitment
};

Support

For SDK support and questions: