logoCheckmate
Getting Started

Quick Start

Create your first chess game in 5 minutes

1. Setup

import { ChessGameSDK } from "@sendarcade/checkmate";
import { createSolanaRpc } from "@solana/kit";

// Standard Solana RPC
const rpc = createSolanaRpc("https://api.devnet.solana.com");

// Ephemeral Rollup RPC (for game state)
const erRpc = createSolanaRpc("https://devnet.magicblock.app");

const chessMateSDK = new ChessGameSDK();

// Your wallet signer
const signer = /* your wallet signer */;

2. Initialize an Integrator

To integrate the ChessMate SDK into your platform, you must first initialize the integrator configuration as an administrator.

const params = {
  integrator: signer, // Admin
  // A unique identifier for your platform.
  // This must be a valid Solana public key,
  // but it does not need to be the address of an existing Solana account.
  integratorId: address("YourIntegratorId"),
  // The fee percentage charged to players, expressed in basis points.
  // For example, a value of 500 equals a 5% fee.
  feeBasisPoints: 500,
  // The Solana wallet address that will receive all collected fees.
  feeVault: address("YourFeeVaultAddress"), // Address
};

const { instruction, integratorConfigPDA } =
  await chessMateSDK.initializeIntegratorIx(params);

// Send transaction
const signature = await sendTransaction(rpc, [instruction], signer);
console.log(`Integrator config created at: ${integratorConfigPDA}`);

Note: Only run this ONCE per integrator setup.

3. Create a Game

const createParams = {
  rpc,
  creator: signer,
  integratorId: address("YourIntegratorId"),
  tokenMint: address("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), // USDC
  entryFee: BigInt(1_000_000), // 1 USDC
  timeControl: {
    initialTime: 600, // 10 minutes
    increment: 5, // 5 seconds per move
    moveTimeLimit: null,
  },
  ratedGame: true,
  allowDrawOffers: true,
};

const { instruction, gameId, gameAccountAddress } =
  await chessMateSDK.createGameIx(createParams);

// Send transaction
const signature = await sendTransaction(rpc, [instruction], signer);
console.log(`Game created with ID: ${gameId}`);

4. Cancel a Game

If no other player joins the game, the creator can cancel it and reclaim the full wager, with no fee charged.

const cancelGameParams = {
  creator: this.signer,
  gameId: BigInt(1),
  integratorId: address("YourIntegratorId"),
  tokenMint: address("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), // USDC
};

const { instruction, gameAccountAddress } = await chessMateSDK.cancelGameIx(
  cancelGameParams
);

// Send transaction
const signature = await sendTransaction(rpc, [instruction], signer);
console.log(`Game canceled with address: ${gameAccountAddress}`);

5. Join a Game

const joinParams = {
  player: signer,
  gameId: BigInt(1),
  integratorId: address("YourIntegratorId"),
  tokenMint: address("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), // USDC
};

const { instruction } = await chessMateSDK.joinGameIx(joinParams);
const signature = await sendTransaction(rpc, [instruction], signer);
console.log("Joined game as black player");

6. Make a Move

Once the second player joins, the game will begin. The game's status updates to InProgress and the GameAccount is delegated to the Ephemeral Rollup environment. All subsequent interactions with the game account, such as making a move or canceling the game, must be performed via the Ephemeral Rollup RPC.

const moveParams = {
  player: signer,
  gameId: BigInt(1),
  integratorId: address("YourIntegratorId"),
  fromSquare: "e2", // or square index: 12
  toSquare: "e4", // or square index: 28
  promotionPiece: undefined, // Only for pawn promotion
};

const { instruction } = await chessMateSDK.makeMoveIx(moveParams);
const signature = await sendTransaction(erRpc, [instruction], signer);
console.log("Move made: e2 to e4");

7. Offer Draw

const offerDrawParams = {
  player: signer, // TransactionSigner
  gameId: BigInt(1), // bigint
  integratorId: address("YourIntegratorId"), // Address
};

const { instruction } = await chessMateSDK.offerDrawIx(offerDrawParams);
const signature = await sendTransaction(erRpc, [instruction], signer);
console.log("Sent offer draw");

8. Accept Draw

const acceptDrawParams = {
  player: signer, // TransactionSigner
  gameId: BigInt(1), // bigint
  integratorId: address("YourIntegratorId"), // Address
};

const { instruction } = await chessMateSDK.acceptDrawIx(acceptDrawParams);
const signature = await sendTransaction(erRpc, [instruction], signer);
console.log("Offer accepted");

9. Reject Draw

const rejectDrawParams = {
  player: signer, // TransactionSigner
  gameId: BigInt(1), // bigint
  integratorId: address("YourIntegratorId"), // Address
};

const { instruction } = await chessMateSDK.rejectDrawIx(rejectDrawParams);
const signature = await sendTransaction(erRpc, [instruction], signer);
console.log("Offer rejected");

10. Claim Winnings

When the game ends, the winner can claim the prize pool:

const claimWinningParams = {
  rpc,
  player: signer,
  gameId: BigInt(1),
  integratorId: address("YourIntegratorId"),
  tokenMint: address("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"),
};

const { instruction } = await chessMateSDK.claimWinningsIx(claimWinningParams);
const signature = await sendTransaction(rpc, [instruction], signer);
console.log("Winnings claimed!");

11. Get Game State & Display

Fetch state to show the board:

import { getGameAccountPDA, fetchGameAccount } from "@sendarcade/checkmate";

// Get the game account PDA
const [gameAccountPDA] = await getGameAccountPDA(
  address("YourIntegratorId"),
  BigInt(1) // Game ID
);

// Fetch the game account data
// Use the appropriate RPC based on game status (see Magicblock Note section)
const gameAccount = await fetchGameAccount(rpc, gameAccountPDA);

// Access the game data
const gameData = gameAccount.data;

console.log("Game status:", gameData.gameStatus);
console.log("Current turn:", gameData.currentTurn);
console.log("Board state:", gameData.board);

Combine this with your frontend chess engine to render the current position.

12. Use Utilities

Use built-in ChessUtils:

import { ChessUtils } from "@sendarcade/checkmate";

const utils = new ChessUtils();

// Convert between square notation and indices
const index = utils.squareToIndex("e4"); // 28
const notation = utils.indexToSquare(28); // "e4"

// Get piece information
const piece = utils.getPieceAt(gameData.board, index);
console.log(`Piece at e4: ${piece?.type} (${piece?.color})`);

// Display board in console
utils.displayBoard(gameData.board, "Current Position");

// Validate Legal Moves
const legalMoves = utils.getLegalMoves(gameData.board, gameData.currentTurn);

// Get legal moves for a specific piece (e2 square)
const e2Index = utils.squareToIndex("e2");
const legalMovesFromE2 = legalMoves.filter((move) => move.from === e2Index);

console.log(
  "Legal moves from e2:",
  legalMovesFromE2.map((m) => utils.indexToSquare(m.to))
);

13. Handle Errors

Wrap calls in try/catch and use the improved error handling in @solana/kit:

import { ChessGameError, GameNotFoundError } from "@sendarcade/checkmate";

try {
  const { instruction } = await chessSDK.makeMoveIx({
    player: signer,
    gameId: BigInt(1),
    integratorId: address("YourIntegratorId"),
    fromSquare: "e2",
    toSquare: "e5", // Invalid move
  });

  // Build and send transaction...
} catch (error) {
  if (error instanceof GameNotFoundError) {
    console.error("Game not found:", error.message);
  } else if (error instanceof ChessGameError) {
    console.error("Chess game error:", error.message);
  } else {
    console.error("Unknown error:", error);
  }
}

Next Steps

  • Basic Concepts - Understand core concepts
  • SDK API Reference - Complete API documentation
  • Game Mechanics - Learn chess rules implementation
  • Integration Guide - Build a complete chess app