Core tools and utilities for the web3.js ecosystem, providing foundational layer functionality for blockchain interactions.
—
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.
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");
}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);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);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);
}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