import { n as __exportAll } from "./chunk-BEJ448es.mjs";
import { i as createPublicClient, n as http } from "./_esm-BKtdEVdT.mjs";
import { a as mainnet, c as base, i as optimism, l as arbitrum, r as polygon } from "./chains-Bx4KIVmV.mjs";
//#region extensions/crypto/src/services/rpc-provider.ts
/**
* Multi-RPC Provider — fault-tolerant RPC access with automatic failover.
*
* Supports multiple RPC providers per chain, with:
* - Priority-ordered provider list
* - Automatic failover on error or timeout (>2s)
* - Rate limit detection (429) with exponential backoff
* - Circuit breaker (5 failures in 60s → skip provider for 5 min)
* - User-configurable via plugin config
*/
var rpc_provider_exports = /* @__PURE__ */ __exportAll({
	RpcManager: () => RpcManager,
	getRpcManager: () => getRpcManager
});
const CUSTOM_RPC_ENV = {
	8453: "RPC_URL_BASE",
	1: "RPC_URL_ETH",
	42161: "RPC_URL_ARB",
	10: "RPC_URL_OP",
	137: "RPC_URL_POLYGON"
};
const QUICKNODE_ENV = {
	8453: "QUICKNODE_ENDPOINT_BASE",
	1: "QUICKNODE_ENDPOINT_ETH",
	42161: "QUICKNODE_ENDPOINT_ARB",
	10: "QUICKNODE_ENDPOINT_OP",
	137: "QUICKNODE_ENDPOINT_POLYGON"
};
const DEFAULT_PROVIDERS = {
	[8453]: [
		{
			url: "",
			name: "QuickNode",
			priority: 1,
			fullUrlEnv: "QUICKNODE_ENDPOINT_BASE"
		},
		{
			url: "https://base-mainnet.g.alchemy.com/v2/",
			name: "Alchemy",
			priority: 2,
			apiKeyEnv: "ALCHEMY_API_KEY"
		},
		{
			url: "https://base.llamarpc.com",
			name: "LlamaNodes",
			priority: 3
		},
		{
			url: "https://mainnet.base.org",
			name: "Base Public",
			priority: 4
		},
		{
			url: "https://base.drpc.org",
			name: "dRPC",
			priority: 5
		},
		{
			url: "https://base.meowrpc.com",
			name: "MeowRPC",
			priority: 6
		},
		{
			url: "https://1rpc.io/base",
			name: "1RPC",
			priority: 7
		}
	],
	[1]: [
		{
			url: "",
			name: "QuickNode",
			priority: 1,
			fullUrlEnv: "QUICKNODE_ENDPOINT_ETH"
		},
		{
			url: "https://eth-mainnet.g.alchemy.com/v2/",
			name: "Alchemy",
			priority: 2,
			apiKeyEnv: "ALCHEMY_API_KEY"
		},
		{
			url: "https://eth.llamarpc.com",
			name: "LlamaNodes",
			priority: 3
		},
		{
			url: "https://ethereum.publicnode.com",
			name: "PublicNode",
			priority: 4
		},
		{
			url: "https://eth.drpc.org",
			name: "dRPC",
			priority: 5
		},
		{
			url: "https://1rpc.io/eth",
			name: "1RPC",
			priority: 6
		},
		{
			url: "https://rpc.ankr.com/eth",
			name: "Ankr",
			priority: 7
		}
	],
	[42161]: [
		{
			url: "",
			name: "QuickNode",
			priority: 1,
			fullUrlEnv: "QUICKNODE_ENDPOINT_ARB"
		},
		{
			url: "https://arb-mainnet.g.alchemy.com/v2/",
			name: "Alchemy",
			priority: 2,
			apiKeyEnv: "ALCHEMY_API_KEY"
		},
		{
			url: "https://arbitrum.llamarpc.com",
			name: "LlamaNodes",
			priority: 3
		},
		{
			url: "https://arb1.arbitrum.io/rpc",
			name: "Arbitrum Public",
			priority: 4
		},
		{
			url: "https://arbitrum.drpc.org",
			name: "dRPC",
			priority: 5
		},
		{
			url: "https://1rpc.io/arb",
			name: "1RPC",
			priority: 6
		}
	],
	[10]: [
		{
			url: "",
			name: "QuickNode",
			priority: 1,
			fullUrlEnv: "QUICKNODE_ENDPOINT_OP"
		},
		{
			url: "https://opt-mainnet.g.alchemy.com/v2/",
			name: "Alchemy",
			priority: 2,
			apiKeyEnv: "ALCHEMY_API_KEY"
		},
		{
			url: "https://optimism.llamarpc.com",
			name: "LlamaNodes",
			priority: 3
		},
		{
			url: "https://mainnet.optimism.io",
			name: "OP Public",
			priority: 4
		},
		{
			url: "https://optimism.drpc.org",
			name: "dRPC",
			priority: 5
		},
		{
			url: "https://1rpc.io/op",
			name: "1RPC",
			priority: 6
		}
	],
	[137]: [
		{
			url: "",
			name: "QuickNode",
			priority: 1,
			fullUrlEnv: "QUICKNODE_ENDPOINT_POLYGON"
		},
		{
			url: "https://polygon-mainnet.g.alchemy.com/v2/",
			name: "Alchemy",
			priority: 2,
			apiKeyEnv: "ALCHEMY_API_KEY"
		},
		{
			url: "https://polygon.llamarpc.com",
			name: "LlamaNodes",
			priority: 3
		},
		{
			url: "https://polygon-rpc.com",
			name: "Polygon Public",
			priority: 4
		},
		{
			url: "https://polygon.drpc.org",
			name: "dRPC",
			priority: 5
		},
		{
			url: "https://1rpc.io/matic",
			name: "1RPC",
			priority: 6
		}
	]
};
const CHAIN_MAP = {
	1: mainnet,
	8453: base,
	42161: arbitrum,
	10: optimism,
	137: polygon
};
const CHAIN_NAME_TO_ID = {
	ethereum: 1,
	eth: 1,
	mainnet: 1,
	base: 8453,
	arbitrum: 42161,
	arb: 42161,
	optimism: 10,
	op: 10,
	polygon: 137,
	matic: 137
};
const MEV_PROTECTION_RPCS = [
	{
		url: "https://rpc.flashbots.net",
		name: "Flashbots Protect",
		chains: [1]
	},
	{
		url: "https://rpc.mevblocker.io",
		name: "MEV Blocker",
		chains: [1]
	},
	{
		url: "https://rpc.flashbots.net/fast",
		name: "Flashbots Fast",
		chains: [1]
	},
	{
		url: "https://base.flashbots.net",
		name: "Flashbots Base",
		chains: [8453]
	}
];
const healthMap = /* @__PURE__ */ new Map();
function getHealth(key) {
	let h = healthMap.get(key);
	if (!h) {
		h = {
			failures: 0,
			lastFailure: 0,
			circuitOpenUntil: 0,
			backoffMs: 0,
			lastRateLimited: 0
		};
		healthMap.set(key, h);
	}
	return h;
}
function recordFailure(key, isRateLimit, config) {
	const h = getHealth(key);
	h.failures++;
	h.lastFailure = Date.now();
	if (isRateLimit) {
		h.lastRateLimited = Date.now();
		h.backoffMs = Math.min((h.backoffMs || 1e3) * 2, 6e4);
	}
	if (h.failures >= config.circuitThreshold) h.circuitOpenUntil = Date.now() + config.circuitResetMs;
}
function recordSuccess(key) {
	const h = getHealth(key);
	h.failures = 0;
	h.backoffMs = 0;
	h.circuitOpenUntil = 0;
}
function isAvailable(key) {
	const h = healthMap.get(key);
	if (!h) return true;
	if (h.circuitOpenUntil > Date.now()) return false;
	if (h.lastRateLimited > 0 && Date.now() - h.lastRateLimited < h.backoffMs) return false;
	return true;
}
var RpcManager = class {
	config;
	clientCache = /* @__PURE__ */ new Map();
	constructor(userConfig = {}) {
		this.config = {
			providers: userConfig.providers ?? {},
			timeoutMs: userConfig.timeoutMs ?? 3e3,
			circuitThreshold: userConfig.circuitThreshold ?? 5,
			circuitResetMs: userConfig.circuitResetMs ?? 3e5,
			mevProtection: userConfig.mevProtection ?? true
		};
	}
	/** Resolve a chain name or ID to a numeric chain ID. */
	resolveChainId(chainInput) {
		if (typeof chainInput === "number") return chainInput;
		const num = parseInt(chainInput, 10);
		if (!isNaN(num)) return num;
		return CHAIN_NAME_TO_ID[chainInput.toLowerCase()] ?? 8453;
	}
	/** Get the ordered list of providers for a chain, filtered by health. */
	getProviders(chainId) {
		const custom = [];
		const chainEnv = CUSTOM_RPC_ENV[chainId];
		if (chainEnv && process.env[chainEnv]) custom.push({
			url: process.env[chainEnv],
			name: "Custom",
			priority: 0
		});
		if (custom.length === 0 && process.env.RPC_URL) custom.push({
			url: process.env.RPC_URL,
			name: "Custom",
			priority: 0
		});
		const qnChainEnv = QUICKNODE_ENV[chainId];
		if (!(qnChainEnv && process.env[qnChainEnv]) && process.env.QUICKNODE_ENDPOINT) custom.push({
			url: process.env.QUICKNODE_ENDPOINT,
			name: "QuickNode",
			priority: 0
		});
		const userProviders = this.config.providers[String(chainId)];
		const defaults = DEFAULT_PROVIDERS[chainId] ?? [];
		const base = userProviders ?? defaults;
		return [...custom, ...base].filter((p) => {
			if (p.apiKeyEnv && !process.env[p.apiKeyEnv]) return false;
			if (p.fullUrlEnv && !process.env[p.fullUrlEnv]) return false;
			return isAvailable(`${chainId}:${p.name}`);
		}).sort((a, b) => a.priority - b.priority);
	}
	/** Build the full RPC URL for a provider (append API key if needed). */
	buildUrl(provider) {
		if (provider.fullUrlEnv) {
			const fullUrl = process.env[provider.fullUrlEnv];
			if (fullUrl) return fullUrl;
		}
		if (provider.apiKeyEnv) {
			const key = process.env[provider.apiKeyEnv];
			if (key) return `${provider.url}${key}`;
		}
		return provider.url;
	}
	/**
	* Get a viem PublicClient for the given chain.
	* Tries providers in priority order, failing over on errors.
	*/
	async getClient(chainInput = "base") {
		const chainId = this.resolveChainId(chainInput);
		const providers = this.getProviders(chainId);
		if (providers.length === 0) throw new Error(`No available RPC providers for chain ${chainId}. Set ALCHEMY_API_KEY or configure custom providers.`);
		let lastError = null;
		for (const provider of providers) {
			const cacheKey = `${chainId}:${provider.name}`;
			const cached = this.clientCache.get(cacheKey);
			if (cached) return cached;
			try {
				const url = this.buildUrl(provider);
				const chain = CHAIN_MAP[chainId];
				const client = createPublicClient({
					chain,
					transport: http(url, { timeout: this.config.timeoutMs })
				});
				await client.getBlockNumber();
				recordSuccess(cacheKey);
				this.clientCache.set(cacheKey, client);
				return client;
			} catch (err) {
				lastError = err;
				if (lastError.message) lastError.message = lastError.message.replace(/[?&/][a-zA-Z0-9_\-]{20,}/g, "/[REDACTED]");
				recordFailure(cacheKey, lastError.message.includes("429") || lastError.message.toLowerCase().includes("rate limit"), {
					circuitThreshold: this.config.circuitThreshold,
					circuitResetMs: this.config.circuitResetMs
				});
				this.clientCache.delete(cacheKey);
			}
		}
		const sanitizedError = lastError?.message?.replace(/[?&/][a-zA-Z0-9_\-]{20,}/g, "/[REDACTED]") ?? "Unknown error";
		throw new Error(`All RPC providers failed for chain ${chainId}. Last error: ${sanitizedError}`);
	}
	/** Clear all cached clients (useful when switching chains). */
	clearCache() {
		this.clientCache.clear();
	}
	/** Get health status of all providers (for diagnostics). */
	getHealthReport(chainId) {
		return (DEFAULT_PROVIDERS[chainId] ?? []).map((p) => {
			const key = `${chainId}:${p.name}`;
			const h = healthMap.get(key);
			return {
				name: p.name,
				url: p.url,
				available: isAvailable(key),
				failures: h?.failures ?? 0,
				circuitOpen: (h?.circuitOpenUntil ?? 0) > Date.now()
			};
		});
	}
	/** List supported chain IDs. */
	getSupportedChains() {
		return Object.keys(DEFAULT_PROVIDERS).map(Number);
	}
	/** Check if MEV protection is enabled. */
	isMevProtectionEnabled() {
		return this.config.mevProtection;
	}
	/**
	* Get MEV-protected RPC URLs for a chain.
	* Returns private transaction RPCs that bypass the public mempool.
	* Falls back to empty array if no MEV RPCs are available for the chain.
	*/
	getMevRpcs(chainId) {
		if (!this.config.mevProtection) return [];
		return MEV_PROTECTION_RPCS.filter((r) => r.chains.includes(chainId));
	}
	/**
	* Get a viem http transport configured for MEV-protected submission.
	* Uses Flashbots Protect (primary) with MEV Blocker as fallback.
	* Returns null if no MEV RPCs are available for the chain.
	*/
	getMevTransport(chainId) {
		const rpcs = this.getMevRpcs(chainId);
		if (rpcs.length === 0) return null;
		for (const rpc of rpcs) if (isAvailable(`mev:${chainId}:${rpc.name}`)) return http(rpc.url, { timeout: this.config.timeoutMs });
		return http(rpcs[0].url, { timeout: this.config.timeoutMs });
	}
	/**
	* Record a MEV RPC failure (for circuit breaker tracking).
	*/
	recordMevFailure(chainId, rpcName, isRateLimit = false) {
		recordFailure(`mev:${chainId}:${rpcName}`, isRateLimit, {
			circuitThreshold: this.config.circuitThreshold,
			circuitResetMs: this.config.circuitResetMs
		});
	}
	/**
	* Record a MEV RPC success.
	*/
	recordMevSuccess(chainId, rpcName) {
		recordSuccess(`mev:${chainId}:${rpcName}`);
	}
};
let _instance = null;
function getRpcManager(config) {
	if (!_instance) _instance = new RpcManager(config);
	return _instance;
}
//#endregion
export { rpc_provider_exports as n, getRpcManager as t };

//# sourceMappingURL=rpc-provider-BELb8v5m.mjs.map