CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-web3-core

Core tools and utilities for the web3.js ecosystem, providing foundational layer functionality for blockchain interactions.

Pending
Overview
Eval results
Files

provider-integration.mddocs/

Provider Integration

The Web3 provider integration system provides comprehensive support for various blockchain providers with type guards, capability detection, and seamless integration patterns. It abstracts provider differences and enables consistent blockchain communication across different provider types.

Capabilities

Provider Type Guards

Utility functions for detecting and validating different provider types with TypeScript type narrowing.

/**
 * Check if provider is a Web3 provider instance
 * @template API - JSON-RPC API specification type
 * @param provider - Provider to check
 * @returns Type guard indicating if provider is Web3BaseProvider
 */
function isWeb3Provider<API extends Web3APISpec = Web3APISpec>(
  provider: unknown
): provider is Web3BaseProvider<API>;

/**
 * Check if provider is a MetaMask provider instance
 * @template API - JSON-RPC API specification type
 * @param provider - Provider to check
 * @returns Type guard indicating if provider is MetaMaskProvider
 */
function isMetaMaskProvider<API extends Web3APISpec = Web3APISpec>(
  provider: unknown
): provider is MetaMaskProvider<API>;

/**
 * Check if provider is a legacy request provider
 * @param provider - Provider to check
 * @returns Type guard indicating if provider is LegacyRequestProvider
 */
function isLegacyRequestProvider(provider: unknown): provider is LegacyRequestProvider;

/**
 * Check if provider is an EIP-1193 compliant provider
 * @template API - JSON-RPC API specification type
 * @param provider - Provider to check
 * @returns Type guard indicating if provider is EIP1193Provider
 */
function isEIP1193Provider<API extends Web3APISpec = Web3APISpec>(
  provider: unknown
): provider is EIP1193Provider<API>;

/**
 * Check if provider is a legacy send provider
 * @param provider - Provider to check
 * @returns Type guard indicating if provider is LegacySendProvider
 */
function isLegacySendProvider(provider: unknown): provider is LegacySendProvider;

/**
 * Check if provider is a legacy sendAsync provider
 * @param provider - Provider to check
 * @returns Type guard indicating if provider is LegacySendAsyncProvider
 */
function isLegacySendAsyncProvider(provider: unknown): provider is LegacySendAsyncProvider;

/**
 * Check if provider is any supported provider type
 * @template API - JSON-RPC API specification type
 * @param provider - Provider to check
 * @returns Type guard indicating if provider is SupportedProviders
 */
function isSupportedProvider<API extends Web3APISpec = Web3APISpec>(
  provider: unknown
): provider is SupportedProviders<API>;

Usage Examples:

import { 
  isWeb3Provider, 
  isMetaMaskProvider, 
  isEIP1193Provider,
  isSupportedProvider,
  isLegacyRequestProvider
} from "web3-core";

// Type-safe provider detection
function handleProvider(provider: unknown) {
  if (isMetaMaskProvider(provider)) {
    // TypeScript knows this is MetaMaskProvider
    console.log("MetaMask detected");
    console.log("Chain ID:", provider.chainId);
    console.log("Selected address:", provider.selectedAddress);
    
    // MetaMask-specific methods available
    provider.request({ method: "eth_requestAccounts", params: [] });
    
  } else if (isEIP1193Provider(provider)) {
    // TypeScript knows this is EIP1193Provider
    console.log("EIP-1193 provider detected");
    
    // Standard EIP-1193 interface
    provider.request({ method: "eth_blockNumber", params: [] });
    
  } else if (isWeb3Provider(provider)) {
    // TypeScript knows this is Web3BaseProvider
    console.log("Web3 provider detected");
    
    // Web3.js provider interface
    provider.request({ method: "eth_gasPrice", params: [] }, (error, result) => {
      if (error) console.error(error);
      else console.log("Gas price:", result);
    });
    
  } else if (isLegacyRequestProvider(provider)) {
    // TypeScript knows this is LegacyRequestProvider
    console.log("Legacy request provider detected");
    
    // Legacy interface
    provider.request("eth_blockNumber", [], (error, result) => {
      console.log("Block number:", result);
    });
    
  } else if (isSupportedProvider(provider)) {
    // Any other supported provider type
    console.log("Supported provider detected");
    
  } else {
    console.error("Unsupported provider type");
  }
}

// Browser provider detection
if (typeof window !== 'undefined' && window.ethereum) {
  handleProvider(window.ethereum);
} else {
  console.log("No browser provider found");
}

Subscription Support Detection

Functions for detecting WebSocket subscription capabilities in providers.

/**
 * Check if provider supports subscriptions (WebSocket functionality)
 * @template API - JSON-RPC API specification type
 * @param provider - Provider to check
 * @returns Boolean indicating subscription support
 */
function isSupportSubscriptions<API extends Web3APISpec = Web3APISpec>(
  provider: unknown
): boolean;

Usage Examples:

import { isSupportSubscriptions } from "web3-core";

// Check subscription support before creating subscription manager
function setupBlockchainConnection(provider: unknown) {
  if (!isSupportedProvider(provider)) {
    throw new Error("Unsupported provider");
  }
  
  const requestManager = new Web3RequestManager(provider);
  
  if (isSupportSubscriptions(provider)) {
    console.log("Provider supports subscriptions - setting up WebSocket features");
    
    // Create subscription manager for real-time updates
    const subscriptionManager = new Web3SubscriptionManager(
      requestManager,
      {
        newBlockHeaders: NewBlockHeadersSubscription,
        logs: LogsSubscription,
        pendingTransactions: PendingTransactionsSubscription
      }
    );
    
    // Subscribe to new blocks
    subscriptionManager.subscribe("newBlockHeaders").then(subscription => {
      subscription.on("data", (blockHeader) => {
        console.log("New block:", blockHeader.number);
      });
    });
    
    return { requestManager, subscriptionManager };
    
  } else {
    console.log("Provider doesn't support subscriptions - using polling");
    
    // Fall back to polling for updates
    const pollForBlocks = async () => {
      const blockNumber = await requestManager.send({
        method: "eth_blockNumber",
        params: []
      });
      console.log("Latest block (polling):", parseInt(blockNumber, 16));
    };
    
    setInterval(pollForBlocks, 12000); // Poll every 12 seconds
    
    return { requestManager };
  }
}

// Usage with different provider types
const httpProvider = "https://eth-mainnet.g.alchemy.com/v2/your-api-key";
const wsProvider = "wss://eth-mainnet.ws.alchemyapi.io/v2/your-api-key";

console.log("HTTP supports subscriptions:", isSupportSubscriptions(httpProvider)); // false
console.log("WebSocket supports subscriptions:", isSupportSubscriptions(wsProvider)); // true

setupBlockchainConnection(wsProvider);

Provider Configuration Patterns

Common patterns for configuring and working with different provider types.

Usage Examples:

// Pattern: Multi-provider setup with fallback
function createResilientConnection() {
  const providers = [
    "wss://eth-mainnet.ws.alchemyapi.io/v2/your-api-key", // Primary WebSocket
    "https://eth-mainnet.g.alchemy.com/v2/your-api-key",  // Fallback HTTP
    "https://cloudflare-eth.com",                          // Public fallback
  ];
  
  for (const provider of providers) {
    try {
      if (isSupportedProvider(provider)) {
        const requestManager = new Web3RequestManager(provider);
        
        console.log(`Connected to ${provider}`);
        console.log(`Subscription support: ${isSupportSubscriptions(provider)}`);
        
        return {
          requestManager,
          hasSubscriptions: isSupportSubscriptions(provider),
          providerType: typeof provider === 'string' ? 'url' : 'object'
        };
      }
    } catch (error) {
      console.warn(`Failed to connect to ${provider}:`, error);
    }
  }
  
  throw new Error("No working provider found");
}

// Pattern: Browser provider detection and setup
function setupBrowserProvider() {
  // Check for injected providers
  if (typeof window === 'undefined') {
    throw new Error("Not in browser environment");
  }
  
  const providers = [
    { name: "MetaMask", provider: window.ethereum },
    { name: "WalletConnect", provider: (window as any).WalletConnect },
    { name: "Coinbase", provider: (window as any).coinbaseWalletExtension }
  ];
  
  for (const { name, provider } of providers) {
    if (provider && isSupportedProvider(provider)) {
      console.log(`${name} provider detected`);
      
      if (isMetaMaskProvider(provider)) {
        // MetaMask-specific setup
        console.log("MetaMask chain ID:", provider.chainId);
        console.log("MetaMask accounts:", provider.selectedAddress);
        
        // Listen to MetaMask events
        provider.on("accountsChanged", (accounts: string[]) => {
          console.log("Accounts changed:", accounts);
        });
        
        provider.on("chainChanged", (chainId: string) => {
          console.log("Chain changed:", chainId);
        });
        
      } else if (isEIP1193Provider(provider)) {
        // Standard EIP-1193 setup
        console.log("EIP-1193 provider setup");
      }
      
      return new Web3RequestManager(provider);
    }
  }
  
  throw new Error("No supported browser provider found");
}

// Pattern: Provider feature detection
function analyzeProvider(provider: unknown) {
  const analysis = {
    isSupported: isSupportedProvider(provider),
    type: 'unknown' as string,
    features: {
      subscriptions: false,
      accounts: false,
      events: false,
      batch: false
    }
  };
  
  if (!analysis.isSupported) {
    return analysis;
  }
  
  // Determine provider type
  if (isMetaMaskProvider(provider)) {
    analysis.type = 'MetaMask';
    analysis.features.accounts = true;
    analysis.features.events = true;
  } else if (isEIP1193Provider(provider)) {
    analysis.type = 'EIP-1193';
    analysis.features.accounts = true;
  } else if (isWeb3Provider(provider)) {
    analysis.type = 'Web3';
    analysis.features.batch = true;
  } else if (isLegacyRequestProvider(provider)) {
    analysis.type = 'Legacy Request';
  } else if (isLegacySendProvider(provider)) {
    analysis.type = 'Legacy Send';
  } else if (isLegacySendAsyncProvider(provider)) {
    analysis.type = 'Legacy SendAsync';
  }
  
  // Check subscription support
  analysis.features.subscriptions = isSupportSubscriptions(provider);
  
  return analysis;
}

// Usage
const analysis = analyzeProvider(window.ethereum);
console.log("Provider analysis:", analysis);

Custom Provider Integration

Patterns for integrating custom or specialized providers.

Usage Examples:

// Pattern: Custom provider wrapper
class CustomProviderWrapper {
  constructor(private baseProvider: any) {}
  
  async request(args: { method: string; params?: any[] }) {
    // Add authentication headers
    const headers = {
      'Authorization': `Bearer ${this.getAuthToken()}`,
      'X-API-Key': 'your-api-key'
    };
    
    // Custom request logic
    try {
      const result = await this.baseProvider.request({
        ...args,
        headers
      });
      
      // Custom response processing
      return this.processResponse(result);
    } catch (error) {
      // Custom error handling
      throw this.processError(error);
    }
  }
  
  private getAuthToken(): string {
    // Token management logic
    return localStorage.getItem('auth-token') || '';
  }
  
  private processResponse(response: any): any {
    // Custom response transformation
    return response;
  }
  
  private processError(error: any): Error {
    // Custom error transformation
    return new Error(`Custom provider error: ${error.message}`);
  }
}

// Use custom provider
const customProvider = new CustomProviderWrapper(window.ethereum);

// Verify it's supported
if (isSupportedProvider(customProvider)) {
  const requestManager = new Web3RequestManager(customProvider);
} else {
  console.error("Custom provider is not compatible");
}

// Pattern: Provider proxy for caching
class CachingProviderProxy {
  private cache = new Map<string, { result: any; timestamp: number }>();
  private cacheTimeout = 30000; // 30 seconds
  
  constructor(private provider: any) {}
  
  async request(args: { method: string; params?: any[] }) {
    const cacheKey = JSON.stringify(args);
    const cached = this.cache.get(cacheKey);
    
    // Return cached result if still valid
    if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
      console.log("Cache hit for:", args.method);
      return cached.result;
    }
    
    // Make actual request
    const result = await this.provider.request(args);
    
    // Cache the result
    this.cache.set(cacheKey, {
      result,
      timestamp: Date.now()
    });
    
    return result;
  }
}

// Pattern: Provider load balancer
class LoadBalancingProvider {
  private currentIndex = 0;
  
  constructor(private providers: any[]) {}
  
  async request(args: { method: string; params?: any[] }) {
    const maxAttempts = this.providers.length;
    
    for (let attempt = 0; attempt < maxAttempts; attempt++) {
      const provider = this.providers[this.currentIndex];
      this.currentIndex = (this.currentIndex + 1) % this.providers.length;
      
      try {
        return await provider.request(args);
      } catch (error) {
        console.warn(`Provider ${this.currentIndex} failed:`, error);
        
        if (attempt === maxAttempts - 1) {
          throw new Error("All providers failed");
        }
      }
    }
  }
}

// Create load-balanced provider
const loadBalancer = new LoadBalancingProvider([
  "https://eth-mainnet.g.alchemy.com/v2/your-api-key",
  "https://mainnet.infura.io/v3/your-project-id",
  "https://cloudflare-eth.com"
]);

if (isSupportedProvider(loadBalancer)) {
  const requestManager = new Web3RequestManager(loadBalancer);
}

Provider Events and Lifecycle

Handling provider events and managing provider lifecycle changes.

Usage Examples:

// Pattern: Provider event handling
function setupProviderEvents(provider: unknown) {
  if (isMetaMaskProvider(provider)) {
    // MetaMask events
    provider.on("accountsChanged", (accounts: string[]) => {
      console.log("Accounts changed:", accounts);
      if (accounts.length === 0) {
        console.log("User disconnected");
      }
    });
    
    provider.on("chainChanged", (chainId: string) => {
      console.log("Chain changed to:", parseInt(chainId, 16));
      // Reload application or update context
      window.location.reload();
    });
    
    provider.on("disconnect", (error: { code: number; message: string }) => {
      console.error("Provider disconnected:", error);
    });
    
  } else if (isEIP1193Provider(provider)) {
    // Standard EIP-1193 events
    provider.on("accountsChanged", (accounts: string[]) => {
      console.log("EIP-1193 accounts changed:", accounts);
    });
    
    provider.on("chainChanged", (chainId: string) => {
      console.log("EIP-1193 chain changed:", chainId);
    });
  }
}

// Pattern: Provider health monitoring
class ProviderHealthMonitor {
  private isHealthy = true;
  private lastCheck = Date.now();
  private checkInterval = 30000; // 30 seconds
  
  constructor(private provider: any) {
    this.startMonitoring();
  }
  
  private startMonitoring() {
    setInterval(async () => {
      try {
        await this.provider.request({
          method: "eth_blockNumber",
          params: []
        });
        
        if (!this.isHealthy) {
          console.log("Provider recovered");
          this.isHealthy = true;
        }
        
        this.lastCheck = Date.now();
      } catch (error) {
        if (this.isHealthy) {
          console.error("Provider health check failed:", error);
          this.isHealthy = false;
        }
      }
    }, this.checkInterval);
  }
  
  getHealthStatus() {
    return {
      isHealthy: this.isHealthy,
      lastCheck: this.lastCheck,
      timeSinceLastCheck: Date.now() - this.lastCheck
    };
  }
}

// Use health monitor
const healthMonitor = new ProviderHealthMonitor(provider);
console.log("Provider health:", healthMonitor.getHealthStatus());

Install with Tessl CLI

npx tessl i tessl/npm-web3-core

docs

batch-processing.md

configuration-management.md

context-management.md

event-system.md

index.md

provider-integration.md

request-management.md

subscription-management.md

tile.json