or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

asset-utilities.mdconfiguration.mdevent-handling.mdindex.mdlegacy-api.mdprovider-interface.mdsdk-initialization.mdtype-utilities.md
tile.json

event-handling.mddocs/

Event Handling

EventEmitter-based system for handling wallet connection events, account changes, chain switches, and connection state management.

Capabilities

Provider Event Map

Event types and their payload structures for wallet state changes.

type ProviderEventMap = {
  /** Emitted when wallet connection is established */
  connect: ProviderConnectInfo;
  /** Emitted when wallet is disconnected */
  disconnect: ProviderRpcError;
  /** Emitted when the active chain is changed */
  chainChanged: string; // hex string
  /** Emitted when connected accounts change */
  accountsChanged: string[];
};

interface ProviderConnectInfo {
  /** Chain ID of the connected network (hex string) */
  readonly chainId: string;
}

interface ProviderRpcError extends Error {
  /** Error message */
  message: string;
  /** Error code following EIP-1193 standards */
  code: number;
  /** Additional error data (optional) */
  data?: unknown;
}

Event Emitter Interface

Base event emitter class for provider event handling.

class ProviderEventEmitter extends EventEmitter<keyof ProviderEventMap> {
  /** Emit an event with typed payload */
  emit<K extends keyof ProviderEventMap>(
    event: K, 
    ...args: [ProviderEventMap[K]]
  ): boolean;
  
  /** Listen for events with typed callback */
  on<K extends keyof ProviderEventMap>(
    event: K, 
    listener: (_: ProviderEventMap[K]) => void
  ): this;
  
  /** Listen for events once with typed callback */
  once<K extends keyof ProviderEventMap>(
    event: K, 
    listener: (_: ProviderEventMap[K]) => void
  ): this;
  
  /** Remove event listener */
  off<K extends keyof ProviderEventMap>(
    event: K, 
    listener: (_: ProviderEventMap[K]) => void
  ): this;
}

Connection Events

Events related to wallet connection establishment and termination.

/**
 * Connect event - emitted when wallet connection is established
 * @param info - Connection information including chain ID
 */
provider.on('connect', (info: ProviderConnectInfo) => void);

/**
 * Disconnect event - emitted when wallet connection is lost
 * @param error - Error information about the disconnection
 */
provider.on('disconnect', (error: ProviderRpcError) => void);

Usage Examples:

import { createCoinbaseWalletSDK } from "@coinbase/wallet-sdk";

const sdk = createCoinbaseWalletSDK({
  appName: "Event Handling Example"
});
const provider = sdk.getProvider();

// Listen for connection
provider.on('connect', (connectInfo) => {
  console.log('Wallet connected to chain:', connectInfo.chainId);
  const chainId = parseInt(connectInfo.chainId, 16);
  
  if (chainId === 1) {
    console.log('Connected to Ethereum mainnet');
  } else if (chainId === 8453) {
    console.log('Connected to Base');
  }
});

// Listen for disconnection
provider.on('disconnect', (error) => {
  console.log('Wallet disconnected:', error.message);
  console.log('Error code:', error.code);
  
  // Handle different disconnect scenarios
  if (error.code === 1013) {
    console.log('User disconnected');
  } else {
    console.log('Unexpected disconnection');
  }
});

// Connect to trigger events
try {
  await provider.request({ method: 'eth_requestAccounts' });
} catch (error) {
  console.error('Connection failed:', error);
}

Account Change Events

Events for monitoring changes to connected wallet accounts.

/**
 * AccountsChanged event - emitted when connected accounts change
 * @param accounts - Array of connected account addresses
 */
provider.on('accountsChanged', (accounts: string[]) => void);

Usage Examples:

// Monitor account changes
provider.on('accountsChanged', (accounts) => {
  console.log('Accounts changed:', accounts);
  
  if (accounts.length === 0) {
    console.log('No accounts connected');
    // Handle disconnected state
    updateUIForDisconnectedState();
  } else {
    console.log('Active account:', accounts[0]);
    // Handle account switch
    updateUIForNewAccount(accounts[0]);
  }
});

// Initial connection
const accounts = await provider.request({
  method: 'eth_requestAccounts'
});
console.log('Initially connected accounts:', accounts);

function updateUIForDisconnectedState() {
  // Update UI to show disconnected state
  document.getElementById('account')?.textContent = 'Not connected';
}

function updateUIForNewAccount(account: string) {
  // Update UI with new account
  document.getElementById('account')?.textContent = 
    `${account.slice(0, 6)}...${account.slice(-4)}`;
}

Chain Change Events

Events for monitoring blockchain network changes.

/**
 * ChainChanged event - emitted when the active chain changes
 * @param chainId - New chain ID as hex string
 */
provider.on('chainChanged', (chainId: string) => void);

Usage Examples:

// Monitor chain changes
provider.on('chainChanged', (chainId) => {
  const chainIdNumber = parseInt(chainId, 16);
  console.log('Chain changed to:', chainIdNumber);
  
  // Handle different chains
  switch (chainIdNumber) {
    case 1:
      console.log('Switched to Ethereum mainnet');
      updateUIForChain('Ethereum', '#627EEA');
      break;
    case 8453:
      console.log('Switched to Base');
      updateUIForChain('Base', '#0052FF');
      break;
    case 137:
      console.log('Switched to Polygon');
      updateUIForChain('Polygon', '#8247E5');
      break;
    default:
      console.log('Switched to unknown chain:', chainIdNumber);
      updateUIForChain(`Chain ${chainIdNumber}`, '#666666');
  }
  
  // Reload application data for new chain
  await loadDataForChain(chainIdNumber);
});

function updateUIForChain(name: string, color: string) {
  const chainElement = document.getElementById('chain');
  if (chainElement) {
    chainElement.textContent = name;
    chainElement.style.color = color;
  }
}

async function loadDataForChain(chainId: number) {
  // Reload balances, transactions, etc. for new chain
  console.log(`Loading data for chain ${chainId}`);
}

Event Listener Management

Methods for managing event listeners lifecycle.

/**
 * Add event listener
 * @param event - Event name
 * @param listener - Event handler function
 */
provider.on<K extends keyof ProviderEventMap>(
  event: K, 
  listener: (payload: ProviderEventMap[K]) => void
): this;

/**
 * Add one-time event listener
 * @param event - Event name
 * @param listener - Event handler function (called once)
 */
provider.once<K extends keyof ProviderEventMap>(
  event: K, 
  listener: (payload: ProviderEventMap[K]) => void
): this;

/**
 * Remove event listener
 * @param event - Event name
 * @param listener - Event handler function to remove
 */
provider.off<K extends keyof ProviderEventMap>(
  event: K, 
  listener: (payload: ProviderEventMap[K]) => void
): this;

Usage Examples:

// Create event handlers
const handleAccountsChanged = (accounts: string[]) => {
  console.log('Accounts updated:', accounts);
};

const handleChainChanged = (chainId: string) => {
  console.log('Chain updated:', chainId);
};

// Add listeners
provider.on('accountsChanged', handleAccountsChanged);
provider.on('chainChanged', handleChainChanged);

// One-time listener for initial connection
provider.once('connect', (connectInfo) => {
  console.log('Initial connection established:', connectInfo.chainId);
});

// Remove specific listener
provider.off('accountsChanged', handleAccountsChanged);

// Component cleanup (remove all listeners)
function cleanup() {
  provider.off('accountsChanged', handleAccountsChanged);
  provider.off('chainChanged', handleChainChanged);
  // Or remove all listeners for an event
  provider.removeAllListeners('connect');
}

Error Event Handling

Handle provider-specific errors through disconnect events and request rejections.

// Global error handling
provider.on('disconnect', (error) => {
  switch (error.code) {
    case 1013: // User disconnected
      console.log('User intentionally disconnected');
      break;
    case 1001: // Network error
      console.log('Network connection lost');
      break;
    default:
      console.error('Unexpected disconnect:', error);
  }
});

// Request-specific error handling
try {
  await provider.request({ method: 'eth_sendTransaction', params: [...] });
} catch (error) {
  if (error.code === 4001) {
    console.log('User rejected transaction');
  } else {
    console.error('Transaction failed:', error);
  }
}

Event-Driven Application Flow

Implement reactive application patterns using provider events:

class WalletManager {
  private provider: ProviderInterface;
  private isConnected = false;
  private currentAccount: string | null = null;
  private currentChain: number | null = null;

  constructor(provider: ProviderInterface) {
    this.provider = provider;
    this.setupEventListeners();
  }

  private setupEventListeners() {
    this.provider.on('connect', this.handleConnect.bind(this));
    this.provider.on('disconnect', this.handleDisconnect.bind(this));
    this.provider.on('accountsChanged', this.handleAccountsChanged.bind(this));
    this.provider.on('chainChanged', this.handleChainChanged.bind(this));
  }

  private handleConnect(connectInfo: ProviderConnectInfo) {
    this.isConnected = true;
    this.currentChain = parseInt(connectInfo.chainId, 16);
    console.log('Connected to chain:', this.currentChain);
  }

  private handleDisconnect(error: ProviderRpcError) {
    this.isConnected = false;
    this.currentAccount = null;
    this.currentChain = null;
    console.log('Disconnected:', error.message);
  }

  private handleAccountsChanged(accounts: string[]) {
    this.currentAccount = accounts.length > 0 ? accounts[0] : null;
    console.log('Current account:', this.currentAccount);
  }

  private handleChainChanged(chainId: string) {
    this.currentChain = parseInt(chainId, 16);
    console.log('Current chain:', this.currentChain);
  }

  public getState() {
    return {
      isConnected: this.isConnected,
      account: this.currentAccount,
      chainId: this.currentChain
    };
  }
}

// Usage
const walletManager = new WalletManager(provider);