JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 73
  • Score
    100M100P100Q97722F
  • License MIT

Universal Web3 Provider SDK. A robust, production-ready JavaScript/TypeScript SDK that provides comprehensive wallet connection utilities for blockchain applications with enhanced error handling, retry mechanisms, and comprehensive wallet functionality.

Package Exports

  • custom-web3-provider-sdk

Readme

Custom Web3 Provider SDK

A robust, production-ready JavaScript/TypeScript SDK that provides comprehensive wallet connection utilities for blockchain applications with enhanced error handling, retry mechanisms, comprehensive wallet functionality, memory leak prevention, and advanced security features.

โœจ Features

  • ๐Ÿ”— Multi-Wallet Support: MetaMask, Coinbase, Trust Wallet, Rabby, Brave, LXX Wallet and more
  • ๐Ÿ›ก๏ธ Robust Error Handling: Comprehensive error types and retry mechanisms with enhanced security
  • ๐Ÿ”„ Auto-Recovery: Automatic reconnection and provider detection with memory leak prevention
  • ๐Ÿ“ฑ React Integration: Optimized React hooks with proper cleanup and state management
  • ๐ŸŽฏ TypeScript First: Full TypeScript support with strict type checking and validation
  • โšก Performance Optimized: Memoized operations and efficient re-renders with memory management
  • ๐Ÿ”’ Security Focused: Input validation, sanitization, and secure transaction handling
  • ๐ŸŒ EIP-1193 Compliant: Full compliance with Ethereum provider standards
  • ๐Ÿ“Š Comprehensive Wallet Actions: Balance checking, transaction signing, gas estimation
  • ๐ŸŽ›๏ธ Configurable: Extensive configuration options for different use cases
  • ๐Ÿš€ Custom Requests: Flexible provider request methods for any type of data
  • ๐Ÿ” Enhanced Event Handling: Robust account/chain change detection with validation and real-time testing
  • ๐Ÿงน Memory Management: Proper cleanup prevents memory leaks
  • ๐Ÿ” Debug Logging: Comprehensive logging for troubleshooting

๐Ÿ“ฆ Installation

npm install custom-web3-provider-sdk

๐ŸŽฎ Live Demo

Experience the SDK in action with our interactive demo:

๐Ÿš€ View Live Demo โ†’ https://custom-sdk-demo.netlify.app

The live demo showcases:

  • โœ… Multi-wallet connection (MetaMask, Coinbase, Trust Wallet, LXX Wallet, etc.)
  • โœ… Real-time account and chain updates with event testing
  • โœ… Secure transaction signing
  • โœ… Message signing with validation
  • โœ… Custom Web3 requests
  • โœ… Error handling and recovery
  • โœ… Account change event testing and validation
  • โœ… Professional UI with all features

๐Ÿš€ Quick Start

Basic React Hook Usage

import React from 'react';
import { useWeb3Provider } from 'custom-web3-provider-sdk';

function Web3App() {
  const {
    providers,
    currentProvider,
    accounts,
    chainId,
    status,
    error,
    isConnecting,
    connect,
    disconnect,
    // Wallet Actions
    getAccount,
    getBalance,
    signMessage,
    sendTransaction,
    // Utilities
    utils
  } = useWeb3Provider({
    preferred: ['metamask', 'coinbase', 'trustwallet', 'lxxwallet'],
    autoConnect: false,
    debug: true,
    onAccountsChanged: (accounts) => {
      console.log('Accounts changed:', accounts);
    },
    onChainChanged: (chainId) => {
      console.log('Chain changed to:', chainId);
    },
    onError: (error) => {
      console.error('Provider error:', error);
    }
  });

  const handleConnect = async () => {
    try {
      await connect('metamask');
      console.log('Connected successfully!');
    } catch (error) {
      console.error('Connection failed:', error);
    }
  };

  const handleSignMessage = async () => {
    try {
      const message = `Hello from Web3 SDK! ${new Date().toISOString()}`;
      const signature = await signMessage(message);
      console.log('Message signed:', signature);
    } catch (error) {
      console.error('Signing failed:', error);
    }
  };

  const handleSendTransaction = async () => {
    try {
      const txHash = await sendTransaction({
        to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
        value: utils.ethToWei('0.001'),
        maxFeePerGas: '0x2540be400',
        maxPriorityFeePerGas: '0x3b9aca00',
      });
      console.log('Transaction hash:', txHash);
    } catch (error) {
      console.error('Transaction failed:', error);
    }
  };

  if (status === 'connected') {
    return (
      <div>
        <h2>Connected to {currentProvider?.name}</h2>
        <p>Account: {utils.formatAddress(accounts[0])}</p>
        <p>Chain ID: {chainId}</p>
        <button onClick={handleSignMessage}>Sign Message</button>
        <button onClick={handleSendTransaction}>Send Transaction</button>
        <button onClick={disconnect}>Disconnect</button>
      </div>
    );
  }

  return (
    <div>
      <h2>Connect Your Wallet</h2>
      {providers.map((provider) => (
        <button key={provider.name} onClick={() => connect(provider.name)}>
          Connect {provider.name}
        </button>
      ))}
    </div>
  );
}

export default Web3App;

๐Ÿ”ง Advanced Configuration

const {
  providers,
  currentProvider,
  accounts,
  chainId,
  status,
  error,
  isConnecting,
  connect,
  disconnect,
  getAccount,
  getAccounts,
  getBalance,
  getUserTransactionCount,
  estimateGas,
  signMessage,
  signTypedData,
  sendTransaction,
  getTransactionReceipt,
  waitForTransaction,
  switchToDefaultNetwork,
  customRequest,
  utils,
  clearError,
  refreshProviders
} = useWeb3Provider({
  // Provider preferences
  preferred: ['metamask', 'coinbase', 'trustwallet'],
  fallbackToAny: true,
  
  // Auto-connection
  autoConnect: true,
  
  // Monitoring
  checkInterval: 2000,
  
  // Error handling
  maxRetries: 3,
  requestTimeout: 30000,
  
  // Event callbacks
  onAccountsChanged: (accounts) => {
    console.log('Accounts changed:', accounts);
  },
  onChainChanged: (chainId) => {
    console.log('Chain changed:', chainId);
  },
  onDisconnect: (error) => {
    console.log('Provider disconnected:', error);
  },
  onError: (error) => {
    console.error('Provider error:', error);
  },
  onProvidersChanged: (providers) => {
    console.log('Available providers:', providers);
  },
  
  // Debug mode
  debug: process.env.NODE_ENV === 'development'
});

๐Ÿ“š Complete API Reference

useWeb3Provider Hook

The main hook that provides all wallet functionality.

Parameters

interface Web3ProviderConfig {
  // Provider preferences
  preferred?: WalletProviderName[];           // Preferred providers in order
  fallbackToAny?: boolean;                    // Fallback to any available provider
  
  // Connection settings
  autoConnect?: boolean;                      // Auto-connect on initialization
  checkInterval?: number;                     // Provider detection interval (ms)
  
  // Error handling
  maxRetries?: number;                        // Max retry attempts for failed operations
  requestTimeout?: number;                    // Request timeout (ms)
  debug?: boolean;                            // Enable debug logging
  
  // Event callbacks
  onError?: (error: Web3ProviderError) => void;
  onAccountsChanged?: (accounts: string[]) => void;
  onChainChanged?: (chainId: string) => void;
  onDisconnect?: (error: any) => void;
  onProvidersChanged?: (providers: DetectedWalletProvider[]) => void;
}

Return Value

interface UseWeb3ProviderReturn {
  // Provider state
  providers: DetectedWalletProvider[];
  currentProvider: DetectedWalletProvider | null;
  accounts: string[];
  chainId: string | null;
  status: ProviderStatus;
  error: Web3ProviderError | null;
  isConnecting: boolean;
  isDetecting: boolean;
  
  // Connection management
  connect: (name: WalletProviderName) => Promise<ConnectionResult>;
  disconnect: () => void;
  getPreferredProvider: () => DetectedWalletProvider | undefined;
  getProviderByName: (name: WalletProviderName) => EthereumProvider | undefined;
  refreshProviders: () => DetectedWalletProvider[];
  clearError: () => void;
  
  // Wallet actions (when connected)
  getAccount: () => Promise<string>;
  getAccounts: () => Promise<string[]>;
  getBalance: (address?: string) => Promise<BalanceInfo>;
  getTransactionCount: (address?: string) => Promise<number>;
  estimateGas: (transaction: Partial<Transaction>) => Promise<GasEstimate>;
  signMessage: (message: string) => Promise<string>;
  signTypedData: (typedData: unknown) => Promise<string>;
  sendTransaction: (transaction: Transaction) => Promise<string>;
  getTransactionReceipt: (txHash: string) => Promise<TransactionReceipt>;
  waitForTransaction: (txHash: string) => Promise<TransactionReceipt>;
  switchToDefaultNetwork: () => Promise<void>;
  customRequest: <T = any>(method: string, params?: any[]) => Promise<T>;
  
  // Utilities
  utils: {
    weiToEth: (wei: string) => string;
    ethToWei: (eth: string) => string;
    formatAddress: (address: string) => string;
    isValidAddress: (address: string) => boolean;
    isValidChainId: (chainId: string) => boolean;
  };
}

Provider Status Types

type ProviderStatus = 
  | 'detecting'      // Scanning for providers
  | 'connected'      // Successfully connected
  | 'disconnected'   // Not connected
  | 'error';         // Error state

Error Handling

The SDK provides comprehensive error handling with specific error types:

// Custom error types
class Web3ProviderError extends Error {
  constructor(message: string, code: string, data?: any) {
    super(message);
    this.name = 'Web3ProviderError';
    this.code = code;
    this.data = data;
  }
  code: string;
  data?: any;
}

class ProviderNotFoundError extends Web3ProviderError {}
class ProviderNotConnectedError extends Web3ProviderError {}
class InvalidAccountError extends Web3ProviderError {}
class TransactionError extends Web3ProviderError {}
class NetworkError extends Web3ProviderError {}

// Error codes
const ERROR_CODES = {
  PROVIDER_NOT_FOUND: 'PROVIDER_NOT_FOUND',
  PROVIDER_NOT_CONNECTED: 'PROVIDER_NOT_CONNECTED',
  INVALID_ACCOUNT: 'INVALID_ACCOUNT',
  TRANSACTION_ERROR: 'TRANSACTION_ERROR',
  NETWORK_ERROR: 'NETWORK_ERROR',
  USER_REJECTED: 'USER_REJECTED',
  UNAUTHORIZED: 'UNAUTHORIZED',
  UNSUPPORTED_METHOD: 'UNSUPPORTED_METHOD',
  INVALID_PARAMS: 'INVALID_PARAMS',
  INTERNAL_ERROR: 'INTERNAL_ERROR',
  RESOURCE_UNAVAILABLE: 'RESOURCE_UNAVAILABLE',
  TRANSACTION_REJECTED: 'TRANSACTION_REJECTED',
  METHOD_NOT_SUPPORTED: 'METHOD_NOT_SUPPORTED',
  LIMIT_EXCEEDED: 'LIMIT_EXCEEDED',
  JSON_RPC_ERROR: 'JSON_RPC_ERROR',
};

Transaction Types

// EIP-1559 Transaction (recommended)
interface EIP1559Transaction {
  to?: string;
  from: string;
  gas?: string;
  value?: string;
  data?: string;
  maxFeePerGas: string;
  maxPriorityFeePerGas: string;
  chainId?: string;
  nonce?: string;
}

// Legacy Transaction (deprecated)
interface LegacyTransaction {
  to?: string;
  from: string;
  gas?: string;
  gasPrice: string;
  value?: string;
  data?: string;
  nonce?: string;
  chainId?: string;
}

type Transaction = LegacyTransaction | EIP1559Transaction;

// Transaction Receipt
interface TransactionReceipt {
  transactionHash: string;
  blockNumber: string;
  blockHash: string;
  transactionIndex: string;
  from: string;
  to: string;
  status: string;
  logs: TransactionLog[];
}

๐ŸŽฏ Advanced Examples

Complete dApp Integration

import React, { useEffect, useState } from 'react';
import { useWeb3Provider } from 'custom-web3-provider-sdk';

function CompleteDApp() {
  const {
    providers,
    currentProvider,
    accounts,
    chainId,
    status,
    error,
    connect,
    disconnect,
    getBalance,
    sendTransaction,
    signMessage,
    signTypedData,
    switchToDefaultNetwork,
    customRequest,
    utils
  } = useWeb3Provider({
    preferred: ['metamask', 'coinbase', 'trustwallet', 'lxxwallet'],
    autoConnect: true,
    debug: true,
    onAccountsChanged: (accounts) => {
      console.log('Accounts changed:', accounts);
    },
    onChainChanged: (chainId) => {
      console.log('Chain changed to:', chainId);
    }
  });

  const [balance, setBalance] = useState<string>('0');

  // Auto-refresh balance when connected
  useEffect(() => {
    const refreshBalance = async () => {
      if (status === 'connected' && accounts[0]) {
        try {
          const balanceInfo = await getBalance(accounts[0]);
          setBalance(balanceInfo.balanceInEth);
        } catch (error) {
          console.error('Failed to get balance:', error);
        }
      }
    };

    refreshBalance();
    const interval = setInterval(refreshBalance, 10000);
    return () => clearInterval(interval);
  }, [status, accounts]);

  const handleConnectWallet = async (providerName: string) => {
    try {
      await connect(providerName);
    } catch (error: any) {
      if (error.code === 'PROVIDER_NOT_FOUND') {
        alert(`${providerName} wallet is not installed. Please install it first.`);
      } else {
        alert(`Failed to connect: ${error.message}`);
      }
    }
  };

  const handleSendTransaction = async () => {
    if (!accounts[0]) return;

    try {
      const txHash = await sendTransaction({
        to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
        value: utils.ethToWei('0.001'), // Send 0.001 ETH
        maxFeePerGas: '0x2540be400',
        maxPriorityFeePerGas: '0x3b9aca00',
      });

      alert(`Transaction sent: ${txHash}`);
      
      // Refresh balance after transaction
      setTimeout(async () => {
        try {
          const balanceInfo = await getBalance(accounts[0]);
          setBalance(balanceInfo.balanceInEth);
        } catch (error) {
          console.error('Failed to refresh balance:', error);
        }
      }, 2000);
    } catch (error: any) {
      if (error.code === 'USER_REJECTED') {
        alert('Transaction cancelled by user');
      } else {
        alert(`Transaction failed: ${error.message}`);
      }
    }
  };

  const handleSignMessage = async () => {
    try {
      const message = `Hello from my dApp signed at ${new Date().toISOString()}`;
      const signature = await signMessage(message);
      console.log('Message signature:', signature);
      alert(`Signed message: ${signature.slice(0, 20)}...`);
    } catch (error: any) {
      alert(`Message signing failed: ${error.message}`);
    }
  };

  return (
    <div style={{ maxWidth: '800px', margin: '0 auto', padding: '20px' }}>
      <h1>Complete dApp Example</h1>
      
      {/* Connection Status */}
      <div style={{ padding: '20px', backgroundColor: '#f5f5f5', borderRadius: '8px', marginBottom: '20px' }}>
        <h3>Connection Status</h3>
        <p><strong>Status:</strong> {status}</p>
        {currentProvider && <p><strong>Provider:</strong> {currentProvider.name}</p>}
        {accounts[0] && <p><strong>Account:</strong> {accounts[0]}</p>}
        {chainId && <p><strong>Chain ID:</strong> {chainId}</p>}
        {balance !== '0' && <p><strong>Balance:</strong> {balance} ETH</p>}
      </div>

      {/* Actions */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))', gap: '20px' }}>
        {/* Connection Section */}
        <div style={{ padding: '20px', border: '1px solid #ddd', borderRadius: '8px' }}>
          <h3>๐Ÿ”— Wallet Connection</h3>
          {status === 'connected' ? (
            <button onClick={disconnect} style={{ padding: '10px 20px', backgroundColor: '#f44336', color: 'white', border: 'none', borderRadius: '4px' }}>
              Disconnect Wallet
            </button>
          ) : (
            <div>
              <p>Choose a wallet to connect:</p>
              {providers.map(provider => (
                <button
                  key={provider.name}
                  onClick={() => handleConnectWallet(provider.name)}
                  style={{ margin: '5px', padding: '10px 15px', backgroundColor: '#2196F3', color: 'white', border: 'none', borderRadius: '4px' }}
                >
                  Connect {provider.name}
                </button>
              ))}
            </div>
          )}
        </div>

        {/* Transaction Section */}
        {status === 'connected' && (
          <div style={{ padding: '20px', border: '1px solid #ddd', borderRadius: '8px' }}>
            <h3>๐Ÿ’ฐ Transactions</h3>
            <button onClick={handleSendTransaction} style={{ padding: '10px 20px', backgroundColor: '#4CAF50', color: 'white', border: 'none', borderRadius: '4px' }}>
              Send Test Transaction
            </button>
          </div>
        )}

        {/* Signing Section */}
        {status === 'connected' && (
          <div style={{ padding: '20px', border: '1px solid #ddd', borderRadius: '8px' }}>
            <h3>โœ๏ธ Message Signing</h3>
            <button onClick={handleSignMessage} style={{ padding: '10px 20px', backgroundColor: '#FF9800', color: 'white', border: 'none', borderRadius: '4px' }}>
              Sign Test Message
            </button>
          </div>
        )}
      </div>

      {/* Error Display */}
      {error && (
        <div style={{ padding: '15px', backgroundColor: '#ffebee', border: '1px solid #f44336', borderRadius: '4px', color: '#d32f2f' }}>
          <h4>โŒ Error</h4>
          <p>{error.message}</p>
          <p><strong>Code:</strong> {error.code}</p>
        </div>
      )}
    </div>
  );
}

export default CompleteDApp;

๐Ÿ”ง Custom Provider Requests (Any Method Supported)

import React, { useState, useEffect } from 'react';
import { useWeb3Provider } from 'custom-web3-provider-sdk';

function CustomRequestDemo() {
  const { customRequest, status, utils } = useWeb3Provider();
  const [blockNumber, setBlockNumber] = useState<string>('0');
  const [gasPrice, setGasPrice] = useState<string>('0');

  // Auto-refresh blockchain data
  useEffect(() => {
    const fetchBlockchainData = async () => {
      if (status === 'connected') {
        try {
          const [block, gas] = await Promise.all([
            customRequest<string>('eth_blockNumber'),
            customRequest<string>('eth_gasPrice')
          ]);
          setBlockNumber(block);
          setGasPrice(gas);
        } catch (error) {
          console.error('Failed to fetch blockchain data:', error);
        }
      }
    };

    fetchBlockchainData();
    const interval = setInterval(fetchBlockchainData, 10000);
    return () => clearInterval(interval);
  }, [status, customRequest]);

  const getBlockInformation = async () => {
    try {
      // Get current block
      const blockNumber = await customRequest<string>('eth_blockNumber');
      console.log('Current block:', parseInt(blockNumber, 16));

      // Get block details
      const block = await customRequest<any>('eth_getBlockByNumber', [
        blockNumber, true // with transactions
      ]);
      console.log('Block details:', block);

      // Get gas price
      const gasPrice = await customRequest<string>('eth_gasPrice');
      const gasInEth = utils.weiToEth(gasPrice);
      console.log('Gas price (ETH):', gasInEth);
      console.log('Gas price (Wei):', gasPrice);

      // Get network version
      const networkId = await customRequest<string>('net_version');
      console.log('Network version:', networkId);

      // Get chain ID
      const chainId = await customRequest<string>('eth_chainId');
      console.log('Chain ID:', chainId);

    } catch (error) {
      console.error('Block information failed:', error);
    }
  };

  const getContractData = async () => {
    try {
      const contractAddress = '0x742d35Cc6634C0532925a3b844Bc454e4438f44e';

      // Check if it's a contract
      const code = await customRequest<string>('eth_getCode', [
        contractAddress,
        'latest'
      ]);
      console.log('Contract code length:', code.length);
      console.log('Is contract:', code !== '0x');

      // Call contract method
      const result = await customRequest<string>('eth_call', [{
        to: contractAddress,
        data: '0x70a08231000000000000000000000000123456789012345678901234567890123456789012'
      }]);
      console.log('Contract call result:', result);
    } catch (error) {
      console.error('Contract interaction failed:', error);
    }
  };

  return (
    <div style={{ padding: '20px' }}>
      <h2>Custom Request Examples</h2>
      
      <div style={{ marginBottom: '20px' }}>
        <h3>Blockchain Data</h3>
        <p>Current Block: {parseInt(blockNumber, 16)}</p>
        <p>Gas Price: {utils.weiToEth(gasPrice)} ETH</p>
      </div>

      <div style={{ display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
        <button onClick={getBlockInformation} style={{ padding: '10px 20px', backgroundColor: '#4CAF50', color: 'white', border: 'none', borderRadius: '4px' }}>
          Get Block Info
        </button>
        <button onClick={getContractData} style={{ padding: '10px 20px', backgroundColor: '#2196F3', color: 'white', border: 'none', borderRadius: '4px' }}>
          Interact with Contract
        </button>
      </div>

      <div style={{ marginTop: '20px', padding: '15px', backgroundColor: '#f5f5f5', borderRadius: '4px' }}>
        <h4>Common Custom Request Methods:</h4>
        <ul>
          <li><code>eth_blockNumber</code> - Get current block number</li>
          <li><code>eth_gasPrice</code> - Get current gas price</li>
          <li><code>eth_getBalance</code> - Get account balance</li>
          <li><code>eth_getCode</code> - Check if address is a contract</li>
          <li><code>eth_call</code> - Read from smart contracts</li>
          <li><code>eth_estimateGas</code> - Estimate transaction gas</li>
          <li><code>eth_getTransactionReceipt</code> - Get transaction status</li>
          <li><code>net_version</code> - Get network ID</li>
        </ul>
      </div>
    </div>
  );
}

export default CustomRequestDemo;

๐Ÿ”„ Account Events Testing

The SDK now includes comprehensive account change event testing functionality to ensure reliable wallet integration:

Real-time Event Monitoring

import { useWeb3Provider } from 'custom-web3-provider-sdk';

function AccountEventsDemo() {
  const {
    accounts,
    chainId,
    status,
    currentProvider,
    connect,
    disconnect
  } = useWeb3Provider({
    preferred: ['metamask', 'coinbase', 'trustwallet', 'lxxwallet'],
    debug: true,
    
    // Enhanced event handlers with validation
    onAccountsChanged: (newAccounts) => {
      console.log('๐Ÿ”‘ Accounts changed:', newAccounts);
      if (newAccounts.length === 0) {
        console.log('โš ๏ธ Wallet disconnected');
      } else {
        console.log(`๐Ÿ“‹ Current accounts: ${newAccounts.join(', ')}`);
      }
    },
    
    onChainChanged: (newChainId) => {
      console.log('๐Ÿ”— Chain changed to:', newChainId);
    },
    
    onDisconnect: (error) => {
      console.error('๐Ÿ’” Provider disconnected:', error);
    },
    
    onError: (error) => {
      console.error('โŒ Provider error:', error);
    }
  });

  return (
    <div>
      <h2>Account Events Testing</h2>
      <div>
        <h3>Current State</h3>
        <p>Status: {status}</p>
        <p>Provider: {currentProvider?.name || 'None'}</p>
        <p>Chain ID: {chainId || 'None'}</p>
        <p>Accounts: {accounts.length > 0 ? `${accounts.length} account(s)` : 'None'}</p>
        {accounts.length > 0 && (
          <div>
            <h4>Account Addresses:</h4>
            {accounts.map((account, index) => (
              <div key={index} style={{ fontFamily: 'monospace', fontSize: '12px' }}>
                {account}
              </div>
            ))}
          </div>
        )}
      </div>
      
      <div style={{ marginTop: '20px' }}>
        <h3>How to Test</h3>
        <ol>
          <li>Connect to a wallet (MetaMask, Coinbase, Trust Wallet, LXX Wallet, etc.)</li>
          <li>In your wallet extension, switch to a different account</li>
          <li>Try switching to a different network (Ethereum, Polygon, etc.)</li>
          <li>Disconnect and reconnect your wallet</li>
          <li>Watch the console for real-time event logs</li>
        </ol>
        
        <div style={{ padding: '15px', backgroundColor: '#e8f5e8', borderRadius: '4px', marginTop: '10px' }}>
          <strong>Expected behavior:</strong> When you change accounts or networks in your wallet, 
          you should see events logged in the console and the UI should update automatically.
        </div>
      </div>
    </div>
  );
}

Event Testing Features

  • โœ… Real-time Account Changes: Detects when users switch accounts in their wallet
  • โœ… Network Switching: Monitors chain changes across different networks
  • โœ… Connection State: Tracks wallet connection and disconnection events
  • โœ… Error Handling: Comprehensive error logging and recovery
  • โœ… Validation: Input validation for all event data
  • โœ… Debug Logging: Detailed console output for troubleshooting

Supported Wallet Providers

The SDK now supports the following wallet providers:

  • MetaMask (window.ethereum)
  • Coinbase Wallet (window.coinbaseWalletExtension)
  • Trust Wallet (window.trustwallet)
  • Rabby Wallet (window.rabby)
  • Brave Wallet (window.brave)
  • LXX Wallet (window.lxxwallet) - New!
  • Custom Wallet (window.customWallet)

๐Ÿ›ก๏ธ Enhanced Security Features

Input Validation & Sanitization

import { useWeb3Provider } from 'custom-web3-provider-sdk';

function SecurityDemo() {
  const { signMessage, sendTransaction, utils } = useWeb3Provider({
    debug: true,
    onError: (error) => {
      console.error('Security error:', error.code, error.message);
    }
  });

  const secureSignMessage = async () => {
    try {
      const message = 'My secure message';
      // Auto-validation applied - length limit, content sanitization, type validation
      const signature = await signMessage(message);
      console.log('โœ… Secure signature:', signature);
    } catch (error) {
      if (error.code === 'INVALID_PARAMS') {
        console.error('โŒ Message validation failed:', error.message);
      }
    }
  };

  const secureTransaction = async () => {
    try {
      const transaction = {
        to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
        value: utils.ethToWei('1.5'),
        maxFeePerGas: '0x2540be400',
        maxPriorityFeePerGas: '0x3b9aca00',
      };

      // Security features applied:
      // - Value bounds checking
      // - Gas limit validation 
      // - Address format validation
      // - Nonce management
      const txHash = await sendTransaction(transaction);
      console.log('โœ… Secure transaction sent:', txHash);
    } catch (error) {
      console.error('โŒ Transaction security check failed:', error);
    }
  };

  return (
    <div>
      <button onClick={secureSignMessage}>๐Ÿ›ก๏ธ Secure Sign</button>
      <button onClick={secureTransaction}>๐Ÿ”’ Secure Transaction</button>
    </div>
  );
}

Enhanced Event Handling

function EventHandlingDemo() {
  const { 
    accounts, 
    chainId, 
    status,
    connect,
    utils 
  } = useWeb3Provider({
    onAccountsChanged: (newAccounts) => {
      // Validates each account address
      console.log('๐Ÿ”‘ Accounts changed:', newAccounts);
      console.log('- Valid accounts:', newAccounts.filter(utils.isValidAddress));
      
      if (newAccounts.length === 0) {
        console.log('โš ๏ธ Wallet disconnected');
      }
    },
    
    onChainChanged: (newChainId) => {
      // Validates chain ID format
      console.log('๐Ÿ”— Chain changed to:', newChainId);
      console.log('- Valid format:', utils.isValidChainId(newChainId));
    },
    
    onDisconnect: (error) => {
      console.log('๐Ÿ’” Provider disconnected:', error);
    },
    
    onError: (error) => {
      console.error('โŒ System error:', {
        code: error.code,
        message: error.message,
        data: error.data
      });
    }
  });

  return <div>Enhanced event handling active</div>;
}

๐Ÿ”ง Development Tools

Building and Development

# Install dependencies
npm install

# Type check
npm run type-check

# Lint code
npm run lint

# Fix linting errors
npm run lint:fix

# Format code
npm run format

# Build for production
npm run build

# Clean build files
npm run clean

# Run all checks (lint + type + format)
npm run check-all

๐Ÿฆบ Testing

# Run test suite
npm test

# Run tests with coverage
npm run test:coverage

# Run tests in watch mode
npm run test:watch

๐Ÿ“ฆ Publishing Guide

We've prepared the package for publishing:

# Build the project
npm run build

# Pack to verify contents
npm pack --dry-run

# Publish to npm (requires npm login first)
npm publish

Publishing Checklist

Before publishing:

  • โœ… Package name is custom-web3-provider-sdk
  • โœ… All "gala" references removed and replaced with "web3"
  • โœ… Package description updated for general-purpose use
  • โœ… All files included in package.json "files" field
  • โœ… TypeScript types exported properly
  • โœ… Build outputs compatible (ESM/CJS)
  • โœ… README is comprehensive and professional
  • โœ… Demo includes all major functionality
  • โœ… Error messages are production-ready

๐Ÿ”ง Configuration Files

TypeScript Configuration

The project includes multiple TypeScript configurations:

  • tsconfig.json - Base configuration
  • tsconfig.cjs.json - CommonJS build
  • tsconfig.esm.json - ESM build

ESLint Configuration

  • Uses eslint.config.js (flat config)
  • TypeScript support
  • Prettier integration
  • React hooks rules
  • Browser environment globals

Prettier Configuration

  • Single quotes
  • Semicolons required
  • 2-space indentation
  • 80 character line width
  • Trailing commas

๐Ÿ†• Recent Updates & Fixes

v1.0.6 - Account Events & LXX Wallet Support

๐Ÿ”ง Fixed Account Change Events

  • โœ… Fixed MetaMask account change events: Account changes now fire properly across all wallet providers
  • โœ… Enhanced global event handling: Improved event listener setup for better reliability
  • โœ… Real-time event testing: Added comprehensive testing functionality in the demo
  • โœ… Robust event validation: Enhanced input validation for all wallet events

๐Ÿ†• New Wallet Provider Support

  • โœ… LXX Wallet integration: Added support for window.lxxwallet provider
  • โœ… Enhanced provider detection: Improved detection patterns for all supported wallets
  • โœ… Better error handling: More robust error handling for provider-specific issues

๐Ÿ” Enhanced Debugging

  • โœ… Comprehensive logging: Added detailed debug logging for event handling
  • โœ… Event testing UI: Interactive testing interface in the demo application
  • โœ… Real-time monitoring: Live event log with color-coded messages

Breaking Changes

  • None in this version - fully backward compatible

๐ŸŽฏ Migration Guide

For anyone migrating from earlier versions:

  1. Hook name: useGalaProvider โ†’ useWeb3Provider
  2. Network switching: switchToGalaNetwork โ†’ switchToDefaultNetwork
  3. Error types: All error classes renamed to Web3* instead of Gala*
  4. General purpose: Module no longer tied to specific blockchain network

๐Ÿ“ž Support

For support:

  1. Check this README for documentation
  2. Look at the example implementations
  3. Open an issue on the GitHub repository
  4. Contact the development team

๐Ÿค Contributing

Contributions welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests (if applicable)
  5. Submit a pull request

๐Ÿ“„ License

MIT License - see LICENSE file for details.


Built with ๐Ÿ’œ for the complete Web3 ecosystem

Perfect for any blockchain project requiring:

  • โœ… Multi-wallet connection (including LXX Wallet)
  • โœ… Transaction handling
  • โœ… Secure message signing
  • โœ… Network switching
  • โœ… Real-time account change detection
  • โœ… Cross-platform compatibility
  • โœ… Production-ready error handling
  • โœ… Comprehensive TypeScript support
  • โœ… Event testing and validation