> ## Documentation Index
> Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Events

> Subscribe to provider events using EventEmitter pattern

# Events

EIP-1193 providers emit events for account changes, chain changes, and connection status using the standard EventEmitter pattern.

## Overview

Providers emit four standard events:

```typescript theme={null}
// Subscribe to account changes
provider.on('accountsChanged', (accounts) => {
  console.log('Active accounts:', accounts);
});

// Subscribe to chain changes
provider.on('chainChanged', (chainId) => {
  console.log('Chain ID:', chainId);
});

// Subscribe to connection
provider.on('connect', (connectInfo) => {
  console.log('Connected to chain:', connectInfo.chainId);
});

// Subscribe to disconnection
provider.on('disconnect', (error) => {
  console.log('Disconnected:', error);
});
```

## Available Events

### accountsChanged

Emitted when the active accounts change (e.g., user switches accounts in wallet).

**Event Data:** `string[]` - Array of addresses

```typescript theme={null}
provider.on('accountsChanged', (accounts: string[]) => {
  if (accounts.length === 0) {
    console.log('No accounts available');
  } else {
    console.log('Active account:', accounts[0]);
  }
});
```

**Use cases:**

* Update UI when user switches wallets
* Re-fetch user-specific data
* Prompt user to reconnect

### chainChanged

Emitted when the chain changes (e.g., user switches from mainnet to testnet).

**Event Data:** `string` - Chain ID (hex-encoded)

```typescript theme={null}
provider.on('chainChanged', (chainId: string) => {
  const chainIdNum = parseInt(chainId, 16);
  console.log('Chain ID:', chainIdNum);

  // Reload app to avoid stale state
  window.location.reload();
});
```

**Use cases:**

* Reload application to avoid stale state
* Update network-specific configurations
* Display appropriate chain indicator

<Warning>
  When chain changes, app state may be invalid. Most apps should reload: `window.location.reload()`.
</Warning>

### connect

Emitted when provider becomes connected to a chain.

**Event Data:** `{chainId: string}` - Connection info

```typescript theme={null}
provider.on('connect', (connectInfo: { chainId: string }) => {
  const chainId = parseInt(connectInfo.chainId, 16);
  console.log('Connected to chain:', chainId);

  // Initialize app with chain-specific data
  initializeApp(chainId);
});
```

**Use cases:**

* Initialize app after connection established
* Fetch initial blockchain data
* Enable blockchain-dependent features

### disconnect

Emitted when provider disconnects from all chains.

**Event Data:** `{code: number, message: string}` - Error info

```typescript theme={null}
provider.on('disconnect', (error: { code: number; message: string }) => {
  console.log('Disconnected:', error.message);

  // Clean up and show reconnection UI
  showReconnectDialog();
});
```

**Use cases:**

* Clean up subscriptions and listeners
* Show reconnection UI
* Save user state before disconnect

## Event Management

### Adding Listeners

Use `on()` or `addEventListener()`:

```typescript theme={null}
const handler = (accounts) => {
  console.log('Accounts:', accounts);
};

// Both work
provider.on('accountsChanged', handler);
provider.addEventListener('accountsChanged', handler);
```

### Removing Listeners

Use `removeListener()` or `removeEventListener()`:

```typescript theme={null}
const handler = (accounts) => {
  console.log('Accounts:', accounts);
};

provider.on('accountsChanged', handler);

// Later, remove listener
provider.removeListener('accountsChanged', handler);
// or
provider.removeEventListener('accountsChanged', handler);
```

<Warning>
  Always use the same function reference when removing listeners. Arrow functions created inline can't be removed.
</Warning>

### One-Time Listeners

Use `once()` for single-use handlers:

```typescript theme={null}
provider.once('connect', (connectInfo) => {
  console.log('Initial connection:', connectInfo.chainId);
  // Handler automatically removed after firing
});
```

## Usage Patterns

### React Hook

```typescript theme={null}
import { useEffect, useState } from 'react';

function useAccounts(provider) {
  const [accounts, setAccounts] = useState<string[]>([]);

  useEffect(() => {
    const handler = (newAccounts: string[]) => {
      setAccounts(newAccounts);
    };

    provider.on('accountsChanged', handler);

    // Cleanup
    return () => {
      provider.removeListener('accountsChanged', handler);
    };
  }, [provider]);

  return accounts;
}
```

### Chain Change Handler

```typescript theme={null}
function setupChainHandler(provider, allowedChains: number[]) {
  provider.on('chainChanged', (chainId: string) => {
    const chainIdNum = parseInt(chainId, 16);

    if (!allowedChains.includes(chainIdNum)) {
      alert(`Please switch to supported chain`);
      return;
    }

    // Chain is valid, reload
    window.location.reload();
  });
}
```

### Connection Monitor

```typescript theme={null}
class ConnectionMonitor {
  private isConnected = false;

  constructor(private provider: any) {
    this.setupListeners();
  }

  private setupListeners() {
    this.provider.on('connect', (info: { chainId: string }) => {
      this.isConnected = true;
      console.log('Connected to chain:', info.chainId);
    });

    this.provider.on('disconnect', (error: any) => {
      this.isConnected = false;
      console.log('Disconnected:', error.message);
    });
  }

  async waitForConnection(): Promise<string> {
    if (this.isConnected) {
      const chainId = await this.provider.request({
        method: 'eth_chainId'
      });
      return chainId;
    }

    return new Promise((resolve) => {
      this.provider.once('connect', (info: { chainId: string }) => {
        resolve(info.chainId);
      });
    });
  }
}
```

### Account Switcher

```typescript theme={null}
function createAccountSwitcher(provider) {
  let currentAccount: string | null = null;

  provider.on('accountsChanged', async (accounts: string[]) => {
    const newAccount = accounts[0] || null;

    if (newAccount !== currentAccount) {
      const oldAccount = currentAccount;
      currentAccount = newAccount;

      console.log(`Account changed from ${oldAccount} to ${newAccount}`);

      // Re-fetch account-specific data
      if (newAccount) {
        await loadAccountData(newAccount);
      }
    }
  });

  return {
    getCurrentAccount: () => currentAccount
  };
}
```

## Best Practices

1. **Always remove listeners** when component unmounts or is no longer needed
2. **Use same function reference** for add/remove to work correctly
3. **Reload on chainChanged** to avoid stale state issues
4. **Handle empty accounts array** - user may disconnect wallet
5. **Test disconnection scenarios** - network issues, manual disconnects

## Error Handling

Events themselves don't throw errors, but you can wrap handlers:

```typescript theme={null}
provider.on('accountsChanged', (accounts) => {
  try {
    updateAccountState(accounts);
  } catch (error) {
    console.error('Failed to handle account change:', error);
  }
});
```

## Key Differences from Custom Event Systems

| Feature       | EIP-1193 Events                                    | Custom Events                  |
| ------------- | -------------------------------------------------- | ------------------------------ |
| Events        | accountsChanged, chainChanged, connect, disconnect | Varies by library              |
| Pattern       | Standard EventEmitter                              | Library-specific               |
| Compatibility | All EIP-1193 providers                             | Provider-specific              |
| Use case      | Wallet/chain changes                               | Blockchain data (blocks, logs) |

For blockchain data subscriptions (blocks, logs, transactions), use JSON-RPC subscription methods like `eth_subscribe`.

## Related

* [Getting Started](/jsonrpc-provider/getting-started) - Installation and setup
* [Method API](/jsonrpc-provider/method-api) - Making JSON-RPC requests
* [Error Handling](/jsonrpc-provider/error-handling) - Handling errors
