> ## Documentation Index
> Fetch the complete documentation index at: https://docs.whisky.casino/llms.txt
> Use this file to discover all available pages before exploring further.

# Whisky React SDK

> React components and hooks for seamless frontend integration

# Whisky React SDK

The Whisky React SDK provides React components and hooks for seamless integration of the Whisky Gaming Protocol into frontend applications.

## Overview

The React SDK serves as the UI layer, providing:

* **React Hooks**: Custom hooks for protocol interaction
* **UI Components**: Pre-built gaming components
* **Wallet Integration**: Seamless wallet connectivity
* **State Management**: Application state handling

## Features

* **Unified Package**: Combines UI components and React hooks in a single package
* **Whisky Protocol Integration**: Built specifically for the Whisky Gaming Protocol
* **TypeScript Support**: Full TypeScript support with comprehensive type definitions
* **Wallet Integration**: Seamless integration with Solana wallet adapters
* **Plugin System**: Extensible plugin system for custom functionality
* **Transaction Management**: Built-in transaction handling and state management

## Installation

```bash theme={null}
npm install @whisky-gaming/ui
```

## Quick Start

```tsx theme={null}
import { WhiskyProvider, useWhisky } from '@whisky-gaming/ui'

function App() {
  return (
    <WhiskyProvider>
      <YourGame />
    </WhiskyProvider>
  )
}

function YourGame() {
  const { play, isPlaying, game } = useWhisky()
  
  const handlePlay = async () => {
    await play({
      wager: 1000000, // 0.001 SOL
      bet: [50, 50], // Equal probability
      creator: 'YOUR_CREATOR_ADDRESS',
    })
  }
  
  return (
    <div>
      <button onClick={handlePlay} disabled={isPlaying}>
        {isPlaying ? 'Playing...' : 'Play'}
      </button>
    </div>
  )
}
```

## Core Components

### WhiskyProvider

The main provider that wraps your app and provides access to the Whisky protocol.

```tsx theme={null}
import { WhiskyProvider } from '@whisky-gaming/ui'

<WhiskyProvider plugins={[yourCustomPlugin]}>
  {children}
</WhiskyProvider>
```

**Props:**

```typescript theme={null}
interface WhiskyProviderProps {
  children: React.ReactNode;
  plugins?: WhiskyPlugin[];
  config?: WhiskyConfig;
}
```

### WhiskyPlatformProvider

Provides platform-specific functionality like token selection and pool management.

```tsx theme={null}
import { WhiskyPlatformProvider } from '@whisky-gaming/ui'

<WhiskyPlatformProvider>
  {children}
</WhiskyPlatformProvider>
```

## Hooks

### useWhisky()

Main hook for interacting with the Whisky protocol.

```tsx theme={null}
const { play, result, isPlaying, game, error } = useWhisky()
```

**Returns:**

```typescript theme={null}
interface WhiskyHookReturn {
  play: (params: PlayParams) => Promise<void>;
  result: GameResult | null;
  isPlaying: boolean;
  game: Game | null;
  error: Error | null;
  reset: () => void;
}
```

**Example:**

```tsx theme={null}
function GamingComponent() {
  const { play, result, isPlaying, game, error } = useWhisky()
  
  const handlePlay = async () => {
    try {
      await play({
        wager: 1000000,
        bet: [50, 50],
        creator: 'CREATOR_ADDRESS',
        clientSeed: 'my_seed_123'
      })
    } catch (err) {
      console.error('Game failed:', err)
    }
  }
  
  return (
    <div>
      <button onClick={handlePlay} disabled={isPlaying}>
        {isPlaying ? 'Playing...' : 'Play Game'}
      </button>
      
      {result && (
        <div>
          {result.won ? 'You won!' : 'You lost!'}
          <p>Payout: {result.payout}</p>
        </div>
      )}
      
      {error && <div>Error: {error.message}</div>}
    </div>
  )
}
```

### usePool()

Get pool information for a specific token.

```tsx theme={null}
const { pool, loading, error } = usePool(tokenMint, poolAuthority)
```

**Parameters:**

* `tokenMint`: Token mint address
* `poolAuthority`: Pool authority address

**Returns:**

```typescript theme={null}
interface PoolHookReturn {
  pool: PoolInfo | null;
  loading: boolean;
  error: Error | null;
  refetch: () => void;
}
```

**Example:**

```tsx theme={null}
function PoolInfo({ tokenMint, poolAuthority }) {
  const { pool, loading, error } = usePool(tokenMint, poolAuthority)
  
  if (loading) return <div>Loading pool...</div>
  if (error) return <div>Error: {error.message}</div>
  if (!pool) return <div>Pool not found</div>
  
  return (
    <div>
      <h3>Pool Information</h3>
      <p>Total Liquidity: {pool.totalLiquidity}</p>
      <p>Total Plays: {pool.totalPlays}</p>
      <p>Min Wager: {pool.minWager}</p>
    </div>
  )
}
```

### useBalance()

Get balance information for a wallet and token.

```tsx theme={null}
const { balance, nativeBalance } = useBalance(wallet, token)
```

**Parameters:**

* `wallet`: Wallet public key
* `token`: Token mint address (optional)

**Returns:**

```typescript theme={null}
interface BalanceHookReturn {
  balance: number | null;
  nativeBalance: number | null;
  bonusBalance: number | null;
  loading: boolean;
  error: Error | null;
  refetch: () => void;
}
```

**Example:**

```tsx theme={null}
function BalanceDisplay({ wallet, token }) {
  const { balance, nativeBalance, loading } = useBalance(wallet, token)
  
  if (loading) return <div>Loading balance...</div>
  
  return (
    <div>
      <p>Token Balance: {balance}</p>
      <p>SOL Balance: {nativeBalance}</p>
    </div>
  )
}
```

### useWalletAddress()

Get the current wallet address.

```tsx theme={null}
const walletAddress = useWalletAddress()
```

**Returns:** `string | null`

**Example:**

```tsx theme={null}
function WalletInfo() {
  const walletAddress = useWalletAddress()
  
  if (!walletAddress) {
    return <div>Please connect your wallet</div>
  }
  
  return (
    <div>
      <p>Connected: {walletAddress.substring(0, 8)}...</p>
    </div>
  )
}
```

## UI Components

### TokenValue

Display token values with proper formatting.

```tsx theme={null}
import { TokenValue } from '@whisky-gaming/ui'

<TokenValue amount={1000000} token={tokenMeta} />
```

**Props:**

```typescript theme={null}
interface TokenValueProps {
  amount: number;
  token: TokenMetadata;
  showSymbol?: boolean;
  decimals?: number;
  className?: string;
}
```

**Example:**

```tsx theme={null}
function TokenDisplay() {
  const usdcToken = {
    symbol: 'USDC',
    decimals: 6,
    name: 'USD Coin'
  }
  
  return (
    <div>
      <TokenValue 
        amount={1000000} 
        token={usdcToken} 
        showSymbol={true}
      />
      {/* Displays: "1.00 USDC" */}
    </div>
  )
}
```

### Canvas

Game canvas component for rendering games.

```tsx theme={null}
import { Canvas } from '@whisky-gaming/ui'

<Canvas game={gameBundle} />
```

**Props:**

```typescript theme={null}
interface CanvasProps {
  game: GameBundle;
  width?: number;
  height?: number;
  onGameEnd?: (result: GameResult) => void;
  className?: string;
}
```

**Example:**

```tsx theme={null}
function GameCanvas({ gameBundle }) {
  const handleGameEnd = (result) => {
    console.log('Game ended:', result)
  }
  
  return (
    <Canvas 
      game={gameBundle}
      width={800}
      height={600}
      onGameEnd={handleGameEnd}
    />
  )
}
```

### GameButton

Pre-styled button component for gaming actions.

```tsx theme={null}
import { GameButton } from '@whisky-gaming/ui'

<GameButton onClick={handlePlay} disabled={isPlaying}>
  Play Game
</GameButton>
```

**Props:**

```typescript theme={null}
interface GameButtonProps {
  children: React.ReactNode;
  onClick: () => void;
  disabled?: boolean;
  variant?: 'primary' | 'secondary' | 'success' | 'danger';
  size?: 'small' | 'medium' | 'large';
  loading?: boolean;
  className?: string;
}
```

### TokenSelector

Component for selecting tokens for gaming.

```tsx theme={null}
import { TokenSelector } from '@whisky-gaming/ui'

<TokenSelector 
  selectedToken={selectedToken}
  onTokenSelect={setSelectedToken}
  tokens={availableTokens}
/>
```

**Props:**

```typescript theme={null}
interface TokenSelectorProps {
  selectedToken: TokenMetadata | null;
  onTokenSelect: (token: TokenMetadata) => void;
  tokens: TokenMetadata[];
  disabled?: boolean;
  className?: string;
}
```

## Plugin System

Create custom plugins to extend functionality:

```tsx theme={null}
import { WhiskyPlugin } from '@whisky-gaming/ui'

const myPlugin: WhiskyPlugin = async (input, context) => {
  // Your custom logic here
  return [] // Return additional transaction instructions
}

<WhiskyProvider plugins={[myPlugin]}>
  {children}
</WhiskyProvider>
```

**Plugin Interface:**

```typescript theme={null}
interface WhiskyPlugin {
  name: string;
  version: string;
  execute: (input: any, context: PluginContext) => Promise<any[]>;
}
```

**Example Plugin:**

```tsx theme={null}
const referralPlugin: WhiskyPlugin = {
  name: 'referral',
  version: '1.0.0',
  execute: async (input, context) => {
    const { referralCode } = input
    
    if (referralCode) {
      // Add referral logic
      return [referralInstruction]
    }
    
    return []
  }
}

function App() {
  return (
    <WhiskyProvider plugins={[referralPlugin]}>
      <GamingApp />
    </WhiskyProvider>
  )
}
```

## Referral System

Built-in referral system support:

```tsx theme={null}
import { ReferralProvider, useReferral } from '@whisky-gaming/ui'

<ReferralProvider>
  <YourApp />
</ReferralProvider>

// In your component
const { referralCode, setReferralCode } = useReferral()
```

**Referral Hook:**

```typescript theme={null}
interface ReferralHookReturn {
  referralCode: string | null;
  setReferralCode: (code: string) => void;
  clearReferralCode: () => void;
  referralStats: ReferralStats | null;
}
```

**Example:**

```tsx theme={null}
function ReferralSystem() {
  const { referralCode, setReferralCode, referralStats } = useReferral()
  
  const handleReferralInput = (code: string) => {
    setReferralCode(code)
  }
  
  return (
    <div>
      <input 
        placeholder="Enter referral code"
        onChange={(e) => handleReferralInput(e.target.value)}
        value={referralCode || ''}
      />
      
      {referralStats && (
        <div>
          <p>Referrals: {referralStats.totalReferrals}</p>
          <p>Earnings: {referralStats.totalEarnings}</p>
        </div>
      )}
    </div>
  )
}
```

## Advanced Usage Examples

### Complete Gaming Application

```tsx theme={null}
import React from 'react'
import { 
  WhiskyProvider, 
  useWhisky, 
  usePool, 
  useBalance,
  TokenValue,
  GameButton,
  TokenSelector 
} from '@whisky-gaming/ui'

function GamingApp() {
  return (
    <WhiskyProvider>
      <div className="gaming-app">
        <h1>Whisky Gaming</h1>
        <GameInterface />
      </div>
    </WhiskyProvider>
  )
}

function GameInterface() {
  const { play, isPlaying, result, error } = useWhisky()
  const [selectedToken, setSelectedToken] = useState(null)
  const [wager, setWager] = useState(1000000)
  const [bet, setBet] = useState([50, 50])
  
  const { pool } = usePool(selectedToken?.mint)
  const { balance } = useBalance(wallet, selectedToken?.mint)
  
  const handlePlay = async () => {
    if (!selectedToken || !pool) return
    
    await play({
      poolAddress: pool.address,
      wager,
      bet,
      creator: 'CREATOR_ADDRESS',
      clientSeed: `game_${Date.now()}`,
      creatorFee: 100,
      jackpotFee: 50,
      metadata: 'Custom Game'
    })
  }
  
  return (
    <div className="game-interface">
      <div className="token-section">
        <TokenSelector 
          selectedToken={selectedToken}
          onTokenSelect={setSelectedToken}
          tokens={availableTokens}
        />
        
        {balance && (
          <div className="balance">
            Balance: <TokenValue amount={balance} token={selectedToken} />
          </div>
        )}
      </div>
      
      <div className="game-controls">
        <input 
          type="number"
          value={wager}
          onChange={(e) => setWager(Number(e.target.value))}
          placeholder="Wager amount"
        />
        
        <GameButton 
          onClick={handlePlay}
          disabled={isPlaying || !selectedToken || !pool}
          loading={isPlaying}
        >
          {isPlaying ? 'Playing...' : 'Play Game'}
        </GameButton>
      </div>
      
      {result && (
        <div className="game-result">
          <h3>{result.won ? 'You Won!' : 'You Lost!'}</h3>
          <p>Payout: <TokenValue amount={result.payout} token={selectedToken} /></p>
          <p>Multiplier: {result.multiplier}x</p>
        </div>
      )}
      
      {error && (
        <div className="error">
          Error: {error.message}
        </div>
      )}
    </div>
  )
}
```

### Multi-Game Interface

```tsx theme={null}
function MultiGameInterface() {
  const [selectedGame, setSelectedGame] = useState('coinflip')
  
  const games = {
    coinflip: {
      name: 'Coin Flip',
      bet: [50, 50],
      description: 'Simple 50/50 chance'
    },
    dice: {
      name: 'Dice Roll',
      bet: [16, 16, 16, 16, 16, 20],
      description: 'Six-sided dice with slight bias'
    },
    slots: {
      name: 'Slot Machine',
      bet: [500, 300, 150, 40, 9, 1],
      description: 'Complex slot machine simulation'
    }
  }
  
  const { play, isPlaying } = useWhisky()
  
  const handleGameSelect = (gameKey) => {
    setSelectedGame(gameKey)
  }
  
  const handlePlay = async () => {
    const game = games[selectedGame]
    await play({
      wager: 1000000,
      bet: game.bet,
      creator: 'CREATOR_ADDRESS',
      metadata: game.name
    })
  }
  
  return (
    <div className="multi-game">
      <div className="game-selector">
        {Object.entries(games).map(([key, game]) => (
          <button
            key={key}
            onClick={() => handleGameSelect(key)}
            className={selectedGame === key ? 'active' : ''}
          >
            {game.name}
          </button>
        ))}
      </div>
      
      <div className="game-info">
        <h3>{games[selectedGame].name}</h3>
        <p>{games[selectedGame].description}</p>
      </div>
      
      <GameButton onClick={handlePlay} disabled={isPlaying}>
        Play {games[selectedGame].name}
      </GameButton>
    </div>
  )
}
```

### Pool Management Interface

```tsx theme={null}
function PoolManagement() {
  const [selectedPool, setSelectedPool] = useState(null)
  const [depositAmount, setDepositAmount] = useState('')
  
  const { pools, loading } = usePools()
  const { depositLiquidity, withdrawLiquidity } = usePoolActions()
  
  const handleDeposit = async () => {
    if (!selectedPool || !depositAmount) return
    
    await depositLiquidity(selectedPool.address, Number(depositAmount))
    setDepositAmount('')
  }
  
  const handleWithdraw = async (lpTokenAmount) => {
    if (!selectedPool) return
    
    await withdrawLiquidity(selectedPool.address, lpTokenAmount)
  }
  
  return (
    <div className="pool-management">
      <h2>Pool Management</h2>
      
      <div className="pool-list">
        {pools.map(pool => (
          <div 
            key={pool.address}
            className={`pool-item ${selectedPool?.address === pool.address ? 'selected' : ''}`}
            onClick={() => setSelectedPool(pool)}
          >
            <TokenValue amount={pool.totalLiquidity} token={pool.token} />
            <p>Total Plays: {pool.totalPlays}</p>
            <p>Fee: {pool.feeBps / 100}%</p>
          </div>
        ))}
      </div>
      
      {selectedPool && (
        <div className="pool-actions">
          <h3>Manage {selectedPool.token.symbol} Pool</h3>
          
          <div className="deposit-section">
            <input
              type="number"
              value={depositAmount}
              onChange={(e) => setDepositAmount(e.target.value)}
              placeholder="Amount to deposit"
            />
            <GameButton onClick={handleDeposit}>
              Deposit
            </GameButton>
          </div>
          
          <div className="withdraw-section">
            <p>Your LP Tokens: {selectedPool.userLpTokens}</p>
            <GameButton 
              onClick={() => handleWithdraw(selectedPool.userLpTokens)}
              variant="secondary"
            >
              Withdraw All
            </GameButton>
          </div>
        </div>
      )}
    </div>
  )
}
```

## Styling and Theming

### Custom Styling

```tsx theme={null}
// Custom CSS
.game-button {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border: none;
  border-radius: 8px;
  color: white;
  padding: 12px 24px;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
}

.game-button:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.game-button:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  transform: none;
}
```

### Theme Provider

```tsx theme={null}
import { WhiskyThemeProvider } from '@whisky-gaming/ui'

const customTheme = {
  colors: {
    primary: '#667eea',
    secondary: '#764ba2',
    success: '#48bb78',
    danger: '#f56565',
    background: '#1a202c',
    text: '#ffffff'
  },
  borderRadius: '8px',
  spacing: {
    small: '8px',
    medium: '16px',
    large: '24px'
  }
}

<WhiskyThemeProvider theme={customTheme}>
  <GamingApp />
</WhiskyThemeProvider>
```

## Error Handling

### Global Error Boundary

```tsx theme={null}
import { WhiskyErrorBoundary } from '@whisky-gaming/ui'

function App() {
  return (
    <WhiskyErrorBoundary
      fallback={<div>Something went wrong with the gaming system</div>}
    >
      <WhiskyProvider>
        <GamingApp />
      </WhiskyProvider>
    </WhiskyErrorBoundary>
  )
}
```

### Hook Error Handling

```tsx theme={null}
function SafeGamingComponent() {
  const { play, error, reset } = useWhisky()
  
  useEffect(() => {
    if (error) {
      // Log error to monitoring service
      console.error('Gaming error:', error)
      
      // Show user-friendly message
      toast.error('Game failed. Please try again.')
    }
  }, [error])
  
  const handlePlay = async () => {
    try {
      await play(gameParams)
    } catch (err) {
      // Handle specific errors
      if (err.code === 'INSUFFICIENT_BALANCE') {
        toast.error('Insufficient balance')
      } else if (err.code === 'POOL_NOT_FOUND') {
        toast.error('Pool not available')
      } else {
        toast.error('Unexpected error occurred')
      }
    }
  }
  
  return (
    <div>
      <GameButton onClick={handlePlay}>
        Play Game
      </GameButton>
      
      {error && (
        <button onClick={reset}>
          Reset Game State
        </button>
      )}
    </div>
  )
}
```

## Performance Optimization

### Memoization

```tsx theme={null}
import React, { useMemo, useCallback } from 'react'

function OptimizedGamingComponent() {
  const { play, isPlaying } = useWhisky()
  
  // Memoize expensive calculations
  const gameConfig = useMemo(() => ({
    bet: [25, 25, 25, 25],
    creatorFee: 100,
    jackpotFee: 50
  }), [])
  
  // Memoize callback
  const handlePlay = useCallback(async () => {
    await play({
      wager: 1000000,
      ...gameConfig,
      metadata: 'Optimized Game'
    })
  }, [play, gameConfig])
  
  return (
    <GameButton onClick={handlePlay} disabled={isPlaying}>
      Play Optimized Game
    </GameButton>
  )
}
```

### Lazy Loading

```tsx theme={null}
import React, { lazy, Suspense } from 'react'

const GameCanvas = lazy(() => import('./GameCanvas'))
const PoolManagement = lazy(() => import('./PoolManagement'))

function LazyGamingApp() {
  return (
    <WhiskyProvider>
      <Suspense fallback={<div>Loading...</div>}>
        <GameCanvas />
        <PoolManagement />
      </Suspense>
    </WhiskyProvider>
  )
}
```

## Testing

### Component Testing

```tsx theme={null}
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import { WhiskyProvider } from '@whisky-gaming/ui'

function TestGamingComponent() {
  const { play, isPlaying } = useWhisky()
  
  return (
    <button onClick={() => play(gameParams)} disabled={isPlaying}>
      {isPlaying ? 'Playing...' : 'Play'}
    </button>
  )
}

test('renders play button', () => {
  render(
    <WhiskyProvider>
      <TestGamingComponent />
    </WhiskyProvider>
  )
  
  expect(screen.getByText('Play')).toBeInTheDocument()
})

test('handles play action', async () => {
  render(
    <WhiskyProvider>
      <TestGamingComponent />
    </WhiskyProvider>
  )
  
  const button = screen.getByText('Play')
  fireEvent.click(button)
  
  await waitFor(() => {
    expect(screen.getByText('Playing...')).toBeInTheDocument()
  })
})
```

### Hook Testing

```tsx theme={null}
import { renderHook, act } from '@testing-library/react-hooks'
import { useWhisky } from '@whisky-gaming/ui'

test('useWhisky hook', () => {
  const { result } = renderHook(() => useWhisky(), {
    wrapper: WhiskyProvider
  })
  
  expect(result.current.isPlaying).toBe(false)
  expect(result.current.result).toBe(null)
  
  act(() => {
    result.current.play(gameParams)
  })
  
  expect(result.current.isPlaying).toBe(true)
})
```

## Dependencies

This package requires the following peer dependencies:

* `@whisky-gaming/core`: The core Whisky protocol SDK
* `@solana/wallet-adapter-react`: Solana wallet integration
* `@solana/web3.js`: Solana web3 utilities
* `react`: React library
* `react-dom`: React DOM

## Development

```bash theme={null}
# Install dependencies
npm install

# Build the package
npm run build

# Development mode with watch
npm run dev

# Type checking
npm run lint
```

## Support

For React SDK support and questions:

* **Documentation**: This documentation
* **Examples**: [GitHub Examples](https://github.com/weknowyourgame/whisky-gaming/examples)
* **Community**: [Discord Server](https://discord.gg/whisky-gaming)
* **Issues**: [GitHub Issues](https://github.com/weknowyourgame/whisky-gaming/issues)
* **Email**: [support@whisky.casino](mailto:support@whisky.casino)
