═══════════════════════════════════════════════════════════════════════════════ ARCADIA GAME SDK - COMPLETE DOCUMENTATION ═══════════════════════════════════════════════════════════════════════════════ Complete Developer Documentation Generated: 2/13/2026, 5:52:23 PM Version: 1.0.0 This document contains all Arcadia Game SDK documentation sections. Perfect for copying into AI IDEs like Cursor, GitHub Copilot, or ChatGPT. ═══════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ SECTION: QUICK START ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ Quick Start - Step by Step Integration ══════════════════════════════════════════════════════════════════════ Get your game integrated with Arcadia in 5 simple steps. Each step includes only the minimal code needed. Prerequisites ════════════════════════════════════════════════════════════ • Your game hosted and accessible via URL • Your game ID from Arcadia (you'll get this when you register your game) • Basic HTML/JavaScript knowledge Step 1: Include the SDK ════════════════════════════════════════════════════════════ Add the SDK to your HTML file using CDN: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [HTML] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Or use NPM: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [BASH] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ npm install @arcadiasol/sdk ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [JAVASCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { ArcadiaSDK } from '@arcadiasol/sdk'; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Step 2: Initialize the SDK ════════════════════════════════════════════════════════════ Create and initialize the SDK instance: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [JAVASCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // Get SDK class (for CDN usage) const SDKClass = window.ArcadiaGameSDK?.default || window.ArcadiaGameSDK?.ArcadiaSDK || window.ArcadiaGameSDK; // Create instance const arcadia = new SDKClass({ gameId: 'your-game-id', // Replace with your game ID }); // Initialize await arcadia.init(); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ NPM usage: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [JAVASCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const arcadia = new ArcadiaSDK({ gameId: 'your-game-id', }); await arcadia.init(); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Step 3: Get Wallet Address ════════════════════════════════════════════════════════════ Retrieve the player's wallet address (your primary user identifier): ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [JAVASCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const walletAddress = await arcadia.getWalletAddress(); if (!walletAddress) { // Player hasn't connected wallet in Arcadia console.log('Please connect wallet'); return; } // Use wallet address as user ID console.log('Player:', walletAddress); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Step 4: Load Player Data (Optional) ════════════════════════════════════════════════════════════ Use the wallet address to load or create player save data: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [JAVASCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ async function loadPlayerData(walletAddress) { // Load from your backend API const response = await fetch([https://your-api.com/player/${walletAddress}]); const data = await response.json(); return data; } // Or create new player data function createNewPlayer(walletAddress) { return { walletAddress, level: 1, score: 0, inventory: [], }; } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Step 5: Handle Payments (Optional) ════════════════════════════════════════════════════════════ Pay-to-Play ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [JAVASCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ try { const result = await arcadia.payment.payToPlay(0.1, 'SOL'); if (result.success) { console.log('Payment successful!', result.txSignature); // Start your game startGame(); } } catch (error) { console.error('Payment failed:', error.message); } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ In-Game Purchase ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [JAVASCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ try { const result = await arcadia.payment.purchaseItem('item-id', 0.05, 'SOL'); if (result.success) { console.log('Purchase successful!', result.txSignature); // Add item to inventory addItemToInventory('item-id'); } } catch (error) { console.error('Purchase failed:', error.message); } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Complete Minimal Example ════════════════════════════════════════════════════════════ Here's everything combined in the smallest possible working example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [HTML] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ My Game
Loading...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ What Each Step Does ════════════════════════════════════════════════════════════ Step 1: Include SDK ══════════════════════════════════════════════════ Loads the Arcadia Game SDK library into your page. Step 2: Initialize SDK ══════════════════════════════════════════════════ Sets up communication between your game and Arcadia's platform. Must be called before using any SDK features. Step 3: Get Wallet Address ══════════════════════════════════════════════════ Retrieves the player's Solana wallet address. This is your universal user identifier - use it to: • Link save data • Track player progress • Identify returning players Step 4: Load Player Data ══════════════════════════════════════════════════ Use the wallet address to fetch or create player data from your backend. This is where you implement your save system. Step 5: Handle Payments ══════════════════════════════════════════════════ Process pay-to-play or in-game purchases. The SDK handles all blockchain complexity - you just call the method and get a result. Next Steps ════════════════════════════════════════════════════════════ Once you have the basics working: 1. Add wallet change listener - Handle wallet disconnection: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [JAVASCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ arcadia.onWalletChange((connected, address) => { if (connected) { console.log('Wallet connected:', address); } else { console.log('Wallet disconnected'); } }); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2. Implement your save system - Connect Step 4 to your backend API 3. Add payment UI - Create buttons/UI for pay-to-play and purchases 4. Handle errors - Add user-friendly error messages 5. Test thoroughly - Test wallet connection, payments, and data loading Common Issues ════════════════════════════════════════════════════════════ SDK Not Loading ══════════════════════════════════════════════════ • Check internet connection • Verify CDN URL is correct • Check browser console for errors Wallet Returns Null ══════════════════════════════════════════════════ • Game must be running inside Arcadia's iframe • Player must connect wallet in Arcadia first • Ensure [init()] completed successfully Payment Fails ══════════════════════════════════════════════════ • Verify wallet has sufficient balance • Check game ID is correct • Ensure game is in Arcadia's iframe • Check console for detailed error Need More Details? ════════════════════════════════════════════════════════════ • Installation options: See Installation Guide • Wallet features: See Wallet Integration • Payment details: See Payments Guide • Complete examples: See Examples • API reference: See API Reference ──────────────────────────────────────────────────────────────────────────────── ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ SECTION: GETTING STARTED ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ Getting Started ══════════════════════════════════════════════════════════════════════ This guide will help you get up and running with the Arcadia Game SDK in just a few minutes. Prerequisites ════════════════════════════════════════════════════════════ Before you begin, make sure you have: 1. A game that runs in a browser - HTML5, JavaScript, or any web-based game framework 2. Your game hosted - The game must be accessible via URL (for iframe embedding) 3. A game ID - You'll receive this when you register your game on Arcadia 4. Basic JavaScript knowledge - Familiarity with async/await and promises Installation ════════════════════════════════════════════════════════════ Choose your preferred installation method: Option 1: NPM (Recommended for TypeScript/Modern Projects) ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [BASH] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ npm install @arcadiasol/sdk ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Option 2: CDN (Quick Start) ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [HTML] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ For detailed installation instructions, see the Installation Guide. Basic Setup ════════════════════════════════════════════════════════════ Step 1: Initialize the SDK ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { ArcadiaSDK } from '@arcadiasol/sdk'; // Create SDK instance const arcadia = new ArcadiaSDK({ gameId: 'your-game-id', // Replace with your actual game ID }); // Initialize SDK await arcadia.init(); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CDN Usage: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [HTML] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Step 2: Get Wallet Address ══════════════════════════════════════════════════ The wallet address is your primary user identifier. Use it to link save data, track progress, and identify players. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const walletAddress = await arcadia.getWalletAddress(); if (!walletAddress) { // Wallet not connected - show message to user showMessage('Please connect your wallet in Arcadia to play'); return; } // Use wallet address as user ID console.log('Player wallet:', walletAddress); // Load or create save data const saveData = await loadSaveDataByWallet(walletAddress); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Step 3: Handle Payments (Optional) ══════════════════════════════════════════════════ If your game requires payment, you can process it like this: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ try { // Pay-to-play example const result = await arcadia.payment.payToPlay(0.5, 'SOL'); console.log('Payment successful!'); console.log('Transaction:', result.txSignature); console.log('Amount:', result.amount, result.token); // Start game after successful payment startGame(); } catch (error) { console.error('Payment failed:', error.message); showError('Payment failed. Please try again.'); } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Complete Minimal Example ════════════════════════════════════════════════════════════ Here's a complete, minimal example that you can use as a starting point: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [HTML] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ My Arcadia Game
Initializing...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Next Steps ════════════════════════════════════════════════════════════ Now that you have the basics working: 1. Learn about Wallet Integration - See Wallet Integration Guide 2. Implement Payments - See Payments Guide 3. Explore Examples - See Examples for real-world use cases 4. Read the API Reference - See API Reference for complete documentation Common Setup Issues ════════════════════════════════════════════════════════════ SDK Not Loading (CDN) ══════════════════════════════════════════════════ If you're using CDN and the SDK doesn't load: 1. Check your internet connection 2. Verify the CDN URL is correct 3. Check browser console for errors 4. Try using NPM instead Wallet Not Connected ══════════════════════════════════════════════════ If [getWalletAddress()] returns [null]: 1. Make sure the game is running inside Arcadia's iframe 2. Ensure the player has connected their wallet in Arcadia 3. Check that [init()] was called successfully Payment Errors ══════════════════════════════════════════════════ If payments fail: 1. Verify the wallet has sufficient balance 2. Check that the game ID is correct 3. Ensure the game is running in Arcadia's iframe 4. See Error Handling Guide for specific error types Need Help? ════════════════════════════════════════════════════════════ • Check the FAQ for common questions • Review the Error Handling Guide for troubleshooting • See Examples for complete working code • Contact support@arcadia.com for additional assistance ──────────────────────────────────────────────────────────────────────────────── ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ SECTION: INSTALLATION ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ Installation Guide ══════════════════════════════════════════════════════════════════════ This guide covers all installation methods and setup options for the Arcadia Game SDK. Installation Methods ════════════════════════════════════════════════════════════ The SDK can be installed via NPM (recommended) or loaded via CDN. Choose the method that best fits your project. NPM Installation ════════════════════════════════════════════════════════════ Install the Package ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [BASH] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ npm install @arcadiasol/sdk ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Or with yarn: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [BASH] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ yarn add @arcadiasol/sdk ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Or with pnpm: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [BASH] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ pnpm add @arcadiasol/sdk ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Import in Your Code ══════════════════════════════════════════════════ ES Modules (Recommended) ────────────────────────────────────────────────── ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { ArcadiaSDK } from '@arcadiasol/sdk'; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CommonJS ────────────────────────────────────────────────── ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [JAVASCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const { ArcadiaSDK } = require('@arcadiasol/sdk'); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ TypeScript Support ══════════════════════════════════════════════════ TypeScript definitions are included automatically. No additional installation needed. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { ArcadiaSDK, SDKConfig, PaymentResult } from '@arcadiasol/sdk'; const config: SDKConfig = { gameId: 'my-game', }; const arcadia = new ArcadiaSDK(config); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CDN Installation ════════════════════════════════════════════════════════════ Development (Unminified) ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [HTML] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Production (Minified) ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [HTML] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Using the SDK (CDN) ══════════════════════════════════════════════════ When using CDN, the SDK is available as a global variable: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [HTML] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Note: The UMD bundle may expose the SDK in different ways depending on your environment. Check what's available: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [JAVASCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // Check available SDK exports console.log(window.ArcadiaGameSDK); // Common patterns: const SDKClass = window.ArcadiaGameSDK?.default || window.ArcadiaGameSDK?.ArcadiaSDK || window.ArcadiaGameSDK; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Build Configuration ════════════════════════════════════════════════════════════ Webpack ══════════════════════════════════════════════════ No special configuration needed. The SDK is already bundled. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [JAVASCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // webpack.config.js module.exports = { // ... your config resolve: { extensions: ['.ts', '.tsx', '.js', '.jsx'], }, }; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Vite ══════════════════════════════════════════════════ No special configuration needed. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [JAVASCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // vite.config.js export default { // ... your config }; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Rollup ══════════════════════════════════════════════════ No special configuration needed. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [JAVASCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // rollup.config.js export default { // ... your config }; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Parcel ══════════════════════════════════════════════════ No special configuration needed. Parcel handles everything automatically. Package Entry Points ════════════════════════════════════════════════════════════ The SDK provides multiple entry points: • ESM: [dist/esm/index.js] - ES Module format • UMD: [dist/umd/arcadia-game-sdk.js] - Universal Module Definition • Types: [dist/esm/index.d.ts] - TypeScript definitions Using Specific Entry Points ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // ESM (if you need to import from specific path) import { ArcadiaSDK } from '@arcadiasol/sdk/dist/esm/index.js'; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Version Pinning ════════════════════════════════════════════════════════════ Latest Version ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [BASH] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ npm install @arcadiasol/sdk@latest ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Specific Version ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [BASH] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ npm install @arcadiasol/sdk@1.0.0 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Version Range ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [JSON] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ { "dependencies": { "@arcadiasol/sdk": "^1.1.0" } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Browser Compatibility ════════════════════════════════════════════════════════════ The SDK works in all modern browsers: • Chrome 90+ • Firefox 88+ • Safari 14+ • Edge 90+ Polyfills ══════════════════════════════════════════════════ The SDK requires: • ES2020 support • postMessage API • Promise support Most modern browsers include these by default. For older browsers, you may need polyfills: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [BASH] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ npm install core-js ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [JAVASCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import 'core-js/stable'; import 'core-js/features/promise'; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Bundle Size ════════════════════════════════════════════════════════════ • UMD (minified): ~15KB gzipped • ESM: ~12KB gzipped • Zero dependencies - No additional packages required Verification ════════════════════════════════════════════════════════════ After installation, verify the SDK is working: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { ArcadiaSDK } from '@arcadiasol/sdk'; // Check SDK is available console.log(ArcadiaSDK); // Should log the class // Create instance const arcadia = new ArcadiaSDK({ gameId: 'your-game-id', }); console.log('SDK initialized:', arcadia.isInitialized()); // false (not yet initialized) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Troubleshooting ════════════════════════════════════════════════════════════ Module Not Found ══════════════════════════════════════════════════ If you get "Module not found" errors: 1. Verify the package is installed: [npm list @arcadiasol/sdk] 2. Check your import path is correct 3. Restart your development server 4. Clear node_modules and reinstall: [rm -rf node_modules && npm install] TypeScript Errors ══════════════════════════════════════════════════ If TypeScript can't find types: 1. Ensure [@arcadiasol/sdk] is in your [package.json] 2. Check [tsconfig.json] includes [node_modules] in type roots 3. Restart your TypeScript server CDN Not Loading ══════════════════════════════════════════════════ If CDN script doesn't load: 1. Check your internet connection 2. Verify the URL is correct 3. Check browser console for CORS errors 4. Try a different CDN or use NPM instead Build Errors ══════════════════════════════════════════════════ If you encounter build errors: 1. Ensure your bundler supports ES2020 2. Check for conflicting dependencies 3. Verify your Node.js version (requires Node 20+) Next Steps ════════════════════════════════════════════════════════════ Once installation is complete: 1. See Getting Started for basic setup 2. Review Wallet Integration for wallet features 3. Check Payments for payment implementation ──────────────────────────────────────────────────────────────────────────────── ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ SECTION: WALLET INTEGRATION ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ Wallet Integration Guide ══════════════════════════════════════════════════════════════════════ This guide covers everything you need to know about integrating wallet functionality into your game using the Arcadia Game SDK. Overview ════════════════════════════════════════════════════════════ The Arcadia Game SDK provides seamless access to the player's connected Solana wallet. The wallet address serves as a universal user identifier, allowing you to: • Link save data to specific players • Track player progress across sessions • Identify returning players • Enable wallet-based features Why Use Wallet Address as User ID? ════════════════════════════════════════════════════════════ Using the wallet address as your primary user identifier offers several advantages: 1. Universal Identity - Works across all games and platforms 2. No Authentication Required - Players don't need to create accounts 3. Persistent - Wallet addresses don't change 4. Secure - Cryptographically secure identifiers 5. Web3 Native - Aligns with blockchain gaming standards Getting the Wallet Address ════════════════════════════════════════════════════════════ Basic Usage ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { ArcadiaSDK } from '@arcadiasol/sdk'; const arcadia = new ArcadiaSDK({ gameId: 'your-game-id', }); await arcadia.init(); // Get wallet address const walletAddress = await arcadia.getWalletAddress(); if (!walletAddress) { // Wallet not connected showMessage('Please connect your wallet in Arcadia to play'); return; } // Use wallet address as user ID console.log('Player wallet:', walletAddress); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Handling No Wallet ══════════════════════════════════════════════════ Always check if the wallet address is [null] before using it: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const walletAddress = await arcadia.getWalletAddress(); if (!walletAddress) { // Handle no wallet scenario showWalletConnectionPrompt(); return; } // Proceed with wallet address loadPlayerData(walletAddress); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Checking Wallet Connection Status ════════════════════════════════════════════════════════════ Simple Check ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const isConnected = await arcadia.isWalletConnected(); if (!isConnected) { showMessage('Please connect your wallet'); return; } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Combined Check ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const walletAddress = await arcadia.getWalletAddress(); const isConnected = walletAddress !== null; if (!isConnected) { // Show connection prompt return; } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Listening for Wallet Changes ════════════════════════════════════════════════════════════ The SDK allows you to listen for wallet connection/disconnection events in real-time. Basic Listener ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ arcadia.onWalletChange((connected, address) => { if (connected && address) { console.log('Wallet connected:', address); // Resume game or load player data loadPlayerData(address); } else { console.log('Wallet disconnected'); // Pause game or show connection prompt pauseGame(); showWalletConnectionPrompt(); } }); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Game State Management ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ let currentWalletAddress: string | null = null; arcadia.onWalletChange((connected, address) => { if (connected && address) { // Wallet connected or changed if (currentWalletAddress && currentWalletAddress !== address) { // Different wallet connected - save current game and load new player saveGameData(currentWalletAddress); currentWalletAddress = address; loadPlayerData(address); } else { // Same wallet or first connection currentWalletAddress = address; if (!isGameLoaded()) { loadPlayerData(address); } } } else { // Wallet disconnected if (currentWalletAddress) { // Save current game state saveGameData(currentWalletAddress); currentWalletAddress = null; } pauseGame(); showMessage('Wallet disconnected. Please reconnect to continue.'); } }); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Removing Listeners ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const handleWalletChange = (connected: boolean, address: string | null) => { // Your handler logic }; // Add listener arcadia.onWalletChange(handleWalletChange); // Later, remove listener arcadia.offWalletChange(handleWalletChange); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Account Linking Patterns ════════════════════════════════════════════════════════════ Pattern 1: Simple Save Data Linking ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // Save game data async function saveGameData(walletAddress: string, gameData: any) { // Store in your database using wallet address as key await fetch('/api/save-game', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ walletAddress, gameData, }), }); } // Load game data async function loadGameData(walletAddress: string) { const response = await fetch([/api/load-game?wallet=${walletAddress}]); const data = await response.json(); return data.gameData; } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Pattern 2: First-Time Player Detection ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ async function initializePlayer(walletAddress: string) { // Check if player exists const existingData = await loadGameData(walletAddress); if (existingData) { // Returning player - load their data return existingData; } else { // First-time player - create new save const newPlayerData = { walletAddress, level: 1, score: 0, inventory: [], createdAt: new Date().toISOString(), }; await saveGameData(walletAddress, newPlayerData); return newPlayerData; } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Pattern 3: Multi-Game Account Linking ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // Use wallet address to link accounts across multiple games async function getPlayerProfile(walletAddress: string) { const response = await fetch([/api/player-profile?wallet=${walletAddress}]); return response.json(); } // Profile might include: // - Games played // - Total achievements // - Cross-game statistics // - Friends list ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Complete Example ════════════════════════════════════════════════════════════ Here's a complete example showing wallet integration: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { ArcadiaSDK, WalletNotConnectedError } from '@arcadiasol/sdk'; class GameManager { private arcadia: ArcadiaSDK; private walletAddress: string | null = null; private playerData: any = null; constructor(gameId: string) { this.arcadia = new ArcadiaSDK({ gameId }); } async initialize() { try { // Initialize SDK await this.arcadia.init(); // Get wallet address this.walletAddress = await this.arcadia.getWalletAddress(); if (!this.walletAddress) { throw new WalletNotConnectedError(); } // Load or create player data this.playerData = await this.loadOrCreatePlayerData(this.walletAddress); // Set up wallet change listener this.arcadia.onWalletChange((connected, address) => { this.handleWalletChange(connected, address); }); // Start game this.startGame(); } catch (error) { if (error instanceof WalletNotConnectedError) { this.showWalletConnectionPrompt(); } else { console.error('Initialization error:', error); this.showError('Failed to initialize game'); } } } private async loadOrCreatePlayerData(walletAddress: string) { // Try to load existing data const existing = await this.loadPlayerData(walletAddress); if (existing) { return existing; } // Create new player data const newData = { walletAddress, level: 1, score: 0, inventory: [], lastPlayed: new Date().toISOString(), }; await this.savePlayerData(walletAddress, newData); return newData; } private async loadPlayerData(walletAddress: string) { // Implement your data loading logic const response = await fetch([/api/player-data?wallet=${walletAddress}]); if (response.ok) { return response.json(); } return null; } private async savePlayerData(walletAddress: string, data: any) { // Implement your data saving logic await fetch('/api/player-data', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ walletAddress, data }), }); } private handleWalletChange(connected: boolean, address: string | null) { if (connected && address) { if (this.walletAddress && this.walletAddress !== address) { // Different wallet - save current and load new this.savePlayerData(this.walletAddress, this.playerData); this.walletAddress = address; this.loadOrCreatePlayerData(address).then(data => { this.playerData = data; }); } else { // Same wallet or first connection this.walletAddress = address; } } else { // Wallet disconnected if (this.walletAddress) { this.savePlayerData(this.walletAddress, this.playerData); this.pauseGame(); this.showMessage('Wallet disconnected. Please reconnect.'); } } } private startGame() { // Start your game with loaded player data console.log('Game started for player:', this.walletAddress); } private pauseGame() { // Pause game logic console.log('Game paused'); } private showWalletConnectionPrompt() { // Show UI prompt for wallet connection console.log('Please connect your wallet'); } private showMessage(message: string) { // Show message to user console.log(message); } private showError(message: string) { // Show error to user console.error(message); } } // Usage const gameManager = new GameManager('your-game-id'); gameManager.initialize(); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Best Practices ════════════════════════════════════════════════════════════ 1. Always Check for Null - Wallet address can be [null] if not connected 2. Handle Disconnections - Save game state when wallet disconnects 3. Listen for Changes - Use [onWalletChange] to react to connection changes 4. Save Frequently - Save player data regularly, not just on disconnect 5. Validate Wallet Address - Ensure wallet address is valid before using it 6. Handle Wallet Switching - Players may switch wallets during gameplay Common Patterns ════════════════════════════════════════════════════════════ Auto-Save on Wallet Disconnect ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ arcadia.onWalletChange((connected, address) => { if (!connected && this.walletAddress) { // Auto-save when wallet disconnects this.autoSave(); } }); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Prevent Gameplay Without Wallet ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ function canPlay(): boolean { return this.walletAddress !== null; } function attemptAction() { if (!canPlay()) { showMessage('Please connect your wallet to play'); return; } // Proceed with action } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Next Steps ════════════════════════════════════════════════════════════ • Learn about Payments to enable in-game purchases • Check Examples for more wallet integration patterns • Review API Reference for complete method documentation ──────────────────────────────────────────────────────────────────────────────── ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ SECTION: PAYMENTS ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ Payments Guide ══════════════════════════════════════════════════════════════════════ This guide covers implementing pay-to-play and in-game purchases using the Arcadia Game SDK. Overview ════════════════════════════════════════════════════════════ The Arcadia Game SDK handles all payment complexity for you. You simply request a payment with an amount and token type, and the SDK: 1. Prompts the player to approve the transaction 2. Sends the transaction to the blockchain 3. Returns complete payment details immediately 4. Handles fee calculation and developer payouts automatically Payment Types ════════════════════════════════════════════════════════════ Pay-to-Play ══════════════════════════════════════════════════ One-time payment required to access or start a game. Typically used for: • Game access fees • Premium game modes • One-time unlocks In-Game Purchases ══════════════════════════════════════════════════ Purchases made during gameplay. Typically used for: • Items and equipment • Upgrades and power-ups • Cosmetics and skins • Currency packs Payment Flow ════════════════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [MERMAID] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sequenceDiagram participant Game participant SDK participant Arcadia participant Wallet participant Blockchain Game->>SDK: payment.payToPlay(amount, token) SDK->>Arcadia: Payment request via postMessage Arcadia->>Wallet: Request transaction approval Wallet->>Blockchain: Send transaction Blockchain-->>Wallet: Transaction signature Wallet-->>Arcadia: Transaction confirmed Arcadia->>SDK: Payment result with details SDK-->>Game: PaymentResult object ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Pay-to-Play Implementation ════════════════════════════════════════════════════════════ Basic Example ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { ArcadiaSDK, PaymentFailedError } from '@arcadiasol/sdk'; try { const result = await arcadia.payment.payToPlay(0.5, 'SOL'); // Payment successful! console.log('Payment successful!'); console.log('Transaction:', result.txSignature); console.log('Amount:', result.amount, result.token); console.log('Timestamp:', result.timestamp); // Start game startGame(); } catch (error) { if (error instanceof PaymentFailedError) { console.error('Payment failed:', error.message); showError('Payment failed. Please try again.'); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ With Payment Verification ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ async function handlePayToPlay(requiredAmount: number) { try { const result = await arcadia.payment.payToPlay(requiredAmount, 'SOL'); // Verify payment details if (result.success && result.amount === requiredAmount && result.token === 'SOL') { // Payment verified - proceed await markPlayerAsPaid(walletAddress); await logPayment(result); startGame(); } else { throw new Error('Payment verification failed'); } } catch (error) { handlePaymentError(error); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Complete Pay-to-Play Flow ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class GamePaymentManager { private arcadia: ArcadiaSDK; private walletAddress: string | null = null; constructor(arcadia: ArcadiaSDK) { this.arcadia = arcadia; } async checkPaymentRequired(): Promise { if (!this.walletAddress) { this.walletAddress = await this.arcadia.getWalletAddress(); } // Check if player has already paid const playerData = await this.loadPlayerData(this.walletAddress!); return !playerData.hasPaid; } async processPayToPlay(amount: number, token: 'SOL' | 'USDC'): Promise { try { const result = await this.arcadia.payment.payToPlay(amount, token); // Verify payment if (!result.success || result.amount !== amount) { throw new Error('Payment verification failed'); } // Update player data await this.markAsPaid(this.walletAddress!, result); // Log payment for analytics await this.logPayment(result); return true; } catch (error) { console.error('Payment error:', error); return false; } } private async markAsPaid(walletAddress: string, paymentResult: PaymentResult) { const playerData = await this.loadPlayerData(walletAddress); playerData.hasPaid = true; playerData.paymentTx = paymentResult.txSignature; playerData.paidAt = paymentResult.timestamp; await this.savePlayerData(walletAddress, playerData); } private async logPayment(result: PaymentResult) { // Log to your analytics service await fetch('/api/analytics/payment', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'pay_to_play', ...result, }), }); } private async loadPlayerData(walletAddress: string) { // Load player data const response = await fetch([/api/player-data?wallet=${walletAddress}]); return response.json(); } private async savePlayerData(walletAddress: string, data: any) { // Save player data await fetch('/api/player-data', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ walletAddress, data }), }); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ In-Game Purchases ════════════════════════════════════════════════════════════ Basic Example ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ async function purchaseItem(itemId: string, price: number) { try { const result = await arcadia.payment.purchaseItem(itemId, price, 'SOL'); // Verify purchase if (result.success && result.amount === price) { // Add item to inventory addItemToInventory(itemId); // Update player data await savePurchase(walletAddress, { itemId, ...result, }); showSuccess('Item purchased successfully!'); } } catch (error) { console.error('Purchase failed:', error); showError('Purchase failed. Please try again.'); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Item Shop Implementation ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class ItemShop { private arcadia: ArcadiaSDK; private walletAddress: string | null = null; constructor(arcadia: ArcadiaSDK) { this.arcadia = arcadia; } async buyItem(item: ShopItem) { if (!this.walletAddress) { this.walletAddress = await this.arcadia.getWalletAddress(); if (!this.walletAddress) { showError('Please connect your wallet'); return; } } try { // Show loading state showLoading([Purchasing ${item.name}...]); // Process purchase const result = await this.arcadia.payment.purchaseItem( item.id, item.price, item.token ); // Verify purchase if (result.success && result.amount === item.price && result.token === item.token) { // Add item to inventory await this.addToInventory(this.walletAddress, item.id); // Update player balance await this.updatePlayerBalance(this.walletAddress, -item.price); // Log purchase await this.logPurchase(item, result); showSuccess([${item.name} purchased successfully!]); } else { throw new Error('Purchase verification failed'); } } catch (error) { console.error('Purchase error:', error); showError('Purchase failed: ' + error.message); } finally { hideLoading(); } } private async addToInventory(walletAddress: string, itemId: string) { const playerData = await this.loadPlayerData(walletAddress); if (!playerData.inventory) { playerData.inventory = []; } playerData.inventory.push(itemId); await this.savePlayerData(walletAddress, playerData); } private async updatePlayerBalance(walletAddress: string, amount: number) { // Update player's in-game balance const playerData = await this.loadPlayerData(walletAddress); playerData.balance = (playerData.balance || 0) + amount; await this.savePlayerData(walletAddress, playerData); } private async logPurchase(item: ShopItem, result: PaymentResult) { await fetch('/api/analytics/purchase', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ itemId: item.id, itemName: item.name, ...result, }), }); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Payment Result Structure ════════════════════════════════════════════════════════════ The [PaymentResult] object contains all payment details: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ interface PaymentResult { success: boolean; // Whether payment was successful txSignature: string; // Blockchain transaction signature amount: number; // Amount paid by user token: 'SOL' | 'USDC'; // Token type used timestamp: string; // ISO timestamp when payment completed purchaseId?: string; // Arcadia purchase ID (for tracking) platformFee?: number; // Platform fee deducted developerAmount?: number; // Amount received by developer (after fees) error?: string; // Error message if payment failed } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Using Payment Details ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const result = await arcadia.payment.payToPlay(0.5, 'SOL'); // Store in your database await savePaymentRecord({ walletAddress: walletAddress, txSignature: result.txSignature, amount: result.amount, token: result.token, timestamp: result.timestamp, purchaseId: result.purchaseId, platformFee: result.platformFee, developerAmount: result.developerAmount, }); // Use for analytics trackEvent('payment_completed', { amount: result.amount, token: result.token, platformFee: result.platformFee, }); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Error Handling ════════════════════════════════════════════════════════════ Common Payment Errors ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { PaymentFailedError, WalletNotConnectedError, InvalidAmountError, InvalidTokenError, TimeoutError, } from '@arcadiasol/sdk'; try { const result = await arcadia.payment.payToPlay(0.5, 'SOL'); } catch (error) { if (error instanceof WalletNotConnectedError) { showError('Please connect your wallet to make a payment'); } else if (error instanceof PaymentFailedError) { showError('Payment failed: ' + error.message); // Check error.txSignature if available } else if (error instanceof InvalidAmountError) { showError('Invalid payment amount'); } else if (error instanceof InvalidTokenError) { showError('Invalid token type. Use SOL or USDC'); } else if (error instanceof TimeoutError) { showError('Payment request timed out. Please try again.'); } else { showError('An unexpected error occurred'); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Retry Logic ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ async function payToPlayWithRetry(amount: number, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { const result = await arcadia.payment.payToPlay(amount, 'SOL'); return result; } catch (error) { if (i === maxRetries - 1) { throw error; // Last attempt failed } // Wait before retry await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); } } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Best Practices ════════════════════════════════════════════════════════════ 1. Verify Payment Amount - Always verify the returned amount matches what you requested 2. Store Transaction Signatures - Keep transaction signatures for record-keeping 3. Handle Errors Gracefully - Provide clear error messages to users 4. Show Loading States - Indicate when payment is processing 5. Don't Block on Payment - Payments return immediately after transaction is sent 6. Log All Payments - Keep records for analytics and debugging 7. Validate Before Processing - Check payment details before granting items/access Payment Timing ════════════════════════════════════════════════════════════ Payments return immediately after the transaction is sent to the blockchain. The SDK doesn't wait for full confirmation, making the payment experience instant for players. However, you should: • Trust the payment result for immediate game actions • Use transaction signatures for verification if needed • Handle edge cases where transactions might fail after initial success Next Steps ════════════════════════════════════════════════════════════ • Review API Reference for complete payment method documentation • Check Examples for complete payment implementations • Read Error Handling for detailed error information ──────────────────────────────────────────────────────────────────────────────── ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ SECTION: API REFERENCE ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ API Reference ══════════════════════════════════════════════════════════════════════ Complete reference documentation for all Arcadia Game SDK methods, types, and interfaces. ArcadiaSDK Class ════════════════════════════════════════════════════════════ The main SDK class that provides all functionality. Constructor ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ new ArcadiaSDK(config: SDKConfig) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Creates a new SDK instance. Parameters: • [config.gameId] (string, required) - Your unique game identifier • [config.parentOrigin] (string, optional) - Parent window origin for security (default: ['']) • [config.timeout] (number, optional) - Request timeout in milliseconds (default: [30000]) Throws: • [InvalidConfigError] - If [gameId] is missing or invalid Example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const arcadia = new ArcadiaSDK({ gameId: 'my-awesome-game', parentOrigin: 'https://arcadia.com', // Optional timeout: 30000, // Optional }); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Methods ══════════════════════════════════════════════════ [init(): Promise] ────────────────────────────────────────────────── Initializes the SDK and requests initialization data from the parent window. Must be called after creating the SDK instance. Returns: Promise that resolves when initialization is complete Example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ await arcadia.init(); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [getWalletAddress(): Promise] ────────────────────────────────────────────────── Gets the connected wallet address. Use this as your primary user identifier. Returns: • [string] - Wallet address if connected • [null] - If wallet is not connected Example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const walletAddress = await arcadia.getWalletAddress(); if (!walletAddress) { console.log('Wallet not connected'); } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [isWalletConnected(): Promise] ────────────────────────────────────────────────── Checks if a wallet is currently connected. Returns: • [true] - If wallet is connected • [false] - If wallet is not connected Example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const connected = await arcadia.isWalletConnected(); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [onWalletChange(callback: (connected: boolean, address: string | null) => void): void] ────────────────────────────────────────────────── Registers a callback to listen for wallet connection changes. Parameters: • [callback] - Function called when wallet connection status changes - [connected] (boolean) - Whether wallet is connected - [address] (string | null) - Wallet address or null Example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ arcadia.onWalletChange((connected, address) => { if (connected) { console.log('Wallet connected:', address); } else { console.log('Wallet disconnected'); } }); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [offWalletChange(callback: Function): void] ────────────────────────────────────────────────── Removes a wallet change listener. Parameters: • [callback] - The callback function to remove Example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const handler = (connected, address) => { / ... / }; arcadia.onWalletChange(handler); // Later... arcadia.offWalletChange(handler); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [isInIframe(): boolean] ────────────────────────────────────────────────── Checks if the SDK is running in an iframe environment. Returns: • [true] - If running in iframe • [false] - If not in iframe Example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ if (arcadia.isInIframe()) { console.log('Running in Arcadia iframe'); } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [isInitialized(): boolean] ────────────────────────────────────────────────── Checks if the SDK has been initialized. Returns: • [true] - If initialized • [false] - If not initialized Example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ if (arcadia.isInitialized()) { // SDK is ready } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [getConfig(): SDKConfig] ────────────────────────────────────────────────── Gets the current SDK configuration. Returns: SDK configuration object Example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const config = arcadia.getConfig(); console.log('Game ID:', config.gameId); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [destroy(): void] ────────────────────────────────────────────────── Cleans up SDK resources. Call this when the game is unloaded. Example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ arcadia.destroy(); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Payment Methods ════════════════════════════════════════════════════════════ [payment.payToPlay(amount: number, token: 'SOL' | 'USDC'): Promise] ══════════════════════════════════════════════════ Processes a pay-to-play payment (one-time payment to access game). Parameters: • [amount] (number) - Payment amount (must be > 0) • [token] ('SOL' | 'USDC') - Token type Returns: Promise that resolves to [PaymentResult] Throws: • [WalletNotConnectedError] - If wallet is not connected • [InvalidAmountError] - If amount is invalid • [InvalidTokenError] - If token is invalid • [PaymentFailedError] - If payment fails • [NotInIframeError] - If not running in iframe Example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const result = await arcadia.payment.payToPlay(0.5, 'SOL'); console.log('Payment successful:', result.txSignature); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [payment.purchaseItem(itemId: string, amount: number, token: 'SOL' | 'USDC'): Promise] ══════════════════════════════════════════════════ Purchases an in-game item. Parameters: • [itemId] (string) - Unique item identifier • [amount] (number) - Payment amount (must be > 0) • [token] ('SOL' | 'USDC') - Token type Returns: Promise that resolves to [PaymentResult] Throws: • [WalletNotConnectedError] - If wallet is not connected • [InvalidAmountError] - If amount is invalid • [InvalidTokenError] - If token is invalid • [PaymentFailedError] - If payment fails • [NotInIframeError] - If not running in iframe • [Error] - If itemId is missing or invalid Example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const result = await arcadia.payment.purchaseItem('sword-001', 1.0, 'SOL'); console.log('Purchase successful:', result.txSignature); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Type Definitions ════════════════════════════════════════════════════════════ SDKConfig ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ interface SDKConfig { gameId: string; // Required: Unique game identifier parentOrigin?: string; // Optional: Parent window origin (default: '') timeout?: number; // Optional: Request timeout in ms (default: 30000) } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ PaymentResult ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ interface PaymentResult { success: boolean; // Whether payment was successful txSignature: string; // Blockchain transaction signature amount: number; // Amount paid by user token: 'SOL' | 'USDC'; // Token type used timestamp: string; // ISO timestamp when payment completed purchaseId?: string; // Arcadia purchase ID (for tracking) platformFee?: number; // Platform fee deducted developerAmount?: number; // Amount received by developer (after fees) error?: string; // Error message if payment failed } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ WalletInfo ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ interface WalletInfo { connected: boolean; // Whether wallet is connected address: string | null; // Wallet address or null if not connected } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ InitData ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ interface InitData { gameId: string; // Game ID userId: string; // User ID wallet: WalletInfo; // Wallet information } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ WalletAddressResponse ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ interface WalletAddressResponse { walletAddress: string | null; // Wallet address or null connected: boolean; // Whether wallet is connected } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Error Classes ════════════════════════════════════════════════════════════ ArcadiaSDKError ══════════════════════════════════════════════════ Base error class for all SDK errors. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class ArcadiaSDKError extends Error { code?: string; message: string; } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ WalletNotConnectedError ══════════════════════════════════════════════════ Thrown when wallet operations are attempted without a connected wallet. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class WalletNotConnectedError extends ArcadiaSDKError { code: 'WALLET_NOT_CONNECTED'; } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ PaymentFailedError ══════════════════════════════════════════════════ Thrown when a payment fails. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class PaymentFailedError extends ArcadiaSDKError { code: 'PAYMENT_FAILED'; txSignature?: string; // Transaction signature if available } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ TimeoutError ══════════════════════════════════════════════════ Thrown when a request times out. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class TimeoutError extends ArcadiaSDKError { code: 'TIMEOUT'; } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ InvalidConfigError ══════════════════════════════════════════════════ Thrown when SDK configuration is invalid. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class InvalidConfigError extends ArcadiaSDKError { code: 'INVALID_CONFIG'; } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ NotInIframeError ══════════════════════════════════════════════════ Thrown when SDK methods are called outside of an iframe. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class NotInIframeError extends ArcadiaSDKError { code: 'NOT_IN_IFRAME'; } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ InvalidAmountError ══════════════════════════════════════════════════ Thrown when an invalid payment amount is provided. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class InvalidAmountError extends ArcadiaSDKError { code: 'INVALID_AMOUNT'; } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ InvalidTokenError ══════════════════════════════════════════════════ Thrown when an invalid token type is provided. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class InvalidTokenError extends ArcadiaSDKError { code: 'INVALID_TOKEN'; } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Importing Types and Errors ════════════════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // Import SDK class import { ArcadiaSDK } from '@arcadiasol/sdk'; // Import types import type { SDKConfig, PaymentResult, WalletInfo, } from '@arcadiasol/sdk'; // Import error classes import { ArcadiaSDKError, WalletNotConnectedError, PaymentFailedError, TimeoutError, InvalidConfigError, NotInIframeError, InvalidAmountError, InvalidTokenError, } from '@arcadiasol/sdk'; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CDN Usage ════════════════════════════════════════════════════════════ When using CDN, the SDK is available as a global variable: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [JAVASCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // SDK class const ArcadiaSDK = window.ArcadiaGameSDK?.default || window.ArcadiaGameSDK?.ArcadiaSDK || window.ArcadiaGameSDK; const arcadia = new ArcadiaSDK({ gameId: 'your-game-id', }); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Next Steps ════════════════════════════════════════════════════════════ • See Examples for complete usage examples • Review Error Handling for error handling patterns • Check Wallet Integration for wallet features • Read Payments for payment implementation ──────────────────────────────────────────────────────────────────────────────── ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ SECTION: EXAMPLES ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ Examples ══════════════════════════════════════════════════════════════════════ Complete, working examples for common use cases with the Arcadia Game SDK. Table of Contents ════════════════════════════════════════════════════════════ • Basic Integration • Wallet Integration • Pay-to-Play • In-Game Purchases • Complete Game Example • TypeScript Example • Error Handling Basic Integration ════════════════════════════════════════════════════════════ Minimal example showing SDK initialization and wallet address retrieval. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [HTML] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Basic SDK Integration
Initializing...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Wallet Integration ════════════════════════════════════════════════════════════ Complete wallet integration with change listeners. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { ArcadiaSDK, WalletNotConnectedError } from '@arcadiasol/sdk'; class WalletManager { private arcadia: ArcadiaSDK; private walletAddress: string | null = null; private onConnectCallbacks: Array<(address: string) => void> = []; private onDisconnectCallbacks: Array<() => void> = []; constructor(gameId: string) { this.arcadia = new ArcadiaSDK({ gameId }); } async initialize() { await this.arcadia.init(); // Get initial wallet address this.walletAddress = await this.arcadia.getWalletAddress(); // Listen for wallet changes this.arcadia.onWalletChange((connected, address) => { if (connected && address) { this.handleConnect(address); } else { this.handleDisconnect(); } }); return this.walletAddress; } private handleConnect(address: string) { const wasConnected = this.walletAddress !== null; this.walletAddress = address; if (!wasConnected) { // First connection this.onConnectCallbacks.forEach(cb => cb(address)); } else if (this.walletAddress !== address) { // Wallet changed this.onDisconnectCallbacks.forEach(cb => cb()); this.onConnectCallbacks.forEach(cb => cb(address)); } } private handleDisconnect() { if (this.walletAddress) { this.walletAddress = null; this.onDisconnectCallbacks.forEach(cb => cb()); } } onConnect(callback: (address: string) => void) { this.onConnectCallbacks.push(callback); } onDisconnect(callback: () => void) { this.onDisconnectCallbacks.push(callback); } getAddress(): string | null { return this.walletAddress; } } // Usage const walletManager = new WalletManager('your-game-id'); await walletManager.initialize(); walletManager.onConnect((address) => { console.log('Wallet connected:', address); loadPlayerData(address); }); walletManager.onDisconnect(() => { console.log('Wallet disconnected'); saveGameState(); pauseGame(); }); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Pay-to-Play ════════════════════════════════════════════════════════════ Complete pay-to-play implementation with verification. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { ArcadiaSDK, PaymentFailedError, WalletNotConnectedError } from '@arcadiasol/sdk'; class PayToPlayManager { private arcadia: ArcadiaSDK; private walletAddress: string | null = null; private hasPaid: boolean = false; constructor(gameId: string) { this.arcadia = new ArcadiaSDK({ gameId }); } async initialize() { await this.arcadia.init(); this.walletAddress = await this.arcadia.getWalletAddress(); if (!this.walletAddress) { throw new WalletNotConnectedError(); } // Check if already paid this.hasPaid = await this.checkPaymentStatus(this.walletAddress); } async checkPaymentRequired(): Promise { return !this.hasPaid; } async processPayment(amount: number, token: 'SOL' | 'USDC'): Promise { if (!this.walletAddress) { throw new WalletNotConnectedError(); } try { showLoading('Processing payment...'); const result = await this.arcadia.payment.payToPlay(amount, token); // Verify payment if (!result.success || result.amount !== amount) { throw new PaymentFailedError('Payment verification failed'); } // Mark as paid await this.markAsPaid(this.walletAddress, result); this.hasPaid = true; // Log payment await this.logPayment(result); return true; } catch (error) { if (error instanceof PaymentFailedError) { showError('Payment failed: ' + error.message); } else if (error instanceof WalletNotConnectedError) { showError('Please connect your wallet'); } else { showError('An error occurred'); } return false; } finally { hideLoading(); } } private async checkPaymentStatus(walletAddress: string): Promise { const response = await fetch([/api/payment-status?wallet=${walletAddress}]); const data = await response.json(); return data.hasPaid || false; } private async markAsPaid(walletAddress: string, result: PaymentResult) { await fetch('/api/mark-paid', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ walletAddress, txSignature: result.txSignature, amount: result.amount, token: result.token, timestamp: result.timestamp, }), }); } private async logPayment(result: PaymentResult) { await fetch('/api/analytics/payment', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(result), }); } } // Usage const paymentManager = new PayToPlayManager('your-game-id'); await paymentManager.initialize(); if (await paymentManager.checkPaymentRequired()) { const paid = await paymentManager.processPayment(0.5, 'SOL'); if (paid) { startGame(); } } else { startGame(); } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ In-Game Purchases ════════════════════════════════════════════════════════════ Complete item shop implementation. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { ArcadiaSDK, PaymentFailedError } from '@arcadiasol/sdk'; interface ShopItem { id: string; name: string; price: number; token: 'SOL' | 'USDC'; description: string; } class ItemShop { private arcadia: ArcadiaSDK; private walletAddress: string | null = null; private inventory: string[] = []; constructor(gameId: string) { this.arcadia = new ArcadiaSDK({ gameId }); } async initialize() { await this.arcadia.init(); this.walletAddress = await this.arcadia.getWalletAddress(); this.inventory = await this.loadInventory(this.walletAddress!); } async purchaseItem(item: ShopItem): Promise { if (!this.walletAddress) { showError('Please connect your wallet'); return false; } try { showLoading([Purchasing ${item.name}...]); const result = await this.arcadia.payment.purchaseItem( item.id, item.price, item.token ); // Verify purchase if (!result.success || result.amount !== item.price || result.token !== item.token) { throw new PaymentFailedError('Purchase verification failed'); } // Add to inventory this.inventory.push(item.id); await this.saveInventory(this.walletAddress, this.inventory); // Log purchase await this.logPurchase(item, result); showSuccess([${item.name} purchased!]); return true; } catch (error) { if (error instanceof PaymentFailedError) { showError('Purchase failed: ' + error.message); } else { showError('An error occurred'); } return false; } finally { hideLoading(); } } hasItem(itemId: string): boolean { return this.inventory.includes(itemId); } private async loadInventory(walletAddress: string): Promise { const response = await fetch([/api/inventory?wallet=${walletAddress}]); const data = await response.json(); return data.inventory || []; } private async saveInventory(walletAddress: string, inventory: string[]) { await fetch('/api/inventory', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ walletAddress, inventory }), }); } private async logPurchase(item: ShopItem, result: PaymentResult) { await fetch('/api/analytics/purchase', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ itemId: item.id, itemName: item.name, ...result, }), }); } } // Usage const shop = new ItemShop('your-game-id'); await shop.initialize(); const item: ShopItem = { id: 'sword-001', name: 'Legendary Sword', price: 1.0, token: 'SOL', description: 'A powerful sword', }; const purchased = await shop.purchaseItem(item); if (purchased) { console.log('Item added to inventory!'); } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Complete Game Example ════════════════════════════════════════════════════════════ Full game integration with wallet, payments, and save data. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { ArcadiaSDK, WalletNotConnectedError, PaymentFailedError } from '@arcadiasol/sdk'; class Game { private arcadia: ArcadiaSDK; private walletAddress: string | null = null; private playerData: any = null; private shop: ItemShop; constructor(gameId: string) { this.arcadia = new ArcadiaSDK({ gameId }); this.shop = new ItemShop(gameId); } async initialize() { // Initialize SDK await this.arcadia.init(); // Get wallet address this.walletAddress = await this.arcadia.getWalletAddress(); if (!this.walletAddress) { throw new WalletNotConnectedError(); } // Load or create player data this.playerData = await this.loadOrCreatePlayerData(this.walletAddress); // Initialize shop await this.shop.initialize(); // Set up wallet change listener this.arcadia.onWalletChange((connected, address) => { this.handleWalletChange(connected, address); }); // Check payment requirement if (this.gameRequiresPayment() && !this.playerData.hasPaid) { await this.handlePayToPlay(); } // Start game this.start(); } private async handlePayToPlay() { const amount = 0.5; const token = 'SOL'; try { const result = await this.arcadia.payment.payToPlay(amount, token); if (result.success && result.amount === amount) { this.playerData.hasPaid = true; await this.savePlayerData(this.walletAddress!, this.playerData); showSuccess('Payment successful!'); } } catch (error) { if (error instanceof PaymentFailedError) { showError('Payment failed: ' + error.message); } throw error; } } private handleWalletChange(connected: boolean, address: string | null) { if (!connected) { this.saveGameState(); this.pause(); showMessage('Wallet disconnected. Please reconnect.'); } else if (address && address !== this.walletAddress) { // Different wallet this.saveGameState(); this.walletAddress = address; this.loadPlayerData(address); } } private async loadOrCreatePlayerData(walletAddress: string) { const existing = await this.loadPlayerData(walletAddress); if (existing) { return existing; } const newData = { walletAddress, level: 1, score: 0, inventory: [], hasPaid: false, }; await this.savePlayerData(walletAddress, newData); return newData; } private async loadPlayerData(walletAddress: string) { const response = await fetch([/api/player-data?wallet=${walletAddress}]); if (response.ok) { return response.json(); } return null; } private async savePlayerData(walletAddress: string, data: any) { await fetch('/api/player-data', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ walletAddress, data }), }); } private saveGameState() { if (this.walletAddress && this.playerData) { this.savePlayerData(this.walletAddress, this.playerData); } } private gameRequiresPayment(): boolean { return true; // Your logic } private start() { console.log('Game started!'); } private pause() { console.log('Game paused'); } } // Initialize game const game = new Game('your-game-id'); game.initialize().catch(error => { console.error('Game initialization failed:', error); }); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ TypeScript Example ════════════════════════════════════════════════════════════ Type-safe implementation with full TypeScript support. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { ArcadiaSDK, SDKConfig, PaymentResult, WalletNotConnectedError, PaymentFailedError, } from '@arcadiasol/sdk'; interface PlayerData { walletAddress: string; level: number; score: number; inventory: string[]; hasPaid: boolean; } class TypedGameManager { private arcadia: ArcadiaSDK; private walletAddress: string | null = null; private playerData: PlayerData | null = null; constructor(config: SDKConfig) { this.arcadia = new ArcadiaSDK(config); } async initialize(): Promise { await this.arcadia.init(); this.walletAddress = await this.arcadia.getWalletAddress(); if (!this.walletAddress) { throw new WalletNotConnectedError(); } this.playerData = await this.loadPlayerData(this.walletAddress); } async processPayment(amount: number, token: 'SOL' | 'USDC'): Promise { if (!this.walletAddress) { throw new WalletNotConnectedError(); } try { const result: PaymentResult = await this.arcadia.payment.payToPlay(amount, token); if (!result.success || result.amount !== amount) { throw new PaymentFailedError('Payment verification failed'); } return result; } catch (error) { if (error instanceof PaymentFailedError) { throw error; } throw new PaymentFailedError('Payment failed'); } } private async loadPlayerData(walletAddress: string): Promise { // Implementation return { walletAddress, level: 1, score: 0, inventory: [], hasPaid: false, }; } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Error Handling ════════════════════════════════════════════════════════════ Complete error handling example. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { ArcadiaSDK, WalletNotConnectedError, PaymentFailedError, TimeoutError, InvalidAmountError, InvalidTokenError, } from '@arcadiasol/sdk'; class ErrorHandlingExample { private arcadia: ArcadiaSDK; constructor(gameId: string) { this.arcadia = new ArcadiaSDK({ gameId }); } async safeGetWalletAddress(): Promise { try { return await this.arcadia.getWalletAddress(); } catch (error) { if (error instanceof TimeoutError) { console.warn('Request timed out, retrying...'); // Retry logic return await this.arcadia.getWalletAddress(); } console.error('Failed to get wallet address:', error); return null; } } async safePayment(amount: number, token: 'SOL' | 'USDC'): Promise { try { return await this.arcadia.payment.payToPlay(amount, token); } catch (error) { if (error instanceof WalletNotConnectedError) { showError('Please connect your wallet'); } else if (error instanceof PaymentFailedError) { showError('Payment failed: ' + error.message); } else if (error instanceof InvalidAmountError) { showError('Invalid payment amount'); } else if (error instanceof InvalidTokenError) { showError('Invalid token type'); } else if (error instanceof TimeoutError) { showError('Request timed out. Please try again.'); } else { showError('An unexpected error occurred'); console.error('Unknown error:', error); } return null; } } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Next Steps ════════════════════════════════════════════════════════════ • See Getting Started for basic setup • Review API Reference for complete documentation • Check Error Handling for error handling patterns ──────────────────────────────────────────────────────────────────────────────── ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ SECTION: ERROR HANDLING ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ Error Handling Guide ══════════════════════════════════════════════════════════════════════ This guide covers all error types, when they occur, and how to handle them properly. Error Types ════════════════════════════════════════════════════════════ The SDK uses specific error classes for different scenarios, making error handling straightforward. Error Class Hierarchy ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ArcadiaSDKError (base class) ├── WalletNotConnectedError ├── PaymentFailedError ├── TimeoutError ├── InvalidConfigError ├── NotInIframeError ├── InvalidAmountError └── InvalidTokenError ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Error Types ════════════════════════════════════════════════════════════ WalletNotConnectedError ══════════════════════════════════════════════════ When it occurs: • Calling [getWalletAddress()] when wallet is not connected • Attempting payment operations without a connected wallet • Wallet disconnects during an operation Error code: [WALLET_NOT_CONNECTED] Example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { WalletNotConnectedError } from '@arcadiasol/sdk'; try { const address = await arcadia.getWalletAddress(); } catch (error) { if (error instanceof WalletNotConnectedError) { showMessage('Please connect your wallet in Arcadia'); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Handling: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const walletAddress = await arcadia.getWalletAddress(); if (!walletAddress) { // Wallet not connected - show prompt showWalletConnectionPrompt(); return; } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ PaymentFailedError ══════════════════════════════════════════════════ When it occurs: • Transaction is rejected by user • Transaction fails on blockchain • Insufficient funds • Network errors • Developer wallet not configured Error code: [PAYMENT_FAILED] Properties: • [message] - Error message • [txSignature] - Transaction signature (if available) Example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { PaymentFailedError } from '@arcadiasol/sdk'; try { const result = await arcadia.payment.payToPlay(0.5, 'SOL'); } catch (error) { if (error instanceof PaymentFailedError) { console.error('Payment failed:', error.message); if (error.txSignature) { console.log('Transaction:', error.txSignature); } showError('Payment failed: ' + error.message); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Handling: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ async function processPayment(amount: number) { try { const result = await arcadia.payment.payToPlay(amount, 'SOL'); return result; } catch (error) { if (error instanceof PaymentFailedError) { // Check specific error message if (error.message.includes('insufficient funds')) { showError('Insufficient balance. Please add funds to your wallet.'); } else if (error.message.includes('user rejected')) { showError('Payment cancelled'); } else { showError('Payment failed: ' + error.message); } return null; } throw error; } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ TimeoutError ══════════════════════════════════════════════════ When it occurs: • Request to parent window times out • Network issues prevent communication • Parent window is unresponsive Error code: [TIMEOUT] Example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { TimeoutError } from '@arcadiasol/sdk'; try { const address = await arcadia.getWalletAddress(); } catch (error) { if (error instanceof TimeoutError) { showError('Request timed out. Please try again.'); // Retry logic setTimeout(() => retryGetWalletAddress(), 1000); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Handling: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ async function getWalletAddressWithRetry(maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await arcadia.getWalletAddress(); } catch (error) { if (error instanceof TimeoutError && i < maxRetries - 1) { await new Promise(resolve => setTimeout(resolve, 1000 (i + 1))); continue; } throw error; } } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ InvalidConfigError ══════════════════════════════════════════════════ When it occurs: • [gameId] is missing or empty • Invalid configuration values Error code: [INVALID_CONFIG] Example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { InvalidConfigError } from '@arcadiasol/sdk'; try { const arcadia = new ArcadiaSDK({ gameId: '', // Invalid - empty string }); } catch (error) { if (error instanceof InvalidConfigError) { console.error('Invalid SDK configuration:', error.message); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Handling: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ function createSDK(gameId: string) { if (!gameId || gameId.trim().length === 0) { throw new Error('gameId is required'); } try { return new ArcadiaSDK({ gameId }); } catch (error) { if (error instanceof InvalidConfigError) { console.error('SDK configuration error:', error.message); throw new Error('Failed to initialize SDK'); } throw error; } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ NotInIframeError ══════════════════════════════════════════════════ When it occurs: • Calling SDK methods outside of Arcadia's iframe • Testing SDK in standalone environment Error code: [NOT_IN_IFRAME] Example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { NotInIframeError } from '@arcadiasol/sdk'; try { const result = await arcadia.payment.payToPlay(0.5, 'SOL'); } catch (error) { if (error instanceof NotInIframeError) { console.warn('SDK must run in Arcadia iframe'); // Fallback for testing useMockPayment(); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Handling: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ if (!arcadia.isInIframe()) { console.warn('SDK is not running in iframe - some features may not work'); // Use mock or test mode } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ InvalidAmountError ══════════════════════════════════════════════════ When it occurs: • Payment amount is 0 or negative • Payment amount is not a number • Payment amount is NaN Error code: [INVALID_AMOUNT] Example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { InvalidAmountError } from '@arcadiasol/sdk'; try { await arcadia.payment.payToPlay(-1, 'SOL'); // Invalid } catch (error) { if (error instanceof InvalidAmountError) { showError('Payment amount must be greater than 0'); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Handling: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ function validateAmount(amount: number): boolean { if (typeof amount !== 'number' || isNaN(amount) || amount <= 0) { showError('Invalid payment amount'); return false; } return true; } const amount = parseFloat(userInput); if (validateAmount(amount)) { await arcadia.payment.payToPlay(amount, 'SOL'); } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ InvalidTokenError ══════════════════════════════════════════════════ When it occurs: • Token type is not 'SOL' or 'USDC' • Token type is invalid Error code: [INVALID_TOKEN] Example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { InvalidTokenError } from '@arcadiasol/sdk'; try { await arcadia.payment.payToPlay(0.5, 'BTC'); // Invalid } catch (error) { if (error instanceof InvalidTokenError) { showError('Invalid token. Use SOL or USDC'); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Handling: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ function validateToken(token: string): token is 'SOL' | 'USDC' { return token === 'SOL' || token === 'USDC'; } const token = userSelectedToken; if (validateToken(token)) { await arcadia.payment.payToPlay(amount, token); } else { showError('Invalid token type'); } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Error Handling Patterns ════════════════════════════════════════════════════════════ Pattern 1: Try-Catch with Type Checking ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { WalletNotConnectedError, PaymentFailedError, TimeoutError, } from '@arcadiasol/sdk'; try { const result = await arcadia.payment.payToPlay(0.5, 'SOL'); // Success } catch (error) { if (error instanceof WalletNotConnectedError) { showMessage('Please connect your wallet'); } else if (error instanceof PaymentFailedError) { showError('Payment failed: ' + error.message); } else if (error instanceof TimeoutError) { showError('Request timed out. Please try again.'); } else { showError('An unexpected error occurred'); console.error('Unknown error:', error); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Pattern 2: Error Handler Utility ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class ErrorHandler { static handle(error: unknown): void { if (error instanceof WalletNotConnectedError) { this.showWalletPrompt(); } else if (error instanceof PaymentFailedError) { this.showPaymentError(error); } else if (error instanceof TimeoutError) { this.showTimeoutError(); } else if (error instanceof InvalidAmountError) { this.showAmountError(); } else if (error instanceof InvalidTokenError) { this.showTokenError(); } else { this.showGenericError(error); } } private static showWalletPrompt() { // Show wallet connection UI } private static showPaymentError(error: PaymentFailedError) { // Show payment error with details console.error('Payment failed:', error.message); if (error.txSignature) { console.log('Transaction:', error.txSignature); } } private static showTimeoutError() { // Show timeout message } private static showAmountError() { // Show amount validation error } private static showTokenError() { // Show token validation error } private static showGenericError(error: unknown) { // Show generic error console.error('Error:', error); } } // Usage try { await arcadia.payment.payToPlay(0.5, 'SOL'); } catch (error) { ErrorHandler.handle(error); } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Pattern 3: Retry Logic ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ async function payToPlayWithRetry( amount: number, maxRetries = 3 ): Promise { for (let i = 0; i < maxRetries; i++) { try { return await arcadia.payment.payToPlay(amount, 'SOL'); } catch (error) { if (error instanceof TimeoutError && i < maxRetries - 1) { // Retry on timeout await new Promise(resolve => setTimeout(resolve, 1000 (i + 1))); continue; } else if (error instanceof PaymentFailedError) { // Don't retry payment failures throw error; } else { // Unknown error - retry if (i < maxRetries - 1) { await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); continue; } throw error; } } } return null; } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Common Error Scenarios ════════════════════════════════════════════════════════════ Wallet Not Connected ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // Always check before operations const walletAddress = await arcadia.getWalletAddress(); if (!walletAddress) { showMessage('Please connect your wallet in Arcadia'); return; } // Or use try-catch try { const result = await arcadia.payment.payToPlay(0.5, 'SOL'); } catch (error) { if (error instanceof WalletNotConnectedError) { showWalletConnectionPrompt(); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Payment Rejected by User ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ try { const result = await arcadia.payment.payToPlay(0.5, 'SOL'); } catch (error) { if (error instanceof PaymentFailedError) { if (error.message.includes('user rejected') || error.message.includes('cancelled')) { // User cancelled - don't show error, just return return; } showError('Payment failed: ' + error.message); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Insufficient Funds ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ try { const result = await arcadia.payment.payToPlay(0.5, 'SOL'); } catch (error) { if (error instanceof PaymentFailedError) { if (error.message.includes('insufficient funds') || error.message.includes('insufficient balance')) { showError('Insufficient balance. Please add funds to your wallet.'); } else { showError('Payment failed: ' + error.message); } } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Debugging Tips ════════════════════════════════════════════════════════════ 1. Check Error Messages - Error messages contain useful information 2. Log Transaction Signatures - Payment errors may include transaction signatures 3. Verify SDK State - Check [isInitialized()] and [isInIframe()] 4. Check Wallet Status - Verify wallet is connected before operations 5. Network Issues - Timeout errors often indicate network problems Next Steps ════════════════════════════════════════════════════════════ • Review API Reference for complete error class documentation • See Examples for error handling patterns • Check Security for security-related error handling ──────────────────────────────────────────────────────────────────────────────── ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ SECTION: SECURITY ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ Security Guide ══════════════════════════════════════════════════════════════════════ This guide covers security best practices when using the Arcadia Game SDK. Overview ════════════════════════════════════════════════════════════ The Arcadia Game SDK is designed with security in mind. It uses secure communication patterns and never exposes sensitive data like private keys. Security Features ════════════════════════════════════════════════════════════ Wallet Security ══════════════════════════════════════════════════ • No Private Keys - The SDK never accesses or transmits private keys • Wallet Address Only - Only public wallet addresses are used • Parent Window Signing - All transactions are signed in the secure parent window • No Wallet Access - Games cannot directly access wallet functionality Communication Security ══════════════════════════════════════════════════ • postMessage API - Secure cross-origin communication • Origin Validation - Optional origin validation for messages • Request Timeouts - Prevents hanging requests • Message Validation - All messages are validated before processing Transaction Security ══════════════════════════════════════════════════ • User Approval Required - All transactions require explicit user approval • No Automatic Transactions - Games cannot send transactions without user consent • Transaction Details - Users see full transaction details before approval • Immediate Return - Payments return after transaction is sent (not confirmed) Best Practices ════════════════════════════════════════════════════════════ 1. Origin Validation ══════════════════════════════════════════════════ Always validate the parent origin when possible: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const arcadia = new ArcadiaSDK({ gameId: 'your-game-id', parentOrigin: 'https://arcadia.com', // Restrict to specific origin }); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Note: Using ['*'] allows any origin. Only use this for development. 2. Validate Payment Results ══════════════════════════════════════════════════ Always verify payment results before granting access or items: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const result = await arcadia.payment.payToPlay(0.5, 'SOL'); // Verify payment details if (result.success && result.amount === 0.5 && result.token === 'SOL') { // Payment verified - proceed grantAccess(); } else { // Payment verification failed rejectPayment(); } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3. Store Transaction Signatures ══════════════════════════════════════════════════ Keep transaction signatures for record-keeping and verification: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const result = await arcadia.payment.payToPlay(0.5, 'SOL'); // Store transaction signature await savePaymentRecord({ walletAddress: walletAddress, txSignature: result.txSignature, amount: result.amount, timestamp: result.timestamp, }); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4. Handle Errors Securely ══════════════════════════════════════════════════ Don't expose sensitive information in error messages: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ try { await arcadia.payment.payToPlay(0.5, 'SOL'); } catch (error) { // Don't expose internal error details if (error instanceof PaymentFailedError) { showError('Payment failed. Please try again.'); // Log full error details server-side logError(error); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5. Validate Wallet Addresses ══════════════════════════════════════════════════ Always validate wallet addresses before using them: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ function isValidSolanaAddress(address: string): boolean { // Basic validation - check length and format return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(address); } const walletAddress = await arcadia.getWalletAddress(); if (walletAddress && isValidSolanaAddress(walletAddress)) { // Use wallet address } else { // Invalid address showError('Invalid wallet address'); } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6. Secure Save Data ══════════════════════════════════════════════════ Use wallet addresses securely when storing player data: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // Good: Use wallet address as identifier await savePlayerData({ walletAddress: walletAddress, // Public key - safe to store gameData: gameData, }); // Bad: Never store private keys or sensitive wallet data // await savePlayerData({ // privateKey: privateKey, // NEVER DO THIS // }); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Common Security Pitfalls ════════════════════════════════════════════════════════════ ❌ Don't Trust Client-Side Validation Alone ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // Bad: Only client-side validation const amount = parseFloat(userInput); if (amount > 0) { await arcadia.payment.payToPlay(amount, 'SOL'); } // Good: Validate server-side too const amount = parseFloat(userInput); if (amount > 0 && amount <= MAX_PAYMENT) { // Also validate on server await arcadia.payment.payToPlay(amount, 'SOL'); } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ❌ Don't Expose Internal Errors ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // Bad: Expose internal error details catch (error) { showError([Payment failed: ${error.message}]); // May expose sensitive information } // Good: Show user-friendly messages catch (error) { showError('Payment failed. Please try again.'); // Log full error server-side logError(error); } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ❌ Don't Skip Payment Verification ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // Bad: Trust payment without verification const result = await arcadia.payment.payToPlay(0.5, 'SOL'); grantAccess(); // No verification! // Good: Verify payment details const result = await arcadia.payment.payToPlay(0.5, 'SOL'); if (result.success && result.amount === 0.5) { grantAccess(); } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ❌ Don't Store Sensitive Data ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // Bad: Store sensitive data localStorage.setItem('privateKey', privateKey); // NEVER! // Good: Only store public data localStorage.setItem('walletAddress', walletAddress); // OK ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ postMessage Security ════════════════════════════════════════════════════════════ The SDK uses [postMessage] for communication. Follow these practices: Validate Message Origin ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // SDK automatically validates origin if parentOrigin is set const arcadia = new ArcadiaSDK({ gameId: 'your-game-id', parentOrigin: 'https://arcadia.com', // Validates origin }); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Don't Trust External Messages ══════════════════════════════════════════════════ The SDK handles message validation internally. Don't process messages from unknown sources: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // SDK handles this automatically // Don't manually process postMessage events ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Transaction Security ════════════════════════════════════════════════════════════ User Approval ══════════════════════════════════════════════════ All transactions require explicit user approval in the wallet: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // User must approve in wallet popup const result = await arcadia.payment.payToPlay(0.5, 'SOL'); // Transaction is only sent after user approval ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Transaction Details ══════════════════════════════════════════════════ Users see full transaction details before approval: • Amount • Token type • Recipient address • Transaction fee No Automatic Transactions ══════════════════════════════════════════════════ Games cannot send transactions automatically: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // This requires user approval - cannot be automated const result = await arcadia.payment.payToPlay(0.5, 'SOL'); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Data Privacy ════════════════════════════════════════════════════════════ Wallet Address Privacy ══════════════════════════════════════════════════ Wallet addresses are public information, but: • Don't share wallet addresses unnecessarily • Don't link wallet addresses to real-world identities without consent • Respect user privacy preferences Payment Data ══════════════════════════════════════════════════ Payment data includes: • Transaction signatures (public) • Amounts (public) • Timestamps (public) • Purchase IDs (internal) All payment data is safe to store and share for analytics. Reporting Security Issues ════════════════════════════════════════════════════════════ If you discover a security vulnerability: 1. Do not open a public issue 2. Email security@arcadia.com 3. Include: - Description of the vulnerability - Steps to reproduce - Potential impact - Suggested fix (if any) Security Checklist ════════════════════════════════════════════════════════════ Before deploying your game: • [ ] Origin validation configured (if applicable) • [ ] Payment results are verified • [ ] Transaction signatures are stored • [ ] Error messages don't expose sensitive data • [ ] Wallet addresses are validated • [ ] No sensitive data in client-side code • [ ] Server-side validation for critical operations • [ ] Security best practices followed Next Steps ════════════════════════════════════════════════════════════ • Review Error Handling for secure error handling • Check API Reference for security-related methods • See Examples for secure implementation patterns ──────────────────────────────────────────────────────────────────────────────── ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ SECTION: FAQ ════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════ Frequently Asked Questions ══════════════════════════════════════════════════════════════════════ Common questions and answers about the Arcadia Game SDK. General ════════════════════════════════════════════════════════════ What is the Arcadia Game SDK? ══════════════════════════════════════════════════ The Arcadia Game SDK is a JavaScript library that enables Web3 games to integrate wallet connectivity and payment processing. It works seamlessly in iframe environments and handles all the complexity of Web3 interactions. What browsers are supported? ══════════════════════════════════════════════════ The SDK works in all modern browsers: • Chrome 90+ • Firefox 88+ • Safari 14+ • Edge 90+ Do I need to know Solana/Web3 to use the SDK? ══════════════════════════════════════════════════ No! The SDK abstracts away all Web3 complexity. You just call methods like [payToPlay()] and [getWalletAddress()] - the SDK handles everything else. Is the SDK free to use? ══════════════════════════════════════════════════ Yes, the SDK is free to use. Arcadia charges platform fees on payments (transparently shown in payment results), but the SDK itself has no cost. Installation ════════════════════════════════════════════════════════════ NPM vs CDN - which should I use? ══════════════════════════════════════════════════ • NPM: Recommended for TypeScript projects, bundlers (Webpack, Vite), and modern development • CDN: Quick for simple HTML games, testing, or when you can't use a bundler Both work the same - choose based on your project setup. How do I update the SDK? ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [BASH] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ npm update @arcadiasol/sdk ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Or update the version in your CDN URL: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [HTML] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Can I use the SDK in a Node.js environment? ══════════════════════════════════════════════════ No, the SDK is designed for browser environments only. It requires [window] and [postMessage] APIs. Wallet Integration ════════════════════════════════════════════════════════════ Why use wallet address as user ID? ══════════════════════════════════════════════════ Wallet addresses are: • Universal (work across all games) • Persistent (don't change) • Secure (cryptographically secure) • No authentication needed This makes them perfect for Web3 games. What if a player doesn't have a wallet? ══════════════════════════════════════════════════ Players must connect a wallet in Arcadia before playing games. The SDK will return [null] for [getWalletAddress()] if no wallet is connected, and you should prompt them to connect. Can players switch wallets during gameplay? ══════════════════════════════════════════════════ Yes. Use [onWalletChange()] to detect wallet changes and handle them appropriately (save current game, load new player data, etc.). How do I handle wallet disconnections? ══════════════════════════════════════════════════ Listen for wallet changes and save game state when disconnected: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ arcadia.onWalletChange((connected, address) => { if (!connected) { saveGameState(); pauseGame(); } }); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Payments ════════════════════════════════════════════════════════════ How fast are payments? ══════════════════════════════════════════════════ Payments return immediately after the transaction is sent to the blockchain. The SDK doesn't wait for full confirmation, making the experience instant for players. What tokens are supported? ══════════════════════════════════════════════════ Currently supported: • SOL (Solana native token) • USDC (USD Coin on Solana) More tokens may be added in the future. How are fees calculated? ══════════════════════════════════════════════════ Platform fees are automatically calculated and deducted. The [PaymentResult] includes: • [platformFee] - Fee deducted by platform • [developerAmount] - Amount you receive (after fees) Can I set custom payment amounts? ══════════════════════════════════════════════════ Yes, you can set any amount > 0. The SDK validates amounts but doesn't restrict them. What happens if a payment fails? ══════════════════════════════════════════════════ The SDK throws a [PaymentFailedError] with details. Common reasons: • User rejected transaction • Insufficient funds • Network error • Developer wallet not configured Do I need to verify payments on-chain? ══════════════════════════════════════════════════ No! The SDK provides complete payment details in the [PaymentResult]. You can verify amounts and store transaction signatures, but you don't need to query the blockchain. Can I refund payments? ══════════════════════════════════════════════════ Refunds are not handled by the SDK. You'll need to implement refund logic separately if needed. Game Integration ════════════════════════════════════════════════════════════ Does my game need to be in an iframe? ══════════════════════════════════════════════════ Yes, the SDK is designed for games embedded in Arcadia's iframe. Some features won't work outside of an iframe. Can I test the SDK locally? ══════════════════════════════════════════════════ Yes, but some features require the Arcadia iframe environment. For full testing, you'll need to: 1. Host your game 2. Add it to Arcadia 3. Test through Arcadia's game player How do I get a game ID? ══════════════════════════════════════════════════ You'll receive a game ID when you register your game on Arcadia. Contact support@arcadia.com for game registration. Can I use the SDK with Unity/Unreal/other game engines? ══════════════════════════════════════════════════ Yes! As long as your game runs in a browser (WebGL builds), you can use the SDK. You'll need to: 1. Build your game for WebGL 2. Host it 3. Integrate the SDK in your game's JavaScript/TypeScript code How do I handle game saves? ══════════════════════════════════════════════════ Use the wallet address as the key for save data: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const walletAddress = await arcadia.getWalletAddress(); await saveGameData(walletAddress, gameData); const loaded = await loadGameData(walletAddress); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Error Handling ════════════════════════════════════════════════════════════ What errors can occur? ══════════════════════════════════════════════════ Common errors: • [WalletNotConnectedError] - Wallet not connected • [PaymentFailedError] - Payment failed • [TimeoutError] - Request timed out • [InvalidAmountError] - Invalid payment amount • [InvalidTokenError] - Invalid token type See Error Handling Guide for details. How do I handle errors? ══════════════════════════════════════════════════ Use try-catch and check error types: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ try { await arcadia.payment.payToPlay(0.5, 'SOL'); } catch (error) { if (error instanceof WalletNotConnectedError) { showMessage('Please connect your wallet'); } else if (error instanceof PaymentFailedError) { showError('Payment failed: ' + error.message); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Security ════════════════════════════════════════════════════════════ Is the SDK secure? ══════════════════════════════════════════════════ Yes! The SDK: • Never accesses private keys • Only uses public wallet addresses • Requires user approval for all transactions • Validates message origins • Uses secure communication patterns Can games steal funds? ══════════════════════════════════════════════════ No. Games cannot: • Access private keys • Send transactions without user approval • Access wallet functionality directly • Bypass security checks All transactions require explicit user approval in the wallet. Should I validate payments server-side? ══════════════════════════════════════════════════ Yes, for critical operations. While the SDK provides payment details, you should verify: • Payment amounts match expected values • Transaction signatures are valid • Payments aren't duplicated Troubleshooting ════════════════════════════════════════════════════════════ SDK not initializing ══════════════════════════════════════════════════ Check: 1. Game is running in Arcadia iframe 2. [gameId] is correct 3. SDK script is loaded 4. Browser console for errors Wallet address is null ══════════════════════════════════════════════════ • Player hasn't connected wallet in Arcadia • Game not running in Arcadia iframe • SDK not initialized Payments failing ══════════════════════════════════════════════════ Check: 1. Wallet has sufficient balance 2. Developer wallet is configured in Arcadia 3. Network connection is stable 4. Error message for specific issue postMessage errors ══════════════════════════════════════════════════ • Game not in iframe • Origin validation mismatch • Parent window not responding Support ════════════════════════════════════════════════════════════ Where can I get help? ══════════════════════════════════════════════════ • Documentation: This guide • Email: support@arcadia.com • GitHub: Issues How do I report bugs? ══════════════════════════════════════════════════ Open an issue on GitHub or email support@arcadia.com with: • Description of the issue • Steps to reproduce • Expected vs actual behavior • Browser/OS information • Error messages (if any) Can I contribute? ══════════════════════════════════════════════════ Yes! Contributions are welcome. Check the GitHub repository for contribution guidelines. Next Steps ════════════════════════════════════════════════════════════ • Review Getting Started if you're new • Check Examples for code samples • Read API Reference for complete documentation ──────────────────────────────────────────────────────────────────────────────── ═══════════════════════════════════════════════════════════════════════════════ For the latest documentation, visit: https://arcadia.obeliskprotocol.io/developer For support, email: support@arcadia.com GitHub: https://github.com/arcadia/game-sdk NPM: https://www.npmjs.com/package/@arcadiasol/game-sdk ═══════════════════════════════════════════════════════════════════════════════