CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-web3-utils

Collection of utility functions used in web3.js for Ethereum dApp development

Pending
Overview
Eval results
Files

providers.mddocs/

Provider Abstractions

Abstract base classes for implementing EIP-1193 compatible providers and socket-based connections with automatic reconnection support. These classes provide the foundation for building Web3 providers.

Capabilities

EIP-1193 Provider

Abstract implementation of the EIP-1193 provider standard.

/**
 * Abstract EIP-1193 provider implementation
 * Extends Web3BaseProvider with EIP-1193 specific functionality
 */
abstract class Eip1193Provider<API extends Web3APISpec = EthExecutionAPI> extends Web3BaseProvider<API> {
  /**
   * Called when provider connects
   * Should be implemented by concrete providers
   */
  protected _onConnect(): void;

  /**
   * Called when provider disconnects
   * Should be implemented by concrete providers
   * @param code - Disconnection code
   * @param data - Optional disconnection data
   */
  protected _onDisconnect(code: number, data?: unknown): void;
}

Socket Provider

Abstract socket-based provider with reconnection capabilities.

/**
 * Abstract socket-based provider for WebSocket, IPC, etc.
 * Provides reconnection logic and socket management
 */
abstract class SocketProvider<
  MessageEvent, 
  CloseEvent, 
  ErrorEvent, 
  API extends Web3APISpec = EthExecutionAPI
> extends Eip1193Provider<API> {
  /**
   * Socket connection accessor
   * @returns Current socket connection
   */
  get SocketConnection(): unknown;

  /**
   * Creates new socket provider
   * @param socketPath - Path or URL for socket connection
   * @param socketOptions - Socket-specific options
   * @param reconnectOptions - Reconnection configuration
   */
  constructor(
    socketPath: string,
    socketOptions?: unknown,
    reconnectOptions?: Partial<ReconnectOptions>
  );

  /**
   * Establishes socket connection
   */
  connect(): void;

  /**
   * Closes socket connection
   * @param code - Close code
   * @param data - Close reason
   */
  disconnect(code?: number, data?: string): void;

  /**
   * Safely disconnects with timeout
   * @param code - Close code
   * @param data - Close reason
   * @param forceDisconnect - Force disconnect after timeout
   * @param ms - Timeout in milliseconds
   * @returns Promise that resolves when disconnected
   */
  safeDisconnect(code?: number, data?: string, forceDisconnect?: boolean, ms?: number): Promise<void>;

  /**
   * Resets provider state and connection
   */
  reset(): void;

  /**
   * Gets pending request queue size
   * @returns Number of pending requests
   */
  getPendingRequestQueueSize(): number;

  /**
   * Gets sent requests queue size
   * @returns Number of sent requests awaiting response
   */
  getSentRequestsQueueSize(): number;

  /**
   * Checks if provider supports subscriptions
   * @returns true if subscriptions are supported
   */
  supportsSubscriptions(): boolean;

  /**
   * Clears request queues
   * @param event - Optional connection event context
   */
  clearQueues(event?: ConnectionEvent): void;

  /**
   * Sends JSON-RPC request
   * @param request - Web3 API payload
   * @returns Promise resolving to JSON-RPC response
   */
  request<Method, ResultType>(
    request: Web3APIPayload<API, Method>
  ): Promise<JsonRpcResponseWithResult<ResultType>>;

  // Event listener methods inherited from EventEmitter
  on(event: string, listener: Function): this;
  once(event: string, listener: Function): this;
  removeListener(event: string, listener: Function): this;
  removeAllListeners(event?: string): this;
}

Reconnection Options

/**
 * Configuration for automatic reconnection
 */
type ReconnectOptions = {
  /**
   * Whether to automatically reconnect on connection loss
   */
  autoReconnect: boolean;
  
  /**
   * Delay between reconnection attempts in milliseconds
   */
  delay: number;
  
  /**
   * Maximum number of reconnection attempts
   */
  maxAttempts: number;
};

Usage Examples

Custom WebSocket Provider

import { SocketProvider, ReconnectOptions } from "web3-utils";

class CustomWebSocketProvider extends SocketProvider<MessageEvent, CloseEvent, ErrorEvent> {
  private ws: WebSocket | null = null;

  constructor(url: string, options?: WebSocketOptions, reconnectOptions?: Partial<ReconnectOptions>) {
    super(url, options, reconnectOptions);
  }

  // Implement required abstract methods
  get SocketConnection() {
    return this.ws;
  }

  connect(): void {
    if (this.ws?.readyState === WebSocket.OPEN) {
      return;
    }

    this.ws = new WebSocket(this.socketPath);
    
    this.ws.onopen = (event) => {
      this._onConnect();
      this.emit('connect');
    };

    this.ws.onmessage = (event) => {
      try {
        const data = JSON.parse(event.data);
        this.emit('message', data);
      } catch (error) {
        this.emit('error', error);
      }
    };

    this.ws.onclose = (event) => {
      this._onDisconnect(event.code, event.reason);
      this.emit('disconnect', event.code, event.reason);
    };

    this.ws.onerror = (event) => {
      this.emit('error', new Error('WebSocket error'));
    };
  }

  disconnect(code?: number, data?: string): void {
    if (this.ws) {
      this.ws.close(code, data);
      this.ws = null;
    }
  }

  // Implement request sending
  protected sendRequest(request: any): void {
    if (this.ws?.readyState === WebSocket.OPEN) {
      this.ws.send(JSON.stringify(request));
    } else {
      throw new Error('WebSocket not connected');
    }
  }
}

// Usage
const provider = new CustomWebSocketProvider('ws://localhost:8546', {}, {
  autoReconnect: true,
  delay: 5000,
  maxAttempts: 5
});

provider.on('connect', () => {
  console.log('Connected to WebSocket');
});

provider.on('disconnect', (code, reason) => {
  console.log(`Disconnected: ${code} - ${reason}`);
});

provider.on('error', (error) => {
  console.error('Provider error:', error);
});

provider.connect();

Custom HTTP Provider

import { Eip1193Provider } from "web3-utils";

class CustomHttpProvider extends Eip1193Provider {
  private url: string;
  private headers: Record<string, string>;

  constructor(url: string, options?: { headers?: Record<string, string> }) {
    super();
    this.url = url;
    this.headers = options?.headers || {};
  }

  protected _onConnect(): void {
    // HTTP providers are always "connected"
    this.emit('connect');
  }

  protected _onDisconnect(code: number, data?: unknown): void {
    // HTTP providers don't really disconnect
    this.emit('disconnect', code, data);
  }

  async request<Method, ResultType>(
    request: Web3APIPayload<any, Method>
  ): Promise<JsonRpcResponseWithResult<ResultType>> {
    try {
      const response = await fetch(this.url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          ...this.headers
        },
        body: JSON.stringify(request)
      });

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }

      const jsonResponse = await response.json();
      
      if (jsonResponse.error) {
        throw new Error(`RPC Error ${jsonResponse.error.code}: ${jsonResponse.error.message}`);
      }

      return jsonResponse;
    } catch (error) {
      this.emit('error', error);
      throw error;
    }
  }

  supportsSubscriptions(): boolean {
    return false; // HTTP doesn't support subscriptions
  }
}

// Usage
const httpProvider = new CustomHttpProvider('https://mainnet.infura.io/v3/YOUR_PROJECT_ID', {
  headers: {
    'Authorization': 'Bearer your-token'
  }
});

// Make requests
const result = await httpProvider.request({
  method: 'eth_getBalance',
  params: ['0x742E4C5b469F50A4a8b399D4915C1fc93d15651B', 'latest']
});

Provider with Queue Management

import { SocketProvider } from "web3-utils";

class ManagedSocketProvider extends SocketProvider<MessageEvent, CloseEvent, ErrorEvent> {
  constructor(socketPath: string) {
    super(socketPath, {}, {
      autoReconnect: true,
      delay: 2000,
      maxAttempts: 10
    });

    // Monitor queue sizes
    setInterval(() => {
      const pending = this.getPendingRequestQueueSize();
      const sent = this.getSentRequestsQueueSize();
      
      if (pending > 100 || sent > 50) {
        console.warn(`High queue sizes: pending=${pending}, sent=${sent}`);
      }
    }, 10000);
  }

  // Override to add queue management
  async request<Method, ResultType>(
    request: Web3APIPayload<any, Method>
  ): Promise<JsonRpcResponseWithResult<ResultType>> {
    // Check queue size before adding request
    if (this.getPendingRequestQueueSize() > 1000) {
      throw new Error('Request queue full');
    }

    return super.request(request);
  }

  // Custom method to clear queues when needed
  emergencyClearQueues(): void {
    console.log('Emergency queue clear initiated');
    this.clearQueues();
  }

  // Graceful shutdown
  async shutdown(): Promise<void> {
    console.log('Shutting down provider...');
    
    // Wait for queues to empty or timeout
    const maxWait = 30000; // 30 seconds
    const startTime = Date.now();
    
    while (
      (this.getPendingRequestQueueSize() > 0 || this.getSentRequestsQueueSize() > 0) &&
      (Date.now() - startTime) < maxWait
    ) {
      await new Promise(resolve => setTimeout(resolve, 100));
    }

    await this.safeDisconnect(1000, 'Normal shutdown', true, 5000);
    console.log('Provider shutdown complete');
  }
}

Common Usage Patterns

Provider Factory

import { SocketProvider, Eip1193Provider } from "web3-utils";

type ProviderConfig = {
  type: 'http' | 'websocket' | 'ipc';
  url: string;
  options?: any;
  reconnectOptions?: Partial<ReconnectOptions>;
};

function createProvider(config: ProviderConfig): Eip1193Provider {
  switch (config.type) {
    case 'http':
      return new CustomHttpProvider(config.url, config.options);
    case 'websocket':
      return new CustomWebSocketProvider(config.url, config.options, config.reconnectOptions);
    case 'ipc':
      return new CustomIPCProvider(config.url, config.options, config.reconnectOptions);
    default:
      throw new Error(`Unsupported provider type: ${config.type}`);
  }
}

// Usage
const provider = createProvider({
  type: 'websocket',
  url: 'ws://localhost:8546',
  reconnectOptions: {
    autoReconnect: true,
    delay: 3000,
    maxAttempts: 5
  }
});

Types

// Provider-related types
type ConnectionEvent = 'connect' | 'disconnect' | 'error';

interface Web3APISpec {
  [method: string]: {
    Parameters: any[];
    ReturnType: any;
  };
}

interface Web3APIPayload<API extends Web3APISpec, Method extends keyof API> {
  method: Method;
  params: API[Method]['Parameters'];
}

interface Web3BaseProvider<API extends Web3APISpec> {
  request<Method extends keyof API>(
    request: Web3APIPayload<API, Method>
  ): Promise<API[Method]['ReturnType']>;
}

Install with Tessl CLI

npx tessl i tessl/npm-web3-utils

docs

conversion.md

data-manipulation.md

events.md

hashing.md

index.md

json-rpc.md

promises.md

providers.md

random-validation.md

tile.json