UNPKG

@m3s/smart-contract

Version:

A modular toolkit for generating, compiling, deploying, and interacting with Ethereum-compatible smart contracts

1,236 lines (1,224 loc) 87.7 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); // packages/smart-contract/package.json var package_default = { name: "@m3s/smart-contract", version: "1.9.2", type: "module", description: "A modular toolkit for generating, compiling, deploying, and interacting with Ethereum-compatible smart contracts", license: "MIT", keywords: [ "smart-contract", "ethereum", "erc20", "erc721", "erc1155", "solidity", "blockchain", "web3", "openzeppelin" ], repository: { type: "git", url: "git@bitbucket.org:ctb-marisca/ms3-package.git", directory: "packages/smart-contract" }, main: "./dist/index.cjs.js", module: "./dist/index.esm.js", types: "./dist/index.d.ts", exports: { ".": { types: "./dist/index.d.ts", import: "./dist/index.esm.js", require: "./dist/index.cjs.js" }, "./package.json": "./package.json" }, scripts: { build: "tsc -b", test: "vitest run --sequence.sequential", "test:core": "vitest run 01_Core.test.ts 02_IBaseContractHandler.test.ts", "test:erc20": "vitest run 03_ERC20.test.ts", "test:erc721": "vitest run 04_ERC721.test.ts", "test:erc1155": "vitest run 05_ERC1155.test.ts" }, dependencies: { "@m3s/wallet": "^2.0.4", "@openzeppelin/contracts": "^5.2.0", "@openzeppelin/contracts-upgradeable": "^5.0.0", "@openzeppelin/wizard": "^0.5.3", "@openzeppelin/wizard-cairo": "^1.0.0", "@openzeppelin/wizard-stellar": "^0.1.1", "@openzeppelin/wizard-stylus": "^0.2.0-alpha.4", ethers: "^6.13.5", hardhat: "^2.22.19", joi: "^17.13.3", starknet: "^6.24.1" }, devDependencies: { "@m3s/common": "*" }, publishConfig: { access: "public", tag: "latest" }, files: [ "dist", "README.md" ] }; // packages/common/dist/errors/AdapterError.js var AdapterError = class extends Error { // Add this line constructor(message, options) { super(message); __publicField(this, "code"); __publicField(this, "cause"); __publicField(this, "methodName"); __publicField(this, "details"); this.name = this.constructor.name; this.code = options?.code; this.cause = options?.cause; this.methodName = options?.methodName; this.details = options?.details; if (typeof Error.captureStackTrace === "function") { Error.captureStackTrace(this, this.constructor); } } }; // packages/common/dist/errors/proxy.js function createErrorHandlingProxy(adapterInstance, errorMap = {}, defaultErrorCode, contextName = "UnknownAdapter") { return new Proxy(adapterInstance, { get(target, prop, receiver) { const originalValue = Reflect.get(target, prop, receiver); const methodName = String(prop); if (typeof originalValue === "function") { return async function(...args) { try { return await originalValue.apply(target, args); } catch (error) { const originalErrorMessage = error instanceof Error ? error.message : String(error); console.error(`[${contextName} Error] Method '${methodName}' failed: ${originalErrorMessage}`, error); if (error instanceof AdapterError) { throw error; } let mappedErrorCode = defaultErrorCode; for (const key in errorMap) { if (originalErrorMessage.includes(key)) { mappedErrorCode = errorMap[key]; break; } } throw new AdapterError(`${contextName} method '${methodName}' failed: ${originalErrorMessage}`, { cause: error, methodName, code: mappedErrorCode // Cast as string if WalletErrorCode is an enum }); } }; } return originalValue; } }); } // packages/common/dist/registry/registry.js function getPropertyByPath(obj, path3) { return path3.split(".").reduce((currentObject, key) => { return currentObject && typeof currentObject === "object" && Object.prototype.hasOwnProperty.call(currentObject, key) ? currentObject[key] : void 0; }, obj); } var UniversalRegistry = class { constructor() { __publicField(this, "modules", /* @__PURE__ */ new Map()); __publicField(this, "adapters", /* @__PURE__ */ new Map()); __publicField(this, "compatibilityMatrices", /* @__PURE__ */ new Map()); } /** * Get compatibility matrix for an adapter */ getCompatibilityMatrix(moduleName, name, version) { const moduleMatrices = this.compatibilityMatrices.get(moduleName); if (!moduleMatrices) return void 0; const key = `${name}@${version}`; return moduleMatrices.get(key); } /** * Get latest version of an adapter */ getLatestVersion(moduleName, name) { const latest = this.getLatestAdapter(moduleName, name); return latest?.version; } /** * Register a compatibility matrix for an adapter */ registerCompatibilityMatrix(moduleName, matrix) { if (!this.compatibilityMatrices.has(moduleName)) { this.compatibilityMatrices.set(moduleName, /* @__PURE__ */ new Map()); } const moduleMatrices = this.compatibilityMatrices.get(moduleName); const key = `${matrix.adapterName}@${matrix.version}`; moduleMatrices.set(key, matrix); } /** * Check compatibility between adapter versions */ checkAdapterCompatibility(moduleName, name, versions) { const report = { compatible: true, conflicts: [], recommendations: [], supportedVersions: [] }; const moduleAdapters = this.adapters.get(moduleName); if (!moduleAdapters) { report.compatible = false; report.conflicts.push({ type: "version", severity: "error", description: `Module '${moduleName}' not found`, affectedVersions: versions }); return report; } for (const version of versions) { const adapter = this.getAdapter(moduleName, name, version); if (!adapter) { report.compatible = false; report.conflicts.push({ type: "version", severity: "error", description: `Adapter '${name}' version '${version}' not found`, affectedVersions: [version] }); continue; } report.supportedVersions.push(version); const matrix = this.getCompatibilityMatrix(moduleName, name, version); if (matrix) { for (const otherVersion of versions) { if (version !== otherVersion) { const breakingChange = matrix.breakingChanges.find((bc) => bc.fromVersion === otherVersion || bc.toVersion === otherVersion); if (breakingChange) { report.conflicts.push({ type: "breaking-change", severity: "warning", description: `Breaking changes between ${breakingChange.fromVersion} and ${breakingChange.toVersion}: ${breakingChange.changes.join(", ")}`, affectedVersions: [breakingChange.fromVersion, breakingChange.toVersion], suggestedAction: breakingChange.migrationPath }); } } } } } if (report.conflicts.length === 0) { report.recommendations.push("All specified versions are compatible"); } else { const latestVersion = this.getLatestVersion(moduleName, name); if (latestVersion) { report.recommendations.push(`Consider using latest version: ${latestVersion}`); } } return report; } /** * Get adapters compatible with a specific adapter instance */ getCompatibleAdapters(currentAdapter, targetModuleName) { const compatibleAdapters = []; const modulesToCheck = targetModuleName ? [targetModuleName] : Array.from(this.adapters.keys()); for (const moduleName of modulesToCheck) { const moduleAdapters = this.adapters.get(moduleName); if (!moduleAdapters) continue; const matrix = this.getCompatibilityMatrix(currentAdapter.moduleName, currentAdapter.name, currentAdapter.version); for (const [, adapterMetadata2] of moduleAdapters) { if (moduleName === currentAdapter.moduleName && adapterMetadata2.name === currentAdapter.name && adapterMetadata2.version === currentAdapter.version) { continue; } let isCompatible = true; if (adapterMetadata2.environment && matrix) { const currentAdapterMeta = this.getAdapter(currentAdapter.moduleName, currentAdapter.name, currentAdapter.version); if (currentAdapterMeta?.environment) { const environmentOverlap = currentAdapterMeta.environment.supportedEnvironments.some((env) => adapterMetadata2.environment.supportedEnvironments.includes(env)); if (!environmentOverlap) { isCompatible = false; } } } if (matrix && isCompatible) { const crossModuleCompat = matrix.crossModuleCompatibility.find((cmc) => cmc.moduleName === moduleName); if (crossModuleCompat) { const compatibleAdapter = crossModuleCompat.compatibleAdapters.find((ca) => ca.name === adapterMetadata2.name && ca.versions.includes(adapterMetadata2.version)); isCompatible = !!compatibleAdapter; } } if (isCompatible) { compatibleAdapters.push(adapterMetadata2); } } } return compatibleAdapters; } /** * Batch register adapters with atomic rollback */ registerAdapters(adapters) { const originalState = new Map(this.adapters); try { for (const adapter of adapters) { this.registerAdapter(adapter.module, adapter); } } catch (error) { this.adapters = originalState; throw new Error(`Batch registration failed: ${error}. State rolled back.`); } } /** * Register a module in the registry */ registerModule(metadata) { this.modules.set(metadata.name, metadata); if (!this.adapters.has(metadata.name)) { this.adapters.set(metadata.name, /* @__PURE__ */ new Map()); } } /** * Register an adapter for a specific module */ registerAdapter(moduleName, metadata) { if (!this.modules.has(moduleName)) { const moduleMetadata = { name: moduleName, version: metadata.version // Use adapter's version as default module version }; this.registerModule(moduleMetadata); } const moduleAdapters = this.adapters.get(moduleName); if (!moduleAdapters) { throw new Error(`Module ${moduleName} not properly initialized in registry`); } const adapterKey = `${metadata.name}@${metadata.version}`; moduleAdapters.set(adapterKey, metadata); } /** * Get an adapter by module and adapter name */ getAdapter(moduleName, name, version) { const moduleAdapters = this.adapters.get(moduleName); if (!moduleAdapters) return void 0; const adapterKey = `${name}@${version}`; return moduleAdapters.get(adapterKey); } /** * Get the latest version of an adapter by name */ getLatestAdapter(moduleName, name) { const moduleAdapters = this.adapters.get(moduleName); if (!moduleAdapters) return void 0; const matchingAdapters = []; for (const [, metadata] of moduleAdapters.entries()) { if (metadata.name === name) { matchingAdapters.push(metadata); } } if (matchingAdapters.length === 0) return void 0; matchingAdapters.sort((a, b) => b.version.localeCompare(a.version)); return matchingAdapters[0]; } /** * Get all adapters for a module */ getModuleAdapters(moduleName) { const moduleAdapters = this.adapters.get(moduleName); if (!moduleAdapters) return []; return Array.from(moduleAdapters.values()); } /** * Get all available versions of a specific adapter */ getAdapterVersions(moduleName, name) { const moduleAdapters = this.adapters.get(moduleName); if (!moduleAdapters) return []; const versions = []; for (const [, metadata] of moduleAdapters.entries()) { if (metadata.name === name) { versions.push(metadata.version); } } return versions.sort((a, b) => b.localeCompare(a)); } /** * Get all modules */ getAllModules() { return Array.from(this.modules.values()); } /** * Check if an adapter supports a specific feature/method */ supportsFeature(moduleName, name, version, featureName) { const adapter = this.getAdapter(moduleName, name, version); if (!adapter) return false; return typeof adapter.adapterClass.prototype[featureName] === "function"; } /** * Find adapters that support a specific feature across all modules */ findAdaptersWithFeature(featureName) { const result = []; for (const [moduleName, moduleAdapters] of Array.from(this.adapters.entries())) { for (const [, metadata] of Array.from(moduleAdapters.entries())) { if (this.supportsFeature(moduleName, metadata.name, metadata.version, featureName)) { result.push(metadata); } } } return result; } /** * Get environment requirements for an adapter */ getEnvironmentRequirements(moduleName, name, version) { const adapter = this.getAdapter(moduleName, name, version); return adapter?.environment; } /** * Check if an adapter supports a specific environment */ supportsEnvironment(moduleName, name, version, environment) { const adapter = this.getAdapter(moduleName, name, version); if (!adapter || !adapter.environment) return true; return adapter.environment.supportedEnvironments.includes(environment); } /** * Get adapters that support a specific environment */ getAdaptersByEnvironment(moduleName, environment) { const moduleAdapters = this.adapters.get(moduleName); if (!moduleAdapters) return []; const result = []; for (const [, metadata] of moduleAdapters.entries()) { if (!metadata.environment || metadata.environment.supportedEnvironments.includes(environment)) { result.push(metadata); } } return result; } /** * ✅ NEW: Helper methods extracted from devtool.ts */ areEnvironmentsCompatible(adapter1, adapter2) { if (!adapter1.environment || !adapter2.environment) return true; return adapter1.environment.supportedEnvironments.some((env) => adapter2.environment.supportedEnvironments.includes(env)); } areInterfacesCompatible(adapter1, adapter2) { if (!adapter1.features || !adapter2.features) return true; const methods1 = adapter1.features.map((f) => f.name); const methods2 = adapter2.features.map((f) => f.name); const coreMethods = ["initialize", "isInitialized"]; return coreMethods.every((method) => methods1.includes(method) && methods2.includes(method)); } /** * ✅ NEW: Find all compatible adapters for a given adapter */ findCompatibleAdapters(moduleName, adapterName, version) { const sourceAdapter = this.getAdapter(moduleName, adapterName, version); if (!sourceAdapter) return []; const compatible = []; for (const module of this.getAllModules()) { if (module.name === moduleName) continue; const moduleAdapters = this.getModuleAdapters(module.name); for (const targetAdapter of moduleAdapters) { const report = this.getCompatibilityReport(moduleName, adapterName, version, module.name, targetAdapter.name, targetAdapter.version); if (report.compatible) { const envScore = this.areEnvironmentsCompatible(sourceAdapter, targetAdapter) ? 1 : 0; const interfaceScore = this.areInterfacesCompatible(sourceAdapter, targetAdapter) ? 1 : 0; const compatibility = (envScore + interfaceScore) / 2; compatible.push({ module: module.name, adapter: targetAdapter.name, version: targetAdapter.version, compatibility }); } } } return compatible.sort((a, b) => b.compatibility - a.compatibility); } /** * ✅ NEW: Get detailed compatibility report between adapters */ getCompatibilityReport(module1, adapter1, version1, module2, adapter2, version2) { const metadata1 = this.getAdapter(module1, adapter1, version1); const metadata2 = this.getAdapter(module2, adapter2, version2); if (!metadata1 || !metadata2) { return { compatible: false, conflicts: [{ type: "version", severity: "error", description: "One or both adapters not found", affectedVersions: [version1, version2] }], recommendations: ["Verify adapter names and versions"], supportedVersions: [] }; } const conflicts = []; let compatible = true; if (!this.areEnvironmentsCompatible(metadata1, metadata2)) { compatible = false; conflicts.push({ type: "environment", severity: "error", description: `Environment incompatibility: ${adapter1} requires ${metadata1.environment?.supportedEnvironments.join(", ")}, ${adapter2} requires ${metadata2.environment?.supportedEnvironments.join(", ")}`, affectedVersions: [version1, version2], suggestedAction: `Use ${adapter1} in ${metadata1.environment?.supportedEnvironments.join("/")} environment, or ${adapter2} in ${metadata2.environment?.supportedEnvironments.join("/")} environment` }); } if (!this.areInterfacesCompatible(metadata1, metadata2)) { compatible = false; conflicts.push({ type: "feature", severity: "error", description: `Interface incompatibility: Core methods missing or incompatible`, affectedVersions: [version1, version2], suggestedAction: "Verify both adapters implement required interface methods" }); } const recommendations = []; if (compatible) { recommendations.push(`\u2705 ${adapter1}@${version1} and ${adapter2}@${version2} are compatible`); if (metadata1.environment && metadata2.environment) { const commonEnvs = metadata1.environment.supportedEnvironments.filter((env) => metadata2.environment.supportedEnvironments.includes(env)); recommendations.push(`\u{1F4A1} Use in ${commonEnvs.join(" or ")} environment${commonEnvs.length > 1 ? "s" : ""}`); } } else { recommendations.push(`\u274C ${adapter1}@${version1} and ${adapter2}@${version2} are not compatible`); if (conflicts.some((c) => c.type === "environment")) { const allAdapters = this.getModuleAdapters(module1); for (const alt of allAdapters) { if (alt.name !== adapter1 && metadata2.environment && alt.environment?.supportedEnvironments.some((env) => metadata2.environment.supportedEnvironments.includes(env))) { recommendations.push(`\u{1F4A1} Try ${alt.name}@${alt.version} instead of ${adapter1} for ${metadata2.environment.supportedEnvironments.join("/")} compatibility`); } } } } return { compatible, conflicts, recommendations, supportedVersions: compatible ? [version1, version2] : [] }; } }; var registry = new UniversalRegistry(); // packages/common/dist/registry/compatibility.js var WALLET_COMPATIBILITY = { "ethers@1.0.0": { adapterName: "ethers", version: "1.0.0", compatibleVersions: ["1.0.0"], breakingChanges: [], crossModuleCompatibility: [ { moduleName: "smart-contract", compatibleAdapters: [ { name: "openZeppelin", versions: ["1.0.0"] } ] }, { moduleName: "crosschain", compatibleAdapters: [ { name: "lifi", versions: ["1.0.0"] } ] } ] }, "web3auth@1.0.0": { adapterName: "web3auth", version: "1.0.0", compatibleVersions: ["1.0.0"], breakingChanges: [], crossModuleCompatibility: [ { moduleName: "smart-contract", compatibleAdapters: [ { name: "openZeppelin", versions: ["1.0.0"] } ] } // ❌ NOTE: web3auth is BROWSER-only, so NO crosschain compatibility // crosschain adapters typically need server environment ] } }; var SMART_CONTRACT_COMPATIBILITY = { "openZeppelin@1.0.0": { adapterName: "openZeppelin", version: "1.0.0", compatibleVersions: ["1.0.0"], breakingChanges: [], crossModuleCompatibility: [ { moduleName: "wallet", compatibleAdapters: [ { name: "ethers", versions: ["1.0.0"] }, { name: "web3auth", versions: ["1.0.0"] } ] } ] } }; var CROSSCHAIN_COMPATIBILITY = { "lifi@1.0.0": { adapterName: "lifi", version: "1.0.0", compatibleVersions: ["1.0.0"], breakingChanges: [], crossModuleCompatibility: [ { moduleName: "wallet", compatibleAdapters: [ { name: "ethers", versions: ["1.0.0"] } // ❌ NOTE: NO web3auth - environment incompatibility ] } ] } }; function getStaticCompatibilityMatrix(moduleName, adapterName, version) { const key = `${adapterName}@${version}`; switch (moduleName) { case "wallet": return WALLET_COMPATIBILITY[key]; case "smart-contract": return SMART_CONTRACT_COMPATIBILITY[key]; case "crosschain": return CROSSCHAIN_COMPATIBILITY[key]; default: return void 0; } } // packages/common/dist/types/registry.js var Ms3Modules; (function(Ms3Modules2) { Ms3Modules2["wallet"] = "wallet"; Ms3Modules2["smartcontract"] = "smart-contract"; Ms3Modules2["crosschain"] = "crosschain"; })(Ms3Modules || (Ms3Modules = {})); var RuntimeEnvironment; (function(RuntimeEnvironment2) { RuntimeEnvironment2["BROWSER"] = "browser"; RuntimeEnvironment2["SERVER"] = "server"; })(RuntimeEnvironment || (RuntimeEnvironment = {})); // packages/common/dist/types/error.js var WalletErrorCode; (function(WalletErrorCode2) { WalletErrorCode2["Unknown"] = "UNKNOWN"; WalletErrorCode2["environment"] = "ENVIRONMENT_MISMATCH"; WalletErrorCode2["NotImplemented"] = "NOT_IMPLEMENTED"; WalletErrorCode2["AdapterNotInitialized"] = "ADAPTER_NOT_INITIALIZED"; WalletErrorCode2["WalletNotConnected"] = "WALLET_NOT_CONNECTED"; WalletErrorCode2["ProviderNotFound"] = "PROVIDER_NOT_FOUND"; WalletErrorCode2["NetworkError"] = "NETWORK_ERROR"; WalletErrorCode2["UserRejected"] = "USER_REJECTED"; WalletErrorCode2["InvalidInput"] = "INVALID_INPUT"; WalletErrorCode2["TransactionFailed"] = "TRANSACTION_FAILED"; WalletErrorCode2["SignatureFailed"] = "SIGNATURE_FAILED"; WalletErrorCode2["MethodNotSupported"] = "METHOD_NOT_SUPPORTED"; WalletErrorCode2["FeatureNotSupported"] = "FEATURE_NOT_SUPPORTED"; WalletErrorCode2["AdapterNotFound"] = "ADAPTER_NOT_FOUND"; WalletErrorCode2["MissingConfig"] = "MISSING_CONFIG"; WalletErrorCode2["InitializationFailed"] = "INITIALIZATION_FAILED"; WalletErrorCode2["ConnectionFailed"] = "CONNECTION_FAILED"; WalletErrorCode2["AccountUnavailable"] = "ACCOUNT_UNAVAILABLE"; WalletErrorCode2["GasEstimationFailed"] = "GAS_ESTIMATION_FAILED"; WalletErrorCode2["InsufficientFunds"] = "INSUFFICIENT_FUNDS"; WalletErrorCode2["TransactionReceiptFailed"] = "TRANSACTION_RECEIPT_FAILED"; WalletErrorCode2["TokenBalanceFailed"] = "TOKEN_BALANCE_FAILED"; WalletErrorCode2["SigningFailed"] = "INVALID_SIGNATURE"; WalletErrorCode2["ContractCallFailed"] = "CONTRACT CALL FAILED"; })(WalletErrorCode || (WalletErrorCode = {})); var CrossChainErrorCode; (function(CrossChainErrorCode2) { CrossChainErrorCode2["Unknown"] = "CC_UNKNOWN"; CrossChainErrorCode2["AdapterNotInitialized"] = "CC_ADAPTER_NOT_INITIALIZED"; CrossChainErrorCode2["NetworkError"] = "CC_NETWORK_ERROR"; CrossChainErrorCode2["InvalidInput"] = "CC_INVALID_INPUT"; CrossChainErrorCode2["QuoteFailed"] = "CC_QUOTE_FAILED"; CrossChainErrorCode2["ExecutionFailed"] = "CC_EXECUTION_FAILED"; CrossChainErrorCode2["ProviderSetFailed"] = "CC_PROVIDER_SETUP_FAILED"; CrossChainErrorCode2["StatusCheckFailed"] = "CC_STATUS_CHECK_FAILED"; CrossChainErrorCode2["UnsupportedChain"] = "CC_UNSUPPORTED_CHAIN"; CrossChainErrorCode2["UnsupportedToken"] = "CC_UNSUPPORTED_TOKEN"; CrossChainErrorCode2["OperationNotFound"] = "CC_OPERATION_NOT_FOUND"; })(CrossChainErrorCode || (CrossChainErrorCode = {})); var SmartContractErrorCode; (function(SmartContractErrorCode2) { SmartContractErrorCode2["Unknown"] = "SC_UNKNOWN"; SmartContractErrorCode2["AdapterNotInitialized"] = "SC_ADAPTER_NOT_INITIALIZED"; SmartContractErrorCode2["NetworkError"] = "SC_NETWORK_ERROR"; SmartContractErrorCode2["InvalidInput"] = "SC_INVALID_INPUT"; SmartContractErrorCode2["CompilationFailed"] = "SC_COMPILATION_FAILED"; SmartContractErrorCode2["DeploymentFailed"] = "SC_DEPLOYMENT_FAILED"; SmartContractErrorCode2["MethodCallFailed"] = "SC_METHOD_CALL_FAILED"; SmartContractErrorCode2["ReadCallFailed"] = "SC_READ_CALL_FAILED"; SmartContractErrorCode2["WriteCallFailed"] = "SC_WRITE_CALL_FAILED"; SmartContractErrorCode2["InvalidAbi"] = "SC_INVALID_ABI"; SmartContractErrorCode2["ContractNotFound"] = "SC_CONTRACT_NOT_FOUND"; SmartContractErrorCode2["WalletRequired"] = "SC_WALLET_REQUIRED"; })(SmartContractErrorCode || (SmartContractErrorCode = {})); // packages/common/dist/helpers/network.js import { JsonRpcProvider } from "ethers"; var _NetworkHelper = class _NetworkHelper { constructor() { __publicField(this, "networkCache"); __publicField(this, "isLoadingNetworks"); __publicField(this, "initializationPromise", null); this.networkCache = { // Default entries ensure basic functionality even if API fails ethereum: { chainId: "0x1", name: "Ethereum Mainnet", rpcUrls: ["https://eth.llamarpc.com", "https://ethereum-rpc.publicnode.com", "https://1rpc.io/eth", "https://cloudflare-eth.com"], blockExplorerUrl: "https://etherscan.io", ticker: "ETH", tickerName: "Ethereum", displayName: "Ethereum Mainnet" }, sepolia: { chainId: "0xaa36a7", name: "Sepolia Testnet", rpcUrls: ["https://rpc.sepolia.org", "https://ethereum-sepolia-rpc.publicnode.com", "https://endpoints.omniatech.io/v1/eth/sepolia/public", "https://eth-sepolia.public.blastapi.io"], blockExplorerUrl: "https://sepolia.etherscan.io", ticker: "ETH", tickerName: "Ethereum", displayName: "Sepolia Testnet" }, polygon: { chainId: "0x89", name: "Polygon Mainnet", rpcUrls: ["https://polygon-rpc.com", "https://polygon.llamarpc.com", "https://polygon.drpc.org"], blockExplorerUrl: "https://polygonscan.com", ticker: "MATIC", tickerName: "Polygon", displayName: "Polygon Mainnet" }, arbitrum: { chainId: "0xa4b1", name: "Arbitrum One", rpcUrls: ["https://arb1.arbitrum.io/rpc", "https://arbitrum.llamarpc.com", "https://arbitrum-one.public.blastapi.io"], blockExplorerUrl: "https://arbiscan.io", ticker: "ETH", tickerName: "Ethereum", displayName: "Arbitrum One" }, optimism: { chainId: "0xa", name: "Optimism", rpcUrls: ["https://mainnet.optimism.io", "https://optimism.llamarpc.com", "https://optimism.publicnode.com"], blockExplorerUrl: "https://optimistic.etherscan.io", ticker: "ETH", tickerName: "Ethereum", displayName: "Optimism" } }; this.isLoadingNetworks = false; this.initializationPromise = this.loadAllNetworks().then(() => { }).catch((err) => { console.error("[NetworkHelper] Background network loading failed:", err.message); }); } async loadAllNetworks() { if (this.isLoadingNetworks) { if (this.initializationPromise) await this.initializationPromise; return this.networkCache; } this.isLoadingNetworks = true; try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 15e3); const response = await fetch("https://chainlist.org/rpcs.json", { signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { throw new Error(`Failed to fetch networks: ${response.status} ${response.statusText}`); } const networks = await response.json(); for (const network of networks) { if (!network.chainId) continue; const filteredRpcUrls = (network.rpc || []).map((rpc) => typeof rpc === "string" ? rpc : rpc?.url).filter((url) => !!url && (url.startsWith("http://") || url.startsWith("https://")) && !url.includes("/demo") && !/\{\$?.*\}/.test(url) && !/api_key|api-key|apikey/i.test(url) && !url.includes("wss://")); if (filteredRpcUrls.length === 0) continue; const chainIdNum = network.chainId; const chainIdHex = `0x${chainIdNum.toString(16)}`; const chainIdDecString = chainIdNum.toString(); const formattedNetwork = { chainId: chainIdHex, name: network.name, displayName: network.name, rpcUrls: filteredRpcUrls, // rpcUrls[0] is the primary ticker: network.nativeCurrency?.symbol || "", tickerName: network.nativeCurrency?.name || "", blockExplorerUrl: network.explorers?.[0]?.url || "", shortName: network.shortName, chainSlug: network.chainSlug }; const normalizedName = network.name.toLowerCase().replace(/\s+/g, ""); this.networkCache[normalizedName] = formattedNetwork; this.networkCache[chainIdDecString] = formattedNetwork; this.networkCache[chainIdHex.toLowerCase()] = formattedNetwork; if (network.shortName) this.networkCache[network.shortName.toLowerCase()] = formattedNetwork; if (network.chainSlug) this.networkCache[network.chainSlug] = formattedNetwork; } } catch (error) { console.warn("[NetworkHelper] Failed to load networks from ChainList API, using defaults:", error.message); } finally { this.isLoadingNetworks = false; } return this.networkCache; } /** * Filters a collection of NetworkConfig | null objects, returning only valid NetworkConfig objects. * A config is considered valid if it's not null, has a chainId, and has at least one RPC URL. * @param configs - A Record<string, NetworkConfig | null> or Array<NetworkConfig | null>. * @returns A collection of the same type (Record or Array) containing only valid NetworkConfig objects. */ static filterValidConfigs(configs) { const isValid = (config) => !!config && !!config.chainId && !!config.rpcUrls && config.rpcUrls.length > 0; if (Array.isArray(configs)) { return configs.filter(isValid); } else { const result = {}; for (const key in configs) { if (Object.prototype.hasOwnProperty.call(configs, key)) { const config = configs[key]; if (isValid(config)) { result[key] = config; } } } return result; } } /** * Asserts that a given NetworkConfig is valid. * Throws an error if the config is null, or missing chainId, or rpcUrls. * @param config - The NetworkConfig | null to validate. * @param context - Optional context string to include in the error message. * @returns The validated NetworkConfig (guaranteed to be non-null and valid). * @throws Error if the config is invalid. */ static assertConfigIsValid(config, context = "NetworkConfiguration") { if (!config) { throw new Error(`[NetworkHelper] ${context}: Configuration is null or undefined.`); } if (!config.chainId) { throw new Error(`[NetworkHelper] ${context} (Name: ${config.name || "N/A"}): Missing chainId.`); } if (!config.rpcUrls || config.rpcUrls.length === 0) { throw new Error(`[NetworkHelper] ${context} (Name: ${config.name || "N/A"}, ChainID: ${config.chainId}): Missing or empty rpcUrls.`); } return config; } static getInstance() { if (!_NetworkHelper.instance) { _NetworkHelper.instance = new _NetworkHelper(); } return _NetworkHelper.instance; } /** * Ensures that the initial loading of networks has attempted to complete. */ async ensureInitialized() { if (this.initializationPromise) { await this.initializationPromise; } } async testRpcConnection(url, expectedChainId, timeoutMs = 5e3) { try { const provider = new JsonRpcProvider(url, void 0, { staticNetwork: true }); const networkPromise = provider.getNetwork(); const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error(`Timeout connecting to ${url}`)), timeoutMs)); const network = await Promise.race([networkPromise, timeoutPromise]); await provider.destroy(); const networkChainIdStr = network.chainId.toString(); const expectedChainIdStr = expectedChainId.toString(); const expectedHex = expectedChainIdStr.startsWith("0x") ? expectedChainIdStr.toLowerCase() : `0x${parseInt(expectedChainIdStr, 10).toString(16).toLowerCase()}`; const expectedDec = expectedChainIdStr.startsWith("0x") ? parseInt(expectedChainIdStr, 16).toString() : expectedChainIdStr; if (networkChainIdStr !== expectedHex && networkChainIdStr !== expectedDec) { return false; } return true; } catch (error) { return false; } } async fetchChainListNetwork(networkIdentifier) { await this.ensureInitialized(); const identifierStr = String(networkIdentifier).toLowerCase(); let cachedConfig = this.networkCache[identifierStr] || this.networkCache[String(networkIdentifier)]; if (cachedConfig) { return cachedConfig; } if (identifierStr.includes("arbi")) { cachedConfig = this.networkCache.arbitrum || this.networkCache.arbitrumone; if (cachedConfig) return cachedConfig; } if (identifierStr.includes("opti")) { cachedConfig = this.networkCache.optimism; if (cachedConfig) return cachedConfig; } if (identifierStr === "sepolia" || identifierStr === "11155111" || identifierStr === "0xaa36a7") { return this.networkCache.sepolia || null; } return null; } async getNetworkConfig(networkIdentifier, preferredRpcUrls = [], useOnlyPreferredRpc = false) { await this.ensureInitialized(); const baseConfig = await this.fetchChainListNetwork(String(networkIdentifier)); if (!baseConfig || !baseConfig.chainId || !baseConfig.rpcUrls || baseConfig.rpcUrls.length === 0) { return null; } const uniquePreferred = [...new Set(preferredRpcUrls.filter((url) => url))]; let urlsToTest = []; let foundInPreferred = false; if (uniquePreferred.length > 0) { urlsToTest.push(...uniquePreferred); } if (!useOnlyPreferredRpc) { const baseRpcUrlsFromCache = (Array.isArray(baseConfig.rpcUrls) ? baseConfig.rpcUrls : []).filter((url) => !uniquePreferred.includes(url)); urlsToTest.push(...baseRpcUrlsFromCache); } else if (uniquePreferred.length === 0) { console.warn(`[NetworkHelper] getNetworkConfig called with useOnlyPreferredRpc=true but no preferredRpcUrls were provided for ${networkIdentifier}.`); return null; } if (urlsToTest.length === 0) { return null; } let workingUrl = null; for (const url of urlsToTest) { if (await this.testRpcConnection(url, baseConfig.chainId)) { workingUrl = url; if (uniquePreferred.includes(url)) { foundInPreferred = true; } break; } } if (!workingUrl) { return null; } if (!useOnlyPreferredRpc && uniquePreferred.length > 0 && !foundInPreferred) { console.warn(`[NetworkHelper] None of the preferred RPCs worked for ${baseConfig.name}. Using a public RPC: ${workingUrl}. For critical operations, ensure your preferred RPCs are operational.`); } const orderedRpcUrls = [workingUrl, ...urlsToTest.filter((url) => url !== workingUrl)]; return { chainId: baseConfig.chainId, name: baseConfig.name, displayName: baseConfig.displayName || baseConfig.name, rpcUrls: orderedRpcUrls, blockExplorerUrl: baseConfig.blockExplorerUrl, ticker: baseConfig.ticker, tickerName: baseConfig.tickerName, shortName: baseConfig.shortName, chainSlug: baseConfig.chainSlug }; } /** * Try each URL until one returns a matching chainId within timeout. * @returns the first working RPC, or null if none worked. */ async findFirstWorkingRpc(urls, expectedChainId, timeoutMs = 3e3) { for (const url of urls) { try { const ok = await this.testRpcConnection(url, expectedChainId, timeoutMs); if (ok) return url; } catch { } } return null; } }; __publicField(_NetworkHelper, "instance"); var NetworkHelper = _NetworkHelper; // packages/common/dist/helpers/keys.js import { Wallet as EthersWallet, HDNodeWallet, Mnemonic, Wallet, isHexString } from "ethers"; var PrivateKeyHelper = class { /** * Generates a new random EVM-compatible private key. * @returns A string representing the private key (hexadecimal, 0x-prefixed). */ generatePrivateKey() { try { const wallet = EthersWallet.createRandom(); return wallet.privateKey; } catch (error) { throw new Error(`[PrivateKeyHelper.generatePrivateKey] Failed: ${error.message}`); } } /** * Encrypts an EVM private key into a JSON keystore (EIP-2335 format) using a password. * @param privateKey The EVM private key string (hexadecimal, 0x-prefixed). * @param password The password for encryption. * @returns A promise resolving to the JSON keystore string. * @throws Error if the private key is invalid or encryption fails. */ async encryptPrivateKey(privateKey, password) { if (!this.isValidEvmPrivateKey(privateKey)) { throw new Error("[PrivateKeyHelper.encryptPrivateKey] Invalid private key format."); } try { const wallet = new EthersWallet(privateKey); const jsonKeystore = await wallet.encrypt(password); return jsonKeystore; } catch (error) { throw new Error(`[PrivateKeyHelper.encryptPrivateKey] Encryption failed: ${error.message}`); } } /** * Decrypts an EVM JSON keystore using a password. * @param encryptedJsonKeystore The JSON keystore string. * @param password The password for decryption. * @returns A promise resolving to the decrypted EVM private key string. * @throws Error if decryption fails (e.g., invalid keystore, incorrect password). */ async decryptPrivateKey(encryptedJsonKeystore, password) { try { const wallet = await EthersWallet.fromEncryptedJson(encryptedJsonKeystore, password); return wallet.privateKey; } catch (error) { throw new Error(`[PrivateKeyHelper.decryptPrivateKey] Decryption failed: ${error.message}`); } } /** * Derives the public Ethereum address from an EVM private key. * @param privateKey The EVM private key string (hexadecimal, 0x-prefixed). * @returns The corresponding public address string. * @throws Error if the private key is invalid. */ getAddressFromPrivateKey(privateKey) { if (!this.isValidEvmPrivateKey(privateKey)) { throw new Error("[PrivateKeyHelper.getAddressFromPrivateKey] Invalid private key format."); } try { const wallet = new EthersWallet(privateKey); return wallet.address; } catch (error) { throw new Error(`[PrivateKeyHelper.getAddressFromPrivateKey] Failed to derive address: ${error.message}`); } } /** * Generates a new random BIP39 mnemonic phrase. * Uses ethers.Wallet.createRandom() for robust generation. * @returns A randomly generated mnemonic phrase (typically 12 words). * @throws Error if mnemonic generation fails. */ generateMnemonic() { try { const randomWallet = Wallet.createRandom(); if (!randomWallet.mnemonic || !randomWallet.mnemonic.phrase) { throw new Error("Failed to generate mnemonic phrase from random wallet."); } return randomWallet.mnemonic.phrase; } catch (error) { const wrappedError = new Error(`[PrivateKeyHelper.generateMnemonic] Failed during mnemonic generation: ${error.message}`); if (error.stack) { wrappedError.stack = error.stack; } wrappedError.cause = error; throw wrappedError; } } /** * Derives an EVM private key from a mnemonic phrase and an optional HD path. * @param mnemonic The BIP-39 mnemonic phrase. * @param path The HD path (e.g., "m/44'/60'/0'/0/0"). Defaults to the standard Ethereum path. * @returns The derived private key string. * @throws Error if the mnemonic is invalid or derivation fails. */ getPrivateKeyFromMnemonic(mnemonic, path3) { const hdPath = path3 || "m/44'/60'/0'/0/0"; try { if (!Mnemonic.isValidMnemonic(mnemonic)) { throw new Error("Invalid mnemonic phrase provided."); } const mnemonicInstance = Mnemonic.fromPhrase(mnemonic); const hdNode = HDNodeWallet.fromMnemonic(mnemonicInstance, hdPath); return hdNode.privateKey; } catch (error) { throw new Error(`[PrivateKeyHelper.getPrivateKeyFromMnemonic] Failed: ${error.message}`); } } /** * Validates if the given string is a plausible EVM private key format. * (Basic check for 0x prefix and 64 hex characters). * @param privateKey The string to validate. * @returns True if it matches the basic format, false otherwise. */ isValidEvmPrivateKey(privateKey) { return typeof privateKey === "string" && isHexString(privateKey, 32); } }; // packages/common/dist/helpers/validator.js function validateAdapterParameters(args) { const { moduleName, name, version, params, adapterInfo, registry: registry2, factoryMethodName } = args; const { neededFeature } = params; if (neededFeature && typeof neededFeature === "string") { if (!registry2.supportsFeature(moduleName, name, version, neededFeature)) { throw new AdapterError(`Feature '${neededFeature}' is not supported by adapter '${name}' for module '${moduleName}'.`, { methodName: factoryMethodName, code: "FEATURE_NOT_SUPPORTED", details: { feature: neededFeature } }); } } else if (neededFeature && !Array.isArray(neededFeature) && typeof neededFeature !== "string") { console.warn(`[validateAdapterParameters] 'neededFeature' for ${name} is of an unexpected type: ${typeof neededFeature}. It should typically be a string.`); } if (adapterInfo.requirements && adapterInfo.requirements.length > 0) { for (const req of adapterInfo.requirements) { const value = getPropertyByPath(params, req.path); if (value === void 0 && !req.allowUndefined) { const errorMessage = req.message || `Required option '${req.path}' is missing for adapter '${name}'.`; throw new AdapterError(errorMessage, { methodName: factoryMethodName, code: "MISSING_ADAPTER_REQUIREMENT", details: { path: req.path, message: req.message } }); } if (req.type && value !== void 0) { const valueType = Array.isArray(value) ? "array" : typeof value; if (valueType !== req.type) { const errorMessage = req.message || `Required option '${req.path}' for adapter '${name}' must be of type '${req.type}', but received '${valueType}'.`; throw new AdapterError(errorMessage, { methodName: factoryMethodName, code: "INVALID_ADAPTER_REQUIREMENT_TYPE", details: { path: req.path, message: req.message, expectedType: req.type, actualType: valueType } }); } } } } } // packages/common/dist/helpers/environment.js function detectRuntimeEnvironment() { const result = []; if (typeof process !== "undefined" && process.versions && process.versions.node) { result.push(RuntimeEnvironment.SERVER); } if (typeof window !== "undefined" && typeof document !== "undefined") { result.push(RuntimeEnvironment.BROWSER); } return result; } function validateEnvironment(adapterName, requirements) { const currentEnvs = detectRuntimeEnvironment(); const isSupported = currentEnvs.some((env) => requirements.supportedEnvironments.includes(env)); if (!isSupported) { const supportedList = requirements.supportedEnvironments.join(", "); const detectedList = currentEnvs.join(", "); let errorMessage = `Adapter '${adapterName}' requires ${supportedList} environment but detected ${detectedList}.`; if (requirements.limitations) { errorMessage += "\n" + requirements.limitations.join("\n"); } throw new AdapterError(errorMessage, { code: WalletErrorCode.environment, methodName: "validateEnvironment", details: { adapterName, currentEnvironment: currentEnvs, // ✅ Now array supportedEnvironments: requirements.supportedEnvironments, limitations: requirements.limitations } }); } if (requirements.securityNotes && requirements.securityNotes.length > 0) { requirements.securityNotes.forEach((note) => { console.warn(`[${adapterName}] Security Note: ${note}`); }); } } // packages/common/dist/helpers/devtool.js function analyzeJoiSchema(schema, basePath) { console.log(`\u{1F52C} [analyzeJoiSchema] Analyzing schema at path: ${basePath}`); const requirements = []; try { const description = schema.describe(); console.log(`\u{1F4CB} [analyzeJoiSchema] Schema description type:`, description.type); console.log(`\u{1F4CB} [analyzeJoiSchema] Schema keys:`, description.keys ? Object.keys(description.keys) : "NO KEYS"); if (description.type === "object" && description.keys) { console.log(`\u2705 [analyzeJoiSchema] Processing object schema with ${Object.keys(description.keys).length} keys`); for (const [key, fieldDesc] of Object.entries(description.keys)) { console.log(`\u{1F511} [analyzeJoiSchema] Processing field: ${key}`); console.log(`\u{1F4DD} [analyzeJoiSchema] Field description:`, fieldDesc); const fieldSchema = fieldDesc; const fieldPath = `${basePath}.${key}`; const hasPresenceFlag = fieldSchema.flags?.presence; const isRequired = hasPresenceFlag === "required" || !hasPresenceFlag && !fieldSchema.flags?.optional; let fieldType = fieldSchema.type || "any"; if (fieldType === "alternatives" && fieldSchema.matches) { fieldType = fieldSchema.matches[0]?.schema?.type || "any"; } let message = fieldSchema.flags?.description || ""; if (!message) { const mandatory = isRequired ? "required" : "optional"; message = `${key} is ${mandatory} and must be of type: ${fieldType}`; } console.log(`\u{1F4CA} [analyzeJoiSchema] Field ${key}: type=${fieldType}, required=${isRequired}, message="${message}"`); requirements.push({ path: fieldPath, type: fieldType, allowUndefined: !isRequired, message }); if (fieldSchema.type === "object" && fieldSchema.keys) { console.log(`\u{1F504} [analyzeJoiSchema] Recursing into nested object: ${key}`); const nestedRequirements = analyzeJoiSchemaFromDescription(fieldSchema, fieldPath); requirements.push(...nestedRequirements); } } } else { console.warn(`\u26A0\uFE0F [analyzeJoiSchema] Expected object schema but got type: ${description.type}`); } } catch (error) { console.error(`\u274C [analyzeJoiSchema] Failed to analyze schema at ${basePath}:`, error); } console.log(`\u{1F4CA} [analyzeJoiSchema] Generated ${requirements.length} requirements for ${basePath}`); return requirements; } function analyzeJoiSchemaFromDescription(description, basePath) { const requirements = []; if (description.keys) { for (const [key, fieldDesc] of Object.entries(description.keys)) { const fieldSchema = fieldDesc; const fieldPath = `${basePath}.${key}`; const isRequired = fieldSchema.flags?.presence === "required" || !fieldSchema.flags?.presence && !fieldSchema.flags?.optional && !fieldSchema.flags?.default; let fieldType = fieldSchema.type || "any"; if (fieldType === "alternatives" && fieldSchema.matches) { fieldType = fieldSchema.matches[0]?.schema?.type || "any"; } let message = fieldSchema.flags?.description || ""; if (!message) { const mandatory = isRequired ? "required" : "optional"; message = `${key} is ${mandatory} and must be of type: ${fieldType}`; } requirements.push({ path: fieldPath, type: fieldType, allowUndefined: !isRequired, message }); if (fieldSchema.type === "object" && fieldSchema.keys) { const nestedRequirements = analyzeJoiSchemaFromDescription(fieldSchema, fieldPath); requirements.push(...nestedRequirements); } } } return requirements; } function generateFallbackRequirements(adapterName) { console.log(`[getRequirements] No requirements found for ${adapterName} interface - using fallback.`); console.warn(`[getRequirements] Using fallback requirements for ${adapterName}`); if (adapterName === "ethers") { return [ { path: "options.privateKey", type: "string", allowUndefined: true, message: "Private key for wallet (generates random if not provided)" }, { path: "options.provider", type: "object", allowUndefined: true, message: "Optional provider configuration" } ]; } if (adapterName