UNPKG

@openzeppelin/contracts-ui-builder-adapter-evm

Version:
1,514 lines (1,486 loc) 212 kB
var __defProp = Object.defineProperty; var __getOwnPropNames = Object.getOwnPropertyNames; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __esm = (fn, res) => function __init() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); // src/wallet/rainbowkit/rainbowkitAssetManager.ts var rainbowkitAssetManager_exports = {}; __export(rainbowkitAssetManager_exports, { ensureRainbowKitAssetsLoaded: () => ensureRainbowKitAssetsLoaded }); import { logger as logger9 } from "@openzeppelin/contracts-ui-builder-utils"; async function ensureRainbowKitAssetsLoaded() { if (loadedAssets) { logger9.debug("RainbowKitAssetManager", "Assets already loaded, returning cached."); return loadedAssets; } if (!providerPromise) { providerPromise = import("@rainbow-me/rainbowkit").then((module) => { const component = module.RainbowKitProvider; logger9.info("RainbowKitAssetManager", "RainbowKitProvider module loaded."); return component; }).catch((err) => { logger9.error("RainbowKitAssetManager", "Failed to load RainbowKitProvider module:", err); return null; }); } if (!cssPromise) { cssPromise = import("@rainbow-me/rainbowkit/styles.css").then(() => { logger9.info("RainbowKitAssetManager", "RainbowKit CSS loaded successfully."); return true; }).catch((err) => { logger9.error("RainbowKitAssetManager", "Failed to load RainbowKit CSS:", err); return false; }); } try { const [ProviderComponent, cssLoadedSuccess] = await Promise.all([providerPromise, cssPromise]); loadedAssets = { ProviderComponent, cssLoaded: cssLoadedSuccess }; if (!ProviderComponent || !cssLoadedSuccess) { logger9.warn( "RainbowKitAssetManager", "One or more RainbowKit assets failed to load.", loadedAssets ); } return loadedAssets; } catch (error) { logger9.error("RainbowKitAssetManager", "Error in Promise.all for asset loading:", error); loadedAssets = { ProviderComponent: null, cssLoaded: false }; return loadedAssets; } } var loadedAssets, providerPromise, cssPromise; var init_rainbowkitAssetManager = __esm({ "src/wallet/rainbowkit/rainbowkitAssetManager.ts"() { "use strict"; loadedAssets = null; providerPromise = null; cssPromise = null; } }); // src/adapter.ts import { logger as logger34 } from "@openzeppelin/contracts-ui-builder-utils"; // src/abi/comparison.ts import { logger, simpleHash } from "@openzeppelin/contracts-ui-builder-utils"; // src/abi/types.ts function isValidAbiArray(value) { return Array.isArray(value) && value.every(isValidAbiItem); } function isValidAbiItem(item) { if (typeof item !== "object" || item === null) { return false; } const abiItem = item; if (typeof abiItem.type !== "string") { return false; } const validTypes = ["function", "event", "constructor", "error", "fallback", "receive"]; if (!validTypes.includes(abiItem.type)) { return false; } if ((abiItem.type === "function" || abiItem.type === "event") && typeof abiItem.name !== "string") { return false; } if ((abiItem.type === "function" || abiItem.type === "event" || abiItem.type === "constructor") && abiItem.inputs !== void 0 && !Array.isArray(abiItem.inputs)) { return false; } return true; } // src/abi/comparison.ts var AbiComparisonService = class { /** * Compares two ABIs and returns detailed difference analysis */ compareAbis(abi1, abi2) { try { const validation1 = this.validateAbi(abi1); const validation2 = this.validateAbi(abi2); if (!validation1.valid || !validation2.valid) { return { identical: false, differences: [], severity: "breaking", summary: "One or both ABIs are invalid and cannot be compared" }; } const normalized1 = this.normalizeAbi(validation1.normalizedAbi); const normalized2 = this.normalizeAbi(validation2.normalizedAbi); const hash1 = simpleHash(JSON.stringify(normalized1)); const hash2 = simpleHash(JSON.stringify(normalized2)); if (hash1 === hash2) { return { identical: true, differences: [], severity: "none", summary: "ABIs are identical" }; } const differences = this.findDifferences(normalized1, normalized2); const severity = this.calculateSeverity(differences); return { identical: false, differences, severity, summary: this.generateSummary(differences) }; } catch (error) { logger.error("ABI comparison failed:", error.message); return { identical: false, differences: [], severity: "breaking", summary: `Comparison failed: ${error.message}` }; } } /** * Validates ABI structure and format */ validateAbi(abiString) { const errors = []; const warnings = []; try { const abi = JSON.parse(abiString); if (!Array.isArray(abi)) { errors.push("ABI must be an array"); return { valid: false, errors, warnings }; } if (abi.length === 0) { errors.push( "ABI array cannot be empty - contract must have at least one function, event, or constructor" ); return { valid: false, errors, warnings }; } for (let i = 0; i < abi.length; i++) { const item = abi[i]; if (!item.type) { errors.push(`Item ${i}: Missing 'type' field`); continue; } if (!["function", "event", "constructor", "error", "fallback", "receive"].includes(item.type)) { errors.push(`Item ${i}: Invalid type '${item.type}'`); } if (item.type === "function" && !item.name) { errors.push(`Item ${i}: Function missing 'name' field`); } if ((item.type === "function" || item.type === "event") && !Array.isArray(item.inputs)) { errors.push(`Item ${i}: Missing or invalid 'inputs' array`); } if (item.type === "function" && !Array.isArray(item.outputs)) { warnings.push(`Item ${i}: Function missing 'outputs' array`); } } if (errors.length === 0 && !isValidAbiArray(abi)) { errors.push("ABI does not conform to expected format"); } return { valid: errors.length === 0, errors, warnings, normalizedAbi: errors.length === 0 ? abi : void 0 }; } catch (parseError) { errors.push(`Invalid JSON: ${parseError.message}`); return { valid: false, errors, warnings }; } } /** * Creates deterministic hash of ABI for quick comparison */ hashAbi(abiString) { try { const validation = this.validateAbi(abiString); if (!validation.valid || !validation.normalizedAbi) { throw new Error("Cannot hash invalid ABI"); } const normalized = this.normalizeAbi(validation.normalizedAbi); const normalizedString = JSON.stringify(normalized); return simpleHash(normalizedString); } catch (error) { logger.error("ABI hashing failed:", error.message); throw new Error(`Failed to hash ABI: ${error.message}`); } } /** * Normalizes ABI for consistent comparison */ normalizeAbi(abi) { return abi.map((item) => { const normalized = { ...item }; if (normalized.inputs) { normalized.inputs = [...normalized.inputs].sort( (a, b) => (a.name || "").localeCompare(b.name || "") ); } if (normalized.outputs) { normalized.outputs = [...normalized.outputs].sort( (a, b) => (a.name || "").localeCompare(b.name || "") ); } return normalized; }).sort((a, b) => { const typeOrder = { constructor: 0, fallback: 1, receive: 2, function: 3, event: 4, error: 5 }; const aOrder = typeOrder[a.type] ?? 99; const bOrder = typeOrder[b.type] ?? 99; if (aOrder !== bOrder) return aOrder - bOrder; const aName = a.name || ""; const bName = b.name || ""; return aName.localeCompare(bName); }); } /** * Finds detailed differences between two normalized ABIs */ findDifferences(abi1, abi2) { const differences = []; const map1 = this.createAbiMap(abi1); const map2 = this.createAbiMap(abi2); for (const [key, item] of map1) { if (!map2.has(key)) { differences.push({ type: "removed", section: item.type, // eslint-disable-next-line @typescript-eslint/no-explicit-any name: item.name || item.type, details: `${item.type} was removed`, impact: this.calculateImpact(item.type, "removed"), oldSignature: this.generateSignature(item) }); } } for (const [key, item] of map2) { if (!map1.has(key)) { differences.push({ type: "added", section: item.type, // eslint-disable-next-line @typescript-eslint/no-explicit-any name: item.name || item.type, details: `${item.type} was added`, impact: this.calculateImpact(item.type, "added"), newSignature: this.generateSignature(item) }); } } for (const [key, item1] of map1) { const item2 = map2.get(key); if (item2 && !this.itemsEqual(item1, item2)) { differences.push({ type: "modified", section: item1.type, // eslint-disable-next-line @typescript-eslint/no-explicit-any name: item1.name || item1.type, details: `${item1.type} signature changed`, impact: this.calculateImpact(item1.type, "modified"), oldSignature: this.generateSignature(item1), newSignature: this.generateSignature(item2) }); } } return differences; } // eslint-disable-next-line @typescript-eslint/no-explicit-any createAbiMap(abi) { const map = /* @__PURE__ */ new Map(); for (const item of abi) { const key = this.generateItemKey(item); map.set(key, item); } return map; } // eslint-disable-next-line @typescript-eslint/no-explicit-any generateItemKey(item) { if (item.type === "constructor" || item.type === "fallback" || item.type === "receive") { return item.type; } const name = item.name || ""; const inputs = item.inputs?.map((input) => input.type).join(",") || ""; return `${item.type}:${name}(${inputs})`; } // eslint-disable-next-line @typescript-eslint/no-explicit-any generateSignature(item) { if (item.type === "constructor") { const inputs = ( // eslint-disable-next-line @typescript-eslint/no-explicit-any item.inputs?.map((input) => `${input.type} ${input.name || ""}`).join(", ") || "" ); return `constructor(${inputs})`; } if (item.type === "fallback" || item.type === "receive") { return item.type + "()"; } if (item.type === "function") { const inputs = ( // eslint-disable-next-line @typescript-eslint/no-explicit-any item.inputs?.map((input) => `${input.type} ${input.name || ""}`).join(", ") || "" ); const outputs = item.outputs?.map((output) => output.type).join(", ") || ""; const mutability = item.stateMutability ? ` ${item.stateMutability}` : ""; return `function ${item.name}(${inputs})${mutability}${outputs ? ` returns (${outputs})` : ""}`; } if (item.type === "event") { const inputs = item.inputs?.map((input) => { const indexed = input.indexed ? " indexed" : ""; return `${input.type}${indexed} ${input.name || ""}`; }).join(", ") || ""; return `event ${item.name}(${inputs})`; } return JSON.stringify(item); } // eslint-disable-next-line @typescript-eslint/no-explicit-any itemsEqual(item1, item2) { return JSON.stringify(item1) === JSON.stringify(item2); } calculateImpact(type, changeType) { if (type === "constructor" || type === "fallback" || type === "receive") { return changeType === "modified" ? "high" : "medium"; } if (type === "function") { if (changeType === "removed") return "high"; if (changeType === "modified") return "medium"; if (changeType === "added") return "low"; } if (type === "event") { return "low"; } if (type === "error") { return "low"; } return "medium"; } calculateSeverity(differences) { if (differences.length === 0) return "none"; const hasHighImpact = differences.some((d) => d.impact === "high"); const hasMediumImpact = differences.some((d) => d.impact === "medium"); const hasRemovedFunctions = differences.some( (d) => d.type === "removed" && d.section === "function" ); if (hasRemovedFunctions || hasHighImpact) return "breaking"; if (hasMediumImpact) return "major"; return "minor"; } generateSummary(differences) { const counts = { added: differences.filter((d) => d.type === "added").length, removed: differences.filter((d) => d.type === "removed").length, modified: differences.filter((d) => d.type === "modified").length }; const parts = []; if (counts.added > 0) parts.push(`${counts.added} added`); if (counts.removed > 0) parts.push(`${counts.removed} removed`); if (counts.modified > 0) parts.push(`${counts.modified} modified`); const summary = parts.join(", "); return `${summary}`; } }; var abiComparisonService = new AbiComparisonService(); // src/types/providers.ts var EvmProviderKeys = { Etherscan: "etherscan", Sourcify: "sourcify" }; var EVM_PROVIDER_ORDER_DEFAULT = [ EvmProviderKeys.Etherscan, EvmProviderKeys.Sourcify ]; function isEvmProviderKey(value) { return value === EvmProviderKeys.Etherscan || value === EvmProviderKeys.Sourcify; } // src/wallet/components/EvmWalletUiRoot.tsx import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { createConfig as createConfig2, http as http3 } from "@wagmi/core"; import { mainnet } from "viem/chains"; import { WagmiProvider } from "wagmi"; import { useEffect as useEffect5, useMemo, useState as useState5 } from "react"; import { logger as logger11 } from "@openzeppelin/contracts-ui-builder-utils"; // src/wallet/context/wagmi-context.tsx import { createContext } from "react"; var WagmiProviderInitializedContext = createContext(false); // src/wallet/evmUiKitManager.ts import { logger as logger10 } from "@openzeppelin/contracts-ui-builder-utils"; // src/wallet/utils/walletImplementationManager.ts import { appConfigService as appConfigService3, logger as logger8 } from "@openzeppelin/contracts-ui-builder-utils"; // src/wallet/implementation/wagmi-implementation.ts import { injected, metaMask, safe, walletConnect } from "@wagmi/connectors"; import { connect, createConfig, disconnect, getAccount, getPublicClient as getWagmiCorePublicClient, getWalletClient as getWagmiWalletClient, switchChain, watchAccount } from "@wagmi/core"; import { http as http2 } from "viem"; import { appConfigService as appConfigService2, logger as logger7 } from "@openzeppelin/contracts-ui-builder-utils"; // src/networks/mainnet.ts import { arbitrum as viemArbitrum, avalanche as viemAvalanche, base as viemBase, bsc as viemBsc, linea as viemLinea, mainnet as viemMainnet, optimism as viemOptimism, polygon as viemPolygon, polygonZkEvm as viemPolygonZkEvm, scroll as viemScroll, zksync as viemZkSync } from "viem/chains"; var ethereumMainnet = { id: "ethereum-mainnet", exportConstName: "ethereumMainnet", name: "Ethereum", ecosystem: "evm", network: "ethereum", type: "mainnet", isTestnet: false, chainId: 1, rpcUrl: viemMainnet.rpcUrls.default.http[0], explorerUrl: "https://etherscan.io", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "ethereum", nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }, viemChain: viemMainnet }; var arbitrumMainnet = { id: "arbitrum-mainnet", exportConstName: "arbitrumMainnet", name: "Arbitrum One", ecosystem: "evm", network: "arbitrum", type: "mainnet", isTestnet: false, chainId: 42161, rpcUrl: viemArbitrum.rpcUrls.default.http[0], explorerUrl: "https://arbiscan.io", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "arbitrum", nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }, viemChain: viemArbitrum }; var polygonMainnet = { id: "polygon-mainnet", exportConstName: "polygonMainnet", name: "Polygon", ecosystem: "evm", network: "polygon", type: "mainnet", isTestnet: false, chainId: 137, rpcUrl: viemPolygon.rpcUrls.default.http[0], explorerUrl: "https://polygonscan.com", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "polygon", nativeCurrency: { name: "MATIC", symbol: "MATIC", decimals: 18 }, viemChain: viemPolygon }; var polygonZkEvmMainnet = { id: "polygon-zkevm-mainnet", exportConstName: "polygonZkEvmMainnet", name: "Polygon zkEVM", ecosystem: "evm", network: "polygon-zkevm", type: "mainnet", isTestnet: false, chainId: 1101, rpcUrl: viemPolygonZkEvm.rpcUrls.default.http[0], explorerUrl: "https://zkevm.polygonscan.com", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "polygon", nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }, viemChain: viemPolygonZkEvm }; var baseMainnet = { id: "base-mainnet", exportConstName: "baseMainnet", name: "Base", ecosystem: "evm", network: "base", type: "mainnet", isTestnet: false, chainId: 8453, rpcUrl: viemBase.rpcUrls.default.http[0], explorerUrl: "https://basescan.org", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "base", nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }, viemChain: viemBase }; var bscMainnet = { id: "bsc-mainnet", exportConstName: "bscMainnet", name: "BNB Smart Chain", ecosystem: "evm", network: "bsc", type: "mainnet", isTestnet: false, chainId: 56, rpcUrl: viemBsc.rpcUrls.default.http[0], explorerUrl: "https://bscscan.com", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "bsc", nativeCurrency: { name: "BNB", symbol: "BNB", decimals: 18 }, viemChain: viemBsc }; var optimismMainnet = { id: "optimism-mainnet", exportConstName: "optimismMainnet", name: "OP Mainnet", ecosystem: "evm", network: "optimism", type: "mainnet", isTestnet: false, chainId: 10, rpcUrl: viemOptimism.rpcUrls.default.http[0], explorerUrl: "https://optimistic.etherscan.io", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "optimism", nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }, viemChain: viemOptimism }; var avalancheMainnet = { id: "avalanche-mainnet", exportConstName: "avalancheMainnet", name: "Avalanche C-Chain", ecosystem: "evm", network: "avalanche", type: "mainnet", isTestnet: false, chainId: 43114, rpcUrl: viemAvalanche.rpcUrls.default.http[0], explorerUrl: "https://snowscan.xyz", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "avalanche", nativeCurrency: { name: "Avalanche", symbol: "AVAX", decimals: 18 }, viemChain: viemAvalanche }; var zkSyncEraMainnet = { id: "zksync-era-mainnet", exportConstName: "zkSyncEraMainnet", name: "ZkSync Era", ecosystem: "evm", network: "zksync-era", type: "mainnet", isTestnet: false, chainId: 324, rpcUrl: viemZkSync.rpcUrls.default.http[0], explorerUrl: "https://explorer.zksync.io", apiUrl: "https://block-explorer-api.mainnet.zksync.io/api", primaryExplorerApiIdentifier: "zksync-era-mainnet", supportsEtherscanV2: false, icon: "zksync", nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }, viemChain: viemZkSync }; var scrollMainnet = { id: "scroll-mainnet", exportConstName: "scrollMainnet", name: "Scroll", ecosystem: "evm", network: "scroll", type: "mainnet", isTestnet: false, chainId: 534352, rpcUrl: viemScroll.rpcUrls.default.http[0], explorerUrl: "https://scrollscan.com", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "scroll", nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }, viemChain: viemScroll }; var lineaMainnet = { id: "linea-mainnet", exportConstName: "lineaMainnet", name: "Linea", ecosystem: "evm", network: "linea", type: "mainnet", isTestnet: false, chainId: 59144, rpcUrl: viemLinea.rpcUrls.default.http[0], explorerUrl: "https://lineascan.build", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "linea", nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }, viemChain: viemLinea }; // src/networks/testnet.ts import { arbitrumSepolia as viemArbitrumSepolia, avalancheFuji as viemAvalancheFuji, baseSepolia as viemBaseSepolia, bscTestnet as viemBscTestnet, lineaSepolia as viemLineaSepolia, monadTestnet as viemMonadTestnet, optimismSepolia as viemOptimismSepolia, polygonAmoy as viemPolygonAmoy, polygonZkEvmCardona as viemPolygonZkEvmCardona, scrollSepolia as viemScrollSepolia, sepolia as viemSepolia, zksyncSepoliaTestnet as viemZkSyncSepoliaTestnet } from "viem/chains"; var ethereumSepolia = { id: "ethereum-sepolia", exportConstName: "ethereumSepolia", name: "Sepolia", ecosystem: "evm", network: "ethereum", type: "testnet", isTestnet: true, chainId: 11155111, rpcUrl: viemSepolia.rpcUrls.default.http[0], explorerUrl: "https://sepolia.etherscan.io", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "ethereum", nativeCurrency: { name: "Sepolia Ether", symbol: "ETH", decimals: 18 }, viemChain: viemSepolia }; var arbitrumSepolia = { id: "arbitrum-sepolia", exportConstName: "arbitrumSepolia", name: "Arbitrum Sepolia", ecosystem: "evm", network: "arbitrum", type: "testnet", isTestnet: true, chainId: 421614, rpcUrl: viemArbitrumSepolia.rpcUrls.default.http[0], explorerUrl: "https://sepolia.arbiscan.io", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "arbitrum", nativeCurrency: { name: "Arbitrum Sepolia Ether", symbol: "ETH", decimals: 18 }, viemChain: viemArbitrumSepolia }; var polygonAmoy = { id: "polygon-amoy", exportConstName: "polygonAmoy", name: "Polygon Amoy", ecosystem: "evm", network: "polygon", type: "testnet", isTestnet: true, chainId: 80002, rpcUrl: viemPolygonAmoy.rpcUrls.default.http[0], explorerUrl: "https://amoy.polygonscan.com", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "polygon", nativeCurrency: { name: "MATIC", symbol: "MATIC", decimals: 18 }, viemChain: viemPolygonAmoy }; var polygonZkEvmCardona = { id: "polygon-zkevm-cardona", exportConstName: "polygonZkEvmCardona", name: "Polygon zkEVM Cardona", ecosystem: "evm", network: "polygon-zkevm", type: "testnet", isTestnet: true, chainId: 2442, rpcUrl: viemPolygonZkEvmCardona.rpcUrls.default.http[0], explorerUrl: "https://cardona-zkevm.polygonscan.com", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "polygon", nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }, viemChain: viemPolygonZkEvmCardona }; var baseSepolia = { id: "base-sepolia", exportConstName: "baseSepolia", name: "Base Sepolia", ecosystem: "evm", network: "base", type: "testnet", isTestnet: true, chainId: 84532, rpcUrl: viemBaseSepolia.rpcUrls.default.http[0], explorerUrl: "https://sepolia.basescan.org", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "base", nativeCurrency: { name: "Sepolia Ether", symbol: "ETH", decimals: 18 }, viemChain: viemBaseSepolia }; var bscTestnet = { id: "bsc-testnet", exportConstName: "bscTestnet", name: "BSC Testnet", ecosystem: "evm", network: "bsc", type: "testnet", isTestnet: true, chainId: 97, rpcUrl: viemBscTestnet.rpcUrls.default.http[0], explorerUrl: "https://testnet.bscscan.com", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "bsc", nativeCurrency: { name: "BNB", symbol: "BNB", decimals: 18 }, viemChain: viemBscTestnet }; var optimismSepolia = { id: "optimism-sepolia", exportConstName: "optimismSepolia", name: "OP Sepolia", ecosystem: "evm", network: "optimism", type: "testnet", isTestnet: true, chainId: 11155420, rpcUrl: viemOptimismSepolia.rpcUrls.default.http[0], explorerUrl: "https://sepolia-optimism.etherscan.io", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "optimism", nativeCurrency: { name: "Sepolia Ether", symbol: "ETH", decimals: 18 }, viemChain: viemOptimismSepolia }; var avalancheFuji = { id: "avalanche-fuji", exportConstName: "avalancheFuji", name: "Avalanche Fuji C-Chain", ecosystem: "evm", network: "avalanche", type: "testnet", isTestnet: true, chainId: 43113, rpcUrl: viemAvalancheFuji.rpcUrls.default.http[0], explorerUrl: "https://testnet.snowscan.xyz", apiUrl: "https://api.etherscan.io/v2/api", // Using Etherscan V2 unified API primaryExplorerApiIdentifier: "etherscan-v2", // Unified identifier for V2 API supportsEtherscanV2: true, requiresExplorerApiKey: true, icon: "avalanche", nativeCurrency: { name: "Avalanche", symbol: "AVAX", decimals: 18 }, viemChain: viemAvalancheFuji }; var zksyncSepoliaTestnet = { id: "zksync-era-sepolia", exportConstName: "zksyncSepoliaTestnet", name: "ZkSync Era Sepolia", ecosystem: "evm", network: "zksync-era", type: "testnet", isTestnet: true, chainId: 300, rpcUrl: viemZkSyncSepoliaTestnet.rpcUrls.default.http[0], explorerUrl: "https://sepolia.explorer.zksync.io", apiUrl: "https://block-explorer-api.sepolia.zksync.dev/api", primaryExplorerApiIdentifier: "zksync-era-sepolia", supportsEtherscanV2: false, icon: "zksync", nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }, viemChain: viemZkSyncSepoliaTestnet }; var scrollSepolia = { id: "scroll-sepolia", exportConstName: "scrollSepolia", name: "Scroll Sepolia", ecosystem: "evm", network: "scroll", type: "testnet", isTestnet: true, chainId: 534351, rpcUrl: viemScrollSepolia.rpcUrls.default.http[0], explorerUrl: "https://sepolia.scrollscan.dev", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "scroll", nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }, viemChain: viemScrollSepolia }; var lineaSepolia = { id: "linea-sepolia", exportConstName: "lineaSepolia", name: "Linea Sepolia", ecosystem: "evm", network: "linea", type: "testnet", isTestnet: true, chainId: 59141, rpcUrl: viemLineaSepolia.rpcUrls.default.http[0], explorerUrl: "https://sepolia.lineascan.build", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "linea", nativeCurrency: { name: "Linea Ether", symbol: "ETH", decimals: 18 }, viemChain: viemLineaSepolia }; var monadTestnet = { id: "monad-testnet", exportConstName: "monadTestnet", name: "Monad Testnet", ecosystem: "evm", network: "monad", type: "testnet", isTestnet: true, chainId: 10143, rpcUrl: viemMonadTestnet.rpcUrls.default.http[0], explorerUrl: "https://testnet.monadexplorer.com", apiUrl: "https://api.etherscan.io/v2/api", primaryExplorerApiIdentifier: "etherscan-v2", supportsEtherscanV2: true, icon: "monad", nativeCurrency: { name: "Monad", symbol: "MON", decimals: 18 }, viemChain: viemMonadTestnet }; // src/networks/index.ts var evmMainnetNetworks = [ ethereumMainnet, arbitrumMainnet, baseMainnet, polygonMainnet, polygonZkEvmMainnet, bscMainnet, optimismMainnet, avalancheMainnet, lineaMainnet, scrollMainnet, zkSyncEraMainnet // Other mainnet networks... ]; var evmTestnetNetworks = [ ethereumSepolia, arbitrumSepolia, baseSepolia, polygonAmoy, polygonZkEvmCardona, bscTestnet, optimismSepolia, avalancheFuji, lineaSepolia, scrollSepolia, zksyncSepoliaTestnet, monadTestnet // Other testnet networks... ]; var evmNetworks = [...evmMainnetNetworks, ...evmTestnetNetworks]; // src/wallet/rainbowkit/components.tsx import { Loader2 as Loader23 } from "lucide-react"; import { useContext as useContext2, useEffect as useEffect4, useRef, useState as useState4 } from "react"; import { Button as Button4 } from "@openzeppelin/contracts-ui-builder-ui"; import { cn as cn4, logger as logger4 } from "@openzeppelin/contracts-ui-builder-utils"; // src/wallet/components/connect/ConnectButton.tsx import { Loader2, Wallet } from "lucide-react"; import { useEffect as useEffect3, useState as useState3 } from "react"; import { useDerivedAccountStatus as useDerivedAccountStatus2, useDerivedConnectStatus as useDerivedConnectStatus2 } from "@openzeppelin/contracts-ui-builder-react-core"; import { Button as Button2 } from "@openzeppelin/contracts-ui-builder-ui"; import { cn } from "@openzeppelin/contracts-ui-builder-utils"; // src/wallet/utils/SafeWagmiComponent.tsx import { useEffect, useState } from "react"; import { logger as logger2 } from "@openzeppelin/contracts-ui-builder-utils"; // src/wallet/hooks/useIsWagmiProviderInitialized.ts import { useContext } from "react"; var useIsWagmiProviderInitialized = () => { return useContext(WagmiProviderInitializedContext); }; // src/wallet/utils/SafeWagmiComponent.tsx import { Fragment, jsx } from "react/jsx-runtime"; var SafeWagmiComponent = ({ children, fallback = null }) => { const isProviderInitialized = useIsWagmiProviderInitialized(); const [hasError, setHasError] = useState(false); useEffect(() => { if (isProviderInitialized) { setHasError(false); } }, [isProviderInitialized]); useEffect(() => { const handleError = (event) => { if (event.error?.message?.includes("useConfig") || event.error?.message?.includes("WagmiProvider")) { logger2.debug( "SafeWagmiComponent", "Caught wagmi error via window error event:", event.error ); setHasError(true); event.preventDefault(); } }; window.addEventListener("error", handleError); return () => { window.removeEventListener("error", handleError); }; }, []); if (!isProviderInitialized || hasError) { return /* @__PURE__ */ jsx(Fragment, { children: fallback }); } try { return /* @__PURE__ */ jsx(Fragment, { children }); } catch (error) { if (error instanceof Error && (error.message.includes("useConfig") || error.message.includes("WagmiProvider"))) { logger2.debug("SafeWagmiComponent", "Caught wagmi error:", error); setHasError(true); return /* @__PURE__ */ jsx(Fragment, { children: fallback }); } throw error; } }; // src/wallet/components/connect/ConnectorDialog.tsx import { useEffect as useEffect2, useState as useState2 } from "react"; import { useDerivedAccountStatus, useDerivedConnectStatus } from "@openzeppelin/contracts-ui-builder-react-core"; import { Button, Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@openzeppelin/contracts-ui-builder-ui"; // src/wallet/hooks/useUiKitConfig.ts import { appConfigService, logger as logger3 } from "@openzeppelin/contracts-ui-builder-utils"; var defaultConfig = { kitName: "custom", // Default to using our custom implementation for EVM kitConfig: { showInjectedConnector: false // Default to hiding the injected connector } }; var uiKitConfig = { ...defaultConfig }; function loadInitialConfigFromAppService() { logger3.debug("useUiKitConfig", "Attempting to load initial config from AppConfigService..."); const configObj = appConfigService.getWalletUIConfig("evm"); if (configObj && configObj.kitName) { logger3.info( "useUiKitConfig", `Loaded initial config from AppConfigService: kitName=${configObj.kitName}`, configObj.kitConfig ); return { kitName: configObj.kitName, kitConfig: { ...defaultConfig.kitConfig, ...configObj.kitConfig || {} } }; } logger3.debug( "useUiKitConfig", "No initial config found in AppConfigService, using module default." ); return { ...defaultConfig }; } function isConfigEnabled(key) { return Boolean(uiKitConfig.kitConfig?.[key]); } function useUiKitConfig() { return uiKitConfig; } // src/wallet/components/connect/ConnectorDialog.tsx import { jsx as jsx2, jsxs } from "react/jsx-runtime"; var ConnectorDialog = ({ open, onOpenChange }) => { const unavailableContent = /* @__PURE__ */ jsx2(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsx2(DialogContent, { className: "sm:max-w-[425px]", children: /* @__PURE__ */ jsxs(DialogHeader, { children: [ /* @__PURE__ */ jsx2(DialogTitle, { children: "Wallet Connection Unavailable" }), /* @__PURE__ */ jsx2(DialogDescription, { children: "The wallet connection system is not properly initialized." }) ] }) }) }); return /* @__PURE__ */ jsx2(SafeWagmiComponent, { fallback: unavailableContent, children: /* @__PURE__ */ jsx2(ConnectorDialogContent, { open, onOpenChange }) }); }; var ConnectorDialogContent = ({ open, onOpenChange }) => { const { connect: connect2, connectors, error: connectError, isConnecting, pendingConnector } = useDerivedConnectStatus(); const { isConnected } = useDerivedAccountStatus(); const [connectingId, setConnectingId] = useState2(null); const fullConfig = useUiKitConfig(); const showInjectedConnector = isConfigEnabled("showInjectedConnector"); useEffect2(() => { }, [fullConfig, showInjectedConnector, isConnecting, pendingConnector]); useEffect2(() => { if (isConnected && connectingId) { onOpenChange(false); setConnectingId(null); } }, [isConnected, connectingId, onOpenChange]); if (!connect2) { return /* @__PURE__ */ jsx2(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-[425px]", children: [ /* @__PURE__ */ jsx2(DialogHeader, { children: /* @__PURE__ */ jsx2(DialogTitle, { children: "Error" }) }), /* @__PURE__ */ jsx2("p", { children: "Wallet connection function is not available." }) ] }) }); } const handleConnectorSelect = (selectedConnector) => { setConnectingId(selectedConnector.id); connect2({ connector: selectedConnector }); }; const filteredConnectors = connectors.filter((connector) => { const isInjected = connector.id === "injected"; return !(isInjected && !showInjectedConnector); }); return /* @__PURE__ */ jsx2(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-[425px]", children: [ /* @__PURE__ */ jsxs(DialogHeader, { children: [ /* @__PURE__ */ jsx2(DialogTitle, { children: "Connect Wallet" }), /* @__PURE__ */ jsx2(DialogDescription, { children: "Select a wallet provider to connect with this application." }) ] }), /* @__PURE__ */ jsx2("div", { className: "grid gap-4 py-4", children: filteredConnectors.length === 0 ? /* @__PURE__ */ jsx2("p", { className: "text-center text-muted-foreground", children: "No wallet connectors available." }) : filteredConnectors.map((connector) => /* @__PURE__ */ jsxs( Button, { onClick: () => handleConnectorSelect(connector), disabled: isConnecting && connectingId === connector.id, variant: "outline", className: "flex justify-between items-center w-full py-6", children: [ /* @__PURE__ */ jsx2("span", { children: connector.name }), isConnecting && connectingId === connector.id && /* @__PURE__ */ jsx2("span", { className: "ml-2 text-xs", children: "Connecting..." }) ] }, connector.id )) }), connectError && /* @__PURE__ */ jsx2("p", { className: "text-sm text-red-500 mt-1", children: connectError.message || "Error connecting wallet" }) ] }) }); }; // src/wallet/components/connect/ConnectButton.tsx import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime"; var CustomConnectButton = ({ className, hideWhenConnected = true }) => { const [dialogOpen, setDialogOpen] = useState3(false); const unavailableButton = /* @__PURE__ */ jsx3("div", { className: cn("flex items-center", className), children: /* @__PURE__ */ jsxs2(Button2, { disabled: true, variant: "outline", size: "sm", className: "h-8 px-2 text-xs", children: [ /* @__PURE__ */ jsx3(Wallet, { className: "size-3.5 mr-1" }), "Wallet Unavailable" ] }) }); return /* @__PURE__ */ jsx3(SafeWagmiComponent, { fallback: unavailableButton, children: /* @__PURE__ */ jsx3( ConnectButtonContent, { className, dialogOpen, setDialogOpen, hideWhenConnected } ) }); }; var ConnectButtonContent = ({ className, dialogOpen, setDialogOpen, hideWhenConnected }) => { const { isConnected } = useDerivedAccountStatus2(); const { isConnecting: isHookConnecting, error: connectError } = useDerivedConnectStatus2(); const [isManuallyInitiated, setIsManuallyInitiated] = useState3(false); useEffect3(() => { if (isConnected && hideWhenConnected) { setDialogOpen(false); setIsManuallyInitiated(false); } }, [isConnected, hideWhenConnected, setDialogOpen]); useEffect3(() => { if (!dialogOpen) { setIsManuallyInitiated(false); } }, [dialogOpen]); useEffect3(() => { if (isHookConnecting) { setIsManuallyInitiated(false); } }, [isHookConnecting]); const handleConnectClick = () => { if (!isConnected) { setIsManuallyInitiated(true); setDialogOpen(true); } }; if (isConnected && hideWhenConnected) { return null; } const showButtonLoading = isHookConnecting || isManuallyInitiated; return /* @__PURE__ */ jsxs2("div", { className: cn("flex items-center", className), children: [ /* @__PURE__ */ jsxs2( Button2, { onClick: handleConnectClick, disabled: showButtonLoading || isConnected, variant: "outline", size: "sm", className: "h-8 px-2 text-xs", title: isConnected ? "Connected" : connectError?.message || "Connect Wallet", children: [ showButtonLoading ? /* @__PURE__ */ jsx3(Loader2, { className: "size-3.5 animate-spin mr-1" }) : /* @__PURE__ */ jsx3(Wallet, { className: "size-3.5 mr-1" }), showButtonLoading ? "Connecting..." : "Connect Wallet" ] } ), /* @__PURE__ */ jsx3( ConnectorDialog, { open: dialogOpen, onOpenChange: (open) => { setDialogOpen(open); if (!open) { setIsManuallyInitiated(false); } } } ) ] }); }; // src/wallet/components/account/AccountDisplay.tsx import { LogOut } from "lucide-react"; import { useDerivedAccountStatus as useDerivedAccountStatus3, useDerivedDisconnect } from "@openzeppelin/contracts-ui-builder-react-core"; import { Button as Button3 } from "@openzeppelin/contracts-ui-builder-ui"; import { cn as cn2, truncateMiddle } from "@openzeppelin/contracts-ui-builder-utils"; import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime"; var CustomAccountDisplay = ({ className }) => { return /* @__PURE__ */ jsx4(SafeWagmiComponent, { fallback: null, children: /* @__PURE__ */ jsx4(AccountDisplayContent, { className }) }); }; var AccountDisplayContent = ({ className }) => { const { isConnected, address, chainId } = useDerivedAccountStatus3(); const { disconnect: disconnect2 } = useDerivedDisconnect(); if (!isConnected || !address || !disconnect2) { return null; } return /* @__PURE__ */ jsxs3("div", { className: cn2("flex items-center gap-2", className), children: [ /* @__PURE__ */ jsxs3("div", { className: "flex flex-col", children: [ /* @__PURE__ */ jsx4("span", { className: "text-xs font-medium", children: truncateMiddle(address, 4, 4) }), /* @__PURE__ */ jsx4("span", { className: "text-[9px] text-muted-foreground -mt-0.5", children: chainId ? `Chain ID: ${chainId}` : "Chain ID: N/A" }) ] }), /* @__PURE__ */ jsx4( Button3, { onClick: () => disconnect2(), variant: "ghost", size: "icon", className: "size-6 p-0", title: "Disconnect wallet", children: /* @__PURE__ */ jsx4(LogOut, { className: "size-3.5" }) } ) ] }); }; // src/wallet/components/network/NetworkSwitcher.tsx import { Loader2 as Loader22 } from "lucide-react"; import { useDerivedAccountStatus as useDerivedAccountStatus4, useDerivedChainInfo, useDerivedSwitchChainStatus } from "@openzeppelin/contracts-ui-builder-react-core"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@openzeppelin/contracts-ui-builder-ui"; import { cn as cn3 } from "@openzeppelin/contracts-ui-builder-utils"; import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime"; var CustomNetworkSwitcher = ({ className }) => { return /* @__PURE__ */ jsx5(SafeWagmiComponent, { fallback: null, children: /* @__PURE__ */ jsx5(NetworkSwitcherContent, { className }) }); }; var NetworkSwitcherContent = ({ className }) => { const { isConnected } = useDerivedAccountStatus4(); const { currentChainId, availableChains: unknownChains } = useDerivedChainInfo(); const { switchChain: switchChain2, isSwitching: isPending, error } = useDerivedSwitchChainStatus(); const typedAvailableChains = unknownChains; if (!isConnected || !switchChain2 || typedAvailableChains.length === 0) { return null; } const handleNetworkChange = (chainId) => { if (chainId !== currentChainId) { switchChain2({ chainId }); } }; const currentChain = typedAvailableChains.find((chain) => chain.id === currentChainId); const currentChainName = currentChain?.name || "Network"; return /* @__PURE__ */ jsxs4("div", { className: cn3("flex items-center", className), children: [ /* @__PURE__ */ jsxs4( Select, { value: currentChainId?.toString() ?? "", onValueChange: (value) => handleNetworkChange(Number(value)), disabled: isPending || typedAvailableChains.length === 0, children: [ /* @__PURE__ */ jsx5(SelectTrigger, { className: "h-8 text-xs px-2 min-w-[90px] max-w-[120px]", children: /* @__PURE__ */ jsx5(SelectValue, { placeholder: "Network", children: currentChainName }) }), /* @__PURE__ */ jsx5( SelectContent, { position: "popper", sideOffset: 5, align: "start", className: "w-auto min-w-[160px] max-h-[300px]", children: typedAvailableChains.map((chain) => /* @__PURE__ */ jsx5(SelectItem, { value: chain.id.toString(), className: "text-xs py-1.5", children: chain.name }, chain.id)) } ) ] } ), isPending && /* @__PURE__ */ jsx5("span", { className: "text-xs text-muted-foreground ml-2", children: /* @__PURE__ */ jsx5(Loader22, { className: "h-3 w-3 animate-spin" }) }), error && /* @__PURE__ */ jsx5("span", { className: "text-xs text-red-500 ml-2", children: "!" }) ] }); }; // src/wallet/rainbowkit/types.ts function isRainbowKitCustomizations(obj) { return typeof obj === "object" && obj !== null && "connectButton" in obj; } function extractRainbowKitCustomizations(kitConfig) { if (!kitConfig || !kitConfig.customizations) { return void 0; } const customizations = kitConfig.customizations; return isRainbowKitCustomizations(customizations) ? customizations : void 0; } // src/wallet/rainbowkit/components.tsx import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime"; var MIN_COMPONENT_LOADING_DISPLAY_MS = 1e3; var RainbowKitConnectButton = (props) => { const [Component, setComponent] = useState4(null); const [error, setError] = useState4(null); const [isLoadingComponent, setIsLoadingComponent] = useState4(true); const [showComponentLoadingOverride, setShowComponentLoadingOverride] = useState4(false); const componentLoadingTimerRef = useRef(null); const [managerState, setManagerState] = useState4(evmUiKitManager.getState()); const isWagmiProviderReady = useContext2(WagmiProviderInitializedContext); useEffect4(() => { const unsubscribe = evmUiKitManager.subscribe(() => { setManagerState(evmUiKitManager.getState()); }); return unsubscribe; }, []); useEffect4(() => { let isMounted = true; setIsLoadingComponent(true); setShowComponentLoadingOverride(true); if (componentLoadingTimerRef.current) { clearTimeout(componentLoadingTimerRef.current); } componentLoadingTimerRef.current = setTimeout(() => { if (isMounted) { setShowComponentLoadingOverride(false); } componentLoadingTimerRef.current = null; }, MIN_COMPONENT_LOADING_DISPLAY_MS); const loadComponent = async () => { try { const rainbowKit = await import("@rainbow-me/rainbowkit"); if (isMounted) { setComponent(() => rainbowKit.ConnectButton); setIsLoadingComponent(false); } } catch (err) { if (isMounted) { setError(err instanceof Error ? err : new Error(String(err))); setIsLoadingComponent(false); logger4.error("RainbowKitConnectButton", "Failed to load RainbowKit ConnectButton:", err); } } }; loadComponent(); return () => { isMounted = false; if (componentLoadingTimerRef.current) { clearTimeout(componentLoadingTimerRef.current); } }; }, []); const renderLoadingPlaceholder = (message) => /* @__PURE__ */ jsxs5( Button4, { disabled: true, variant: "outline", size: "sm", className: cn4("h-8 px-2 text-xs", props.className), children: [ /* @__PURE__ */ jsx6(Loader23, { className: "h-3.5 w-3.5 animate-spin mr-1.5" }), message ] } ); if (error) { logger4.warn( "RainbowKitConnectButton", "Error loading RainbowKit ConnectButton. Displaying fallback CustomConnectButton." ); return /* @__PURE__ */ jsx6(CustomConnectButton, { ...props }); } if (isLoadingComponent || showComponentLoadingOverride) { return renderLoadingPlaceholder("Loading Wallet..."); } if (!isWagmiProviderReady) { return renderLoadingPlaceholder("Initializing Provider..."); } if (!Component) { logger4.warn("RainbowKitConnectButton", "Component is null after loading phase, falling back."); return /* @__PURE__ */ jsx6(CustomConnectButton, { ...props }); } const kitConfig = managerState.currentFullUiKitConfig?.kitConfig; const customizations = extractRainbowKitCustomizations(kitConfig); const connectButtonConfig = customizations?.connectButton; const finalProps = { ...connectButtonConfig, // Apply custom configuration from config ...props // Allow props to override configuration }; logger4.debug("RainbowKitConnectButton", "Rendering with configuration:", { configFromFile: connectButtonConfig, finalProps }); return /* @__PURE__ */ jsx6(Component, { ...finalProps }); }; // src/wallet/rainbowkit/utils.ts import { logger as logger5 } from "@openzeppelin/contracts-ui-builder-utils"; function validateRainbowKitConfig(kitConfig) { logger5.debug( "validateRainbowKitConfig", "Received kitConfig for validation:", JSON.stringify(kitConfig) ); if (!kitConfig) { logger5.warn("validateRainbowKitConfig", "Validation failed: No kitConfig provided."); return { isValid: false, error: "No kitConfig provided for RainbowKit" }; } const wagmiParamsFromKitConfig = kitConfig.wagmiParams; if (!wagmiParamsFromKitConfig || typeof wagmiParamsFromKitConfig !== "object" || wagmiParamsFromKitConfig === null) { logger5.warn( "validateRainbowKitConfig", "Validation failed: kitConfig.wagmiParams is missing or invalid.", { wagmiParamsFromKitConfig } ); return { isValid: false, error: "kitConfig.