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:
- Universal Identity - Works across all games and platforms
- No Authentication Required - Players don't need to create accounts
- Persistent - Wallet addresses don't change
- Secure - Cryptographically secure identifiers
- Web3 Native - Aligns with blockchain gaming standards
Getting the Wallet Address
Basic Usage
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:
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
const isConnected = await arcadia.isWalletConnected();
if (!isConnected) {
showMessage('Please connect your wallet');
return;
}
Combined Check
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
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
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
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
// 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
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
// 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:
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
- Always Check for Null - Wallet address can be
nullif not connected - Handle Disconnections - Save game state when wallet disconnects
- Listen for Changes - Use
onWalletChangeto react to connection changes - Save Frequently - Save player data regularly, not just on disconnect
- Validate Wallet Address - Ensure wallet address is valid before using it
- Handle Wallet Switching - Players may switch wallets during gameplay
Common Patterns
Auto-Save on Wallet Disconnect
arcadia.onWalletChange((connected, address) => {
if (!connected && this.walletAddress) {
// Auto-save when wallet disconnects
this.autoSave();
}
});
Prevent Gameplay Without Wallet
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