Skip to content

Real-Time Game State

Build an on-chain game with instant state updates.

onchain-game.ts
import { createPublicClient, createWalletClient, webSocket, http, encodeFunctionData } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { riseTestnet } from 'viem/chains'
import { sendRawTransactionSync } from 'shreds/viem'
 
// Simple game contract ABI
const gameAbi = [
  {
    inputs: [{ name: 'move', type: 'uint8' }],
    name: 'makeMove',
    outputs: [],
    type: 'function'
  },
  {
    inputs: [],
    name: 'gameState',
    outputs: [
      { name: 'player1', type: 'address' },
      { name: 'player2', type: 'address' },
      { name: 'currentTurn', type: 'address' },
      { name: 'board', type: 'uint8[9]' },
      { name: 'winner', type: 'address' }
    ],
    type: 'function'
  },
  {
    anonymous: false,
    inputs: [
      { indexed: true, name: 'player', type: 'address' },
      { indexed: false, name: 'position', type: 'uint8' }
    ],
    name: 'MoveMade',
    type: 'event'
  }
] as const
 
class OnChainGame {
  private gameAddress: `0x${string}`
  private wsClient: any
  private walletClient: any
  private publicClient: any
  
  constructor(gameAddress: `0x${string}`) {
    this.gameAddress = gameAddress
    
    this.wsClient = createPublicClient({
      chain: riseTestnet,
      transport: webSocket()
    })
    
    this.publicClient = createPublicClient({
      chain: riseTestnet,
      transport: http()
    })
    
    const account = privateKeyToAccount('0x...')
    this.walletClient = createWalletClient({
      account,
      chain: riseTestnet,
      transport: http()
    })
  }
  
  async makeMove(position: number) {
    console.log(`Making move at position ${position}...`)
    
    // Prepare and sign transaction
    const request = await this.walletClient.prepareTransactionRequest({
      to: this.gameAddress,
      data: encodeFunctionData({
        abi: gameAbi,
        functionName: 'makeMove',
        args: [position]
      })
    })
    
    const serializedTransaction = await this.walletClient.signTransaction(request)
    
    const receipt = await sendRawTransactionSync(this.publicClient, {
      serializedTransaction
    })
    
    console.log('[SUCCESS] Move confirmed instantly!')
    return receipt.transactionHash
  }
  
  async watchGame(onUpdate: (state: any) => void) {
    // Initial state
    const state = await this.getGameState()
    onUpdate(state)
    
    // Watch for updates
    const unwatch = this.wsClient.watchContractEvent({
      address: this.gameAddress,
      abi: gameAbi,
      eventName: 'MoveMade',
      onLogs: async (logs) => {
        // Get updated state immediately
        const newState = await this.getGameState()
        onUpdate(newState)
        
        logs.forEach(log => {
          console.log(`Player ${log.args.player} moved to ${log.args.position}`)
        })
      }
    })
    
    return unwatch
  }
  
  private async getGameState() {
    const state = await this.publicClient.readContract({
      address: this.gameAddress,
      abi: gameAbi,
      functionName: 'gameState'
    })
    
    return {
      player1: state[0],
      player2: state[1],
      currentTurn: state[2],
      board: state[3],
      winner: state[4]
    }
  }
}
 
// Play the game
const game = new OnChainGame('0x...')
 
// Watch for updates
const unwatch = await game.watchGame((state) => {
  console.log('Game state updated:', state)
  // Update UI...
})
 
// Make a move
await game.makeMove(4) // Center position

Game Features

  • Instant Moves: Players see moves immediately
  • Real-Time Updates: Game state syncs across all players
  • Fair Play: Blockchain ensures no cheating
  • Global State: Anyone can verify the game state

Example: Tic-Tac-Toe UI

// Simple console UI for the game
function displayBoard(board: number[]) {
  const symbols = [' ', 'X', 'O']
  console.clear()
  console.log('Current Board:')
  console.log(`
    ${symbols[board[0]]} | ${symbols[board[1]]} | ${symbols[board[2]]}
    ---------
    ${symbols[board[3]]} | ${symbols[board[4]]} | ${symbols[board[5]]}
    ---------
    ${symbols[board[6]]} | ${symbols[board[7]]} | ${symbols[board[8]]}
  `)
}
 
// Game loop
const game = new OnChainGame('0x...')
 
await game.watchGame((state) => {
  displayBoard(state.board)
  
  if (state.winner !== '0x0000000000000000000000000000000000000000') {
    console.log(`Winner: ${state.winner}`)
  } else {
    console.log(`Current turn: ${state.currentTurn}`)
  }
})

Advanced Gaming Features

  1. Tournaments: Create brackets with instant match results
  2. Leaderboards: Real-time ranking updates
  3. Achievements: Instant NFT minting for milestones
  4. Betting: Place and settle bets immediately

Benefits for Gaming

  • No Lag: Moves confirmed in milliseconds
  • Provably Fair: All game logic on-chain
  • Global Play: Anyone can join from anywhere
  • Instant Rewards: Prizes distributed immediately

Next Steps

  • Build more complex games (poker, chess, RPGs)
  • Add multiplayer matchmaking
  • Implement game economies with tokens
  • Create gaming tournaments