@m3s/wallet
Version:
A flexible wallet interface supporting multiple blockchain wallet types, including EVM wallets and Web3Auth integration
1,249 lines (1,234 loc) • 123 kB
JavaScript
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);
// packages/shared/dist/errors/AdapterError.js
var AdapterError;
var init_AdapterError = __esm({
"packages/shared/dist/errors/AdapterError.js"() {
"use strict";
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;
console.error(`[AdapterError] ${message}`, {
code: this.code,
methodName: this.methodName,
details: this.details,
cause: this.cause,
stack: this.stack
});
if (typeof Error.captureStackTrace === "function") {
Error.captureStackTrace(this, this.constructor);
}
}
};
}
});
// packages/shared/dist/registry/capability.js
var Capability, MethodToCapabilityMap;
var init_capability = __esm({
"packages/shared/dist/registry/capability.js"() {
"use strict";
(function(Capability2) {
Capability2["CoreWallet"] = "ICoreWallet";
Capability2["EventEmitter"] = "IEventEmitter";
Capability2["MessageSigner"] = "IMessageSigner";
Capability2["TransactionHandler"] = "ITransactionHandler";
Capability2["TypedDataSigner"] = "ITypedDataSigner";
Capability2["GasEstimation"] = "IGasEstimation";
Capability2["TokenOperations"] = "ITokenOperations";
Capability2["RPCHandler"] = "IRPCHandler";
Capability2["TransactionStatus"] = "ITransactionStatus";
Capability2["ContractGenerator"] = "IContractGenerator";
Capability2["ContractCompiler"] = "IContractCompiler";
Capability2["QuoteProvider"] = "IQuoteProvider";
Capability2["OperationHandler"] = "IOperationHandler";
Capability2["ChainDiscovery"] = "IChainDiscovery";
Capability2["GasEstimator"] = "IGasEstimator";
Capability2["OperationMaintenance"] = "IOperationMaintenance";
Capability2["AdapterIdentity"] = "IAdapterIdentity";
Capability2["AdapterLifecycle"] = "IAdapterLifecycle";
})(Capability || (Capability = {}));
MethodToCapabilityMap = {
// --- ICoreWallet ---
"getAccounts": Capability.CoreWallet,
"getBalance": Capability.CoreWallet,
"getNetwork": Capability.CoreWallet,
"setProvider": Capability.CoreWallet,
"disconnect": Capability.CoreWallet,
"isConnected": Capability.CoreWallet,
// --- ITransactionHandler ---
"sendTransaction": Capability.TransactionHandler,
// --- IMessageSigner ---
"signMessage": Capability.MessageSigner,
// --- ITypedDataSigner ---
"signTypedData": Capability.TypedDataSigner,
// --- IGasEstimation ---
"estimateGas": Capability.GasEstimation,
// --- IEventEmitter ---
"on": Capability.EventEmitter,
"off": Capability.EventEmitter,
"emit": Capability.EventEmitter,
// --- ITokenOperations ---
"callContract": Capability.TokenOperations,
// --- IRPCHandler ---
"getChainId": Capability.RPCHandler,
"getGasPrice": Capability.RPCHandler,
"getBlockNumber": Capability.RPCHandler,
// --- ITransactionStatus ---
"getTransaction": Capability.TransactionStatus,
"waitForTransaction": Capability.TransactionStatus,
// --- IContractGenerator ---
"generate": Capability.ContractGenerator,
// --- IContractCompiler ---
"compile": Capability.ContractCompiler,
// --- IQuoteProvider ---
"getOperationQuote": Capability.QuoteProvider,
// --- IOperations ---
"executeOperation": Capability.OperationHandler,
"getOperationStatus": Capability.OperationHandler,
"cancelOperation": Capability.OperationHandler,
"resumeOperation": Capability.OperationHandler,
// --- IChainDiscovery ---
"getSupportedChains": Capability.ChainDiscovery,
"getSupportedTokens": Capability.ChainDiscovery,
// --- IGasEstimator ---
"getGasOnDestination": Capability.GasEstimator,
// --- IOperationMaintenance ---
"checkForTimedOutOperations": Capability.OperationMaintenance,
// --- IAdapterLifecycle ---
"initialize": Capability.AdapterLifecycle,
"isInitialized": Capability.AdapterLifecycle
};
}
});
// packages/shared/dist/errors/proxy.js
function createErrorHandlingProxy(adapterInstance, capabilities, 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") {
const requiredCapability = MethodToCapabilityMap[methodName];
if (requiredCapability && !capabilities.includes(requiredCapability)) {
return () => {
throw new AdapterError(`Method '${methodName}' is not supported by ${contextName}. It lacks the required capability: '${requiredCapability}'.`, { code: "METHOD_NOT_SUPPORTED", methodName });
};
}
const isAsync = originalValue.constructor.name === "AsyncFunction";
const handleError = (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
});
};
if (isAsync) {
return async function(...args) {
try {
return await originalValue.apply(target, args);
} catch (error) {
handleError(error);
}
};
} else {
return function(...args) {
try {
return originalValue.apply(target, args);
} catch (error) {
handleError(error);
}
};
}
}
return originalValue;
}
});
}
var init_proxy = __esm({
"packages/shared/dist/errors/proxy.js"() {
"use strict";
init_AdapterError();
init_capability();
}
});
// packages/shared/dist/errors/index.js
var init_errors = __esm({
"packages/shared/dist/errors/index.js"() {
"use strict";
init_AdapterError();
init_proxy();
}
});
// packages/shared/dist/types/error.js
var WalletErrorCode, CrossChainErrorCode, SmartContractErrorCode;
var init_error = __esm({
"packages/shared/dist/types/error.js"() {
"use strict";
(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 = {}));
(function(CrossChainErrorCode2) {
CrossChainErrorCode2["RpcValidationFailed"] = "RPC_VALIDATION_FAILED";
CrossChainErrorCode2["RpcReliabilityWarning"] = "RPC_RELIABILITY_WARNING";
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 = {}));
(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/shared/dist/types/registry.js
var Ms3Modules, RuntimeEnvironment;
var init_registry = __esm({
"packages/shared/dist/types/registry.js"() {
"use strict";
(function(Ms3Modules2) {
Ms3Modules2["wallet"] = "wallet";
Ms3Modules2["smartcontract"] = "smart-contract";
Ms3Modules2["crosschain"] = "crosschain";
})(Ms3Modules || (Ms3Modules = {}));
(function(RuntimeEnvironment2) {
RuntimeEnvironment2["BROWSER"] = "browser";
RuntimeEnvironment2["SERVER"] = "server";
})(RuntimeEnvironment || (RuntimeEnvironment = {}));
}
});
// packages/shared/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}`);
});
}
}
var init_environment = __esm({
"packages/shared/dist/helpers/environment.js"() {
"use strict";
init_AdapterError();
init_error();
init_registry();
}
});
// packages/shared/dist/registry/compatibility.js
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;
}
}
function checkCrossPackageCompatibility(sourceModule, sourceAdapter, sourceVersion, targetModule, targetAdapter, targetVersion) {
const sourceMatrix = getStaticCompatibilityMatrix(sourceModule, sourceAdapter, sourceVersion);
if (!sourceMatrix)
return false;
const targetModuleCompatRule = sourceMatrix.crossModuleCompatibility.find((cmc) => cmc.moduleName === targetModule);
if (!targetModuleCompatRule)
return false;
const targetAdapterInfo = registry.getAdapter(targetModule, targetAdapter, targetVersion);
if (!targetAdapterInfo?.capabilities)
return false;
const sourceAdapterInfo = registry.getAdapter(sourceModule, sourceAdapter, sourceVersion);
const currentEnvironments = detectRuntimeEnvironment();
if (sourceAdapterInfo?.environment && !sourceAdapterInfo.environment.supportedEnvironments.some((env) => currentEnvironments.includes(env))) {
return false;
}
if (targetAdapterInfo.environment && !targetAdapterInfo.environment.supportedEnvironments.some((env) => currentEnvironments.includes(env))) {
return false;
}
return targetModuleCompatRule.requiresCapabilities.every((requiredCap) => targetAdapterInfo.capabilities.includes(requiredCap));
}
var WALLET_COMPATIBILITY, SMART_CONTRACT_COMPATIBILITY, CROSSCHAIN_COMPATIBILITY;
var init_compatibility = __esm({
"packages/shared/dist/registry/compatibility.js"() {
"use strict";
init_environment();
init_capability();
init_registry2();
WALLET_COMPATIBILITY = {
"ethers@1.0.0": {
adapterName: "ethers",
version: "1.0.0",
compatibleVersions: ["1.0.0"],
breakingChanges: [],
crossModuleCompatibility: [
{
moduleName: "smart-contract",
// ✅ This wallet can work with any smart-contract adapter that can generate contracts.
requiresCapabilities: [Capability.ContractGenerator]
},
{
moduleName: "crosschain",
// ✅ This wallet can work with any crosschain adapter that can execute operations.
requiresCapabilities: [Capability.OperationHandler]
}
]
},
"web3auth@1.0.0": {
adapterName: "web3auth",
version: "1.0.0",
compatibleVersions: ["1.0.0"],
breakingChanges: [],
crossModuleCompatibility: [
{
moduleName: "smart-contract",
// ✅ This wallet can work with any smart-contract adapter that can generate contracts.
requiresCapabilities: [Capability.ContractGenerator]
},
{
moduleName: "crosschain",
// ✅ This wallet can work with any crosschain adapter that can execute operations.
requiresCapabilities: [Capability.OperationHandler]
}
]
}
};
SMART_CONTRACT_COMPATIBILITY = {
"openZeppelin@1.0.0": {
adapterName: "openZeppelin",
version: "1.0.0",
compatibleVersions: ["1.0.0"],
breakingChanges: [],
crossModuleCompatibility: [
{
moduleName: "wallet",
// ✅ This smart-contract adapter needs a wallet that can handle transactions.
requiresCapabilities: [Capability.TransactionHandler, Capability.RPCHandler]
}
]
}
};
CROSSCHAIN_COMPATIBILITY = {
"lifi@1.0.0": {
adapterName: "lifi",
version: "1.0.0",
compatibleVersions: ["1.0.0"],
breakingChanges: [],
crossModuleCompatibility: [
{
moduleName: "wallet",
// ✅ This crosschain adapter needs a wallet that can handle transactions and RPC calls.
requiresCapabilities: [Capability.TransactionHandler, Capability.RPCHandler]
}
]
}
};
}
});
// packages/shared/dist/registry/registry.js
function getPropertyByPath(obj, path) {
return path.split(".").reduce((currentObject, key) => {
return currentObject && typeof currentObject === "object" && Object.prototype.hasOwnProperty.call(currentObject, key) ? currentObject[key] : void 0;
}, obj);
}
var UniversalRegistry, registry;
var init_registry2 = __esm({
"packages/shared/dist/registry/registry.js"() {
"use strict";
init_compatibility();
UniversalRegistry = class {
constructor() {
__publicField(this, "modules", /* @__PURE__ */ new Map());
__publicField(this, "adapters", /* @__PURE__ */ new Map());
__publicField(this, "compatibilityMatrices", /* @__PURE__ */ new Map());
__publicField(this, "interfaceShapes", /* @__PURE__ */ new Map());
}
// ✅ ADD: The missing map
/**
* ✅ NEW: Register the shape of a convenience alias.
* This is called by modules (e.g., wallet/index.ts) to define their aliases.
* @param interfaceName The name of the alias (e.g., 'IEVMWallet').
* @param requiredCapabilities An array of base capability names it requires.
*/
registerInterfaceShape(interfaceName, requiredCapabilities) {
this.interfaceShapes.set(interfaceName, requiredCapabilities);
}
/**
* ✅ NEW: Get the shape of a convenience alias.
* This is called by the validator to verify an adapter meets an interface's requirements.
*/
getInterfaceShape(interfaceName) {
return this.interfaceShapes.get(interfaceName);
}
/**
* ✅ NEW: A modern replacement for findAdaptersWithFeature that uses our new architecture.
* Finds all adapters that have a specific capability.
*/
findAdaptersWithCapability(capability) {
const result = [];
for (const moduleAdapters of this.adapters.values()) {
for (const metadata of moduleAdapters.values()) {
if (metadata.capabilities?.includes(capability)) {
result.push(metadata);
}
}
}
return result;
}
/**
* 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) {
if (moduleName === currentAdapter.moduleName)
continue;
const moduleAdapters = this.adapters.get(moduleName);
if (!moduleAdapters)
continue;
for (const [, targetAdapterMetadata] of moduleAdapters) {
const isCompatible = checkCrossPackageCompatibility(currentAdapter.moduleName, currentAdapter.name, currentAdapter.version, targetAdapterMetadata.module, targetAdapterMetadata.name, targetAdapterMetadata.version);
if (isCompatible) {
compatibleAdapters.push(targetAdapterMetadata);
}
}
}
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());
}
/**
* 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;
}
};
registry = new UniversalRegistry();
}
});
// packages/shared/dist/registry/index.js
var init_registry3 = __esm({
"packages/shared/dist/registry/index.js"() {
"use strict";
init_registry2();
init_compatibility();
init_capability();
}
});
// packages/shared/dist/types/base.js
var init_base = __esm({
"packages/shared/dist/types/base.js"() {
"use strict";
}
});
// packages/shared/dist/types/index.js
var init_types = __esm({
"packages/shared/dist/types/index.js"() {
"use strict";
init_registry();
init_error();
init_base();
}
});
// packages/shared/dist/helpers/network.js
import { BrowserProvider, JsonRpcProvider } from "ethers";
var staticChainList, _NetworkHelper, NetworkHelper;
var init_network = __esm({
"packages/shared/dist/helpers/network.js"() {
"use strict";
init_AdapterError();
init_error();
staticChainList = [
{
name: "Ethereum Mainnet",
chainId: 1,
shortName: "eth",
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
rpc: [
"https://eth.llamarpc.com",
"https://ethereum-rpc.publicnode.com",
"https://1rpc.io/eth",
"https://cloudflare-eth.com"
],
blockExplorerUrl: "https://etherscan.io",
isTestnet: false,
isStatic: true
},
{
name: "Polygon Mainnet",
chainId: 137,
shortName: "matic",
nativeCurrency: { name: "MATIC", symbol: "MATIC", decimals: 18 },
rpc: [
"https://polygon-rpc.com",
"https://polygon.llamarpc.com",
"https://polygon.drpc.org"
],
blockExplorerUrl: "https://polygonscan.com",
isTestnet: false,
isStatic: true
},
{
name: "Optimism",
chainId: 10,
shortName: "oeth",
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
rpc: [
"https://mainnet.optimism.io",
"https://optimism.llamarpc.com",
"https://optimism.publicnode.com"
],
blockExplorerUrl: "https://optimistic.etherscan.io",
isTestnet: false,
isStatic: true
},
{
name: "Arbitrum One",
chainId: 42161,
shortName: "arb1",
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
rpc: [
"https://arb1.arbitrum.io/rpc",
"https://arbitrum.llamarpc.com",
"https://arbitrum-one.public.blastapi.io"
],
blockExplorerUrl: "https://arbiscan.io",
isTestnet: false,
isStatic: true
},
{
name: "Holesky",
chainId: 17e3,
shortName: "holesky",
nativeCurrency: { name: "Holesky Ether", symbol: "ETH", decimals: 18 },
rpc: ["https://ethereum-holesky.publicnode.com"],
blockExplorerUrl: "https://holesky.etherscan.io",
isTestnet: true,
isStatic: true
},
{
name: "Sepolia",
chainId: 11155111,
shortName: "sep",
nativeCurrency: { name: "Sepolia Ether", symbol: "ETH", decimals: 18 },
rpc: [
"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",
isTestnet: true,
isStatic: true
}
];
_NetworkHelper = class _NetworkHelper {
constructor() {
__publicField(this, "networkCache", {});
__publicField(this, "initializationPromise", null);
for (const chain of staticChainList) {
this.addChainToCache(chain);
}
}
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) {
this.initializationPromise = this.fetchAndMergeExternalChainList();
}
await this.initializationPromise;
}
async fetchAndMergeExternalChainList() {
try {
const response = await fetch("https://chainid.network/chains.json");
if (!response.ok) {
throw new Error(`Failed to fetch chain list: ${response.statusText}`);
}
const externalChains = await response.json();
for (const chain of externalChains) {
const normalizedId = _NetworkHelper.normalizeChainId(chain.chainId);
if (!this.networkCache[normalizedId] || !this.networkCache[normalizedId].isStatic) {
this.addChainToCache(chain, false);
}
}
} catch (error) {
console.warn("[NetworkHelper] Could not fetch external chain list. Using embedded static list only.", error);
}
}
addChainToCache(chain, isStatic = true) {
if (!chain || !chain.chainId)
return;
const normalizedId = _NetworkHelper.normalizeChainId(chain.chainId);
const rpcUrls = (chain.rpc || []).filter((url) => url && url.startsWith("http") && !url.includes("${"));
if (rpcUrls.length === 0 && !isStatic)
return;
const config = {
name: chain.name,
chainId: normalizedId,
shortName: chain.shortName,
nativeCurrency: chain.nativeCurrency,
rpcUrls,
blockExplorerUrl: chain.explorers?.[0]?.url || chain.blockExplorerUrl,
// isTestnet: chain.isTestnet ?? (chain.networkId !== 1), // Simple heuristic
isStatic,
displayName: chain.name,
decimals: chain.nativeCurrency?.decimals || 18,
ticker: chain.nativeCurrency?.symbol,
tickerName: chain.nativeCurrency?.name
};
this.networkCache[normalizedId] = config;
this.networkCache[chain.chainId.toString()] = config;
if (chain.shortName) {
this.networkCache[chain.shortName.toLowerCase()] = config;
}
if (chain.name) {
this.networkCache[chain.name.toLowerCase().replace(/\s+/g, "")] = config;
}
}
async getNetworkConfig(networkIdentifier, preferredRpcUrls = [], useOnlyPreferredRpc = false) {
await this.ensureInitialized();
const identifierStr = String(networkIdentifier).toLowerCase().replace(/\s+/g, "");
const baseConfig = this.networkCache[identifierStr];
if (!baseConfig || !baseConfig.chainId) {
return null;
}
const uniquePreferred = [...new Set(preferredRpcUrls.filter((url) => url))];
const baseRpcUrls = Array.isArray(baseConfig.rpcUrls) ? baseConfig.rpcUrls : [];
let urlsToTest = [];
if (useOnlyPreferredRpc) {
if (uniquePreferred.length === 0) {
console.warn(`[NetworkHelper] getNetworkConfig called with useOnlyPreferredRpc=true but no preferredRpcUrls were provided for ${networkIdentifier}.`);
return null;
}
urlsToTest = uniquePreferred;
} else {
urlsToTest = [...uniquePreferred, ...baseRpcUrls.filter((url) => !uniquePreferred.includes(url))];
}
if (urlsToTest.length === 0) {
return null;
}
const workingUrl = await this.findFirstWorkingRpc(urlsToTest, baseConfig.chainId);
if (!workingUrl) {
return null;
}
if (!useOnlyPreferredRpc && uniquePreferred.length > 0 && !uniquePreferred.includes(workingUrl)) {
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,
decimals: baseConfig.decimals,
blockExplorerUrl: baseConfig.blockExplorerUrl,
ticker: baseConfig.ticker,
tickerName: baseConfig.tickerName,
shortName: baseConfig.shortName
};
}
async testRpcConnection(url, expectedChainId, timeoutMs = 5e3) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), timeoutMs);
try {
const response = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ jsonrpc: "2.0", method: "eth_chainId", params: [], id: 1 }),
signal: controller.signal
});
if (!response.ok) {
return false;
}
const data = await response.json();
if (data.error) {
return false;
}
const receivedChainId = _NetworkHelper.normalizeChainId(data.result);
const expectedNormalized = _NetworkHelper.normalizeChainId(expectedChainId);
if (receivedChainId !== expectedNormalized) {
console.warn(`[testRpcConnection] Chain ID mismatch for ${url}: Got ${receivedChainId}, Expected ${expectedNormalized}`);
return false;
}
return true;
} catch (error) {
if (error.name === "AbortError") {
} else {
}
return false;
} finally {
clearTimeout(timeout);
}
}
async findFirstWorkingRpc(urls, expectedChainId, timeoutMs = 3e3) {
for (const url of urls) {
if (await this.testRpcConnection(url, expectedChainId, timeoutMs)) {
return url;
}
}
return null;
}
async getProvider(input, preferredRpcUrls = [], chainId) {
if (input instanceof JsonRpcProvider || input instanceof BrowserProvider) {
return input;
}
if (input && typeof input.request === "function") {
return new BrowserProvider(input, "any");
}
if (typeof input === "string") {
return new JsonRpcProvider(input);
}
if (input && typeof input === "object" && Array.isArray(input.rpcUrls) && input.rpcUrls.length > 0) {
return new JsonRpcProvider(input.rpcUrls[0]);
}
if (!chainId) {
throw new AdapterError("No chainId available to pick a public RPC. Supply your own in options.provider.", { code: WalletErrorCode.InvalidInput, methodName: "getProvider" });
}
const net = await this.getNetworkConfig(chainId, preferredRpcUrls);
if (!net || !net.rpcUrls || net.rpcUrls.length === 0) {
throw new AdapterError(`No RPC could be reached for chainId=${chainId}. Please supply at least one working URL in options.provider.rpcUrls.`, { code: WalletErrorCode.ConnectionFailed, methodName: "getProvider" });
}
return new JsonRpcProvider(net.rpcUrls[0]);
}
static normalizeChainId(chainId) {
if (typeof chainId === "number") {
return `0x${chainId.toString(16).toLowerCase()}`;
}
if (typeof chainId === "string") {
if (chainId.toLowerCase().startsWith("0x")) {
return chainId.toLowerCase();
}
const num = parseInt(chainId, 10);
if (!isNaN(num)) {
return `0x${num.toString(16).toLowerCase()}`;
}
}
throw new AdapterError(`Invalid chainId format: ${chainId}`, { code: WalletErrorCode.InvalidInput });
}
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 filterValidConfigs(configs) {
const isValid = (config) => !!config && !!config.chainId && Array.isArray(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;
}
}
validatePrivateRpcsForChains(chainIds, walletRpcs) {
const missingChains = [];
for (const chainId of chainIds) {
const normalizedId = _NetworkHelper.normalizeChainId(chainId);
const decimalId = parseInt(normalizedId, 16).toString();
const hasRpcs = walletRpcs[normalizedId]?.length > 0 || walletRpcs[decimalId]?.length > 0;
if (!hasRpcs) {
missingChains.push(decimalId);
}
}
return {
hasAllPrivateRpcs: missingChains.length === 0,
missingChains
};
}
};
__publicField(_NetworkHelper, "instance");
NetworkHelper = _NetworkHelper;
}
});
// packages/shared/dist/helpers/keys.js
import { Wallet as EthersWallet, HDNodeWallet, Mnemonic, Wallet, isHexString } from "ethers";
var PrivateKeyHelper;
var init_keys = __esm({
"packages/shared/dist/helpers/keys.js"() {
"use strict";
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, path) {
const hdPath = path || "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/shared/dist/helpers/validator.js
function validateAdapterParameters(args) {
const { name, version, params, adapterInfo, registry: registry2, factoryMethodName } = args;
const { expectedInterface } = params;
console.log("Validator - arguments, ", args);
if (expectedInterface) {
const requiredCapabilities = registry2.getInterfaceShape(expectedInterface);
if (!requiredCapabilities) {
throw new AdapterError(`Unknown interface shape requested: '${expectedInterface}'. Ensure it is registered in the registry.`, { code: "INTERNAL_ERROR" });
}
const adapterCapabilities = adapterInfo.capabilities || [];
for (const req of requiredCapabilities) {
if (!adapterCapabilities.includes(req)) {
throw new AdapterError(`Adapter '${name}@${version}' does not fully implement the '${expectedInterface}' interface. Missing capability: '${req}'.`, { code: "INCOMPATIBLE_ADAPTER", methodName: factoryMethodName });
}
}
}
if (adapterInfo.requirements && adapterInfo.requirements.length > 0) {
console.log("Validator - adapterInfo, ", adapterInfo);
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.ty