@emblemvault/auth-sdk 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"ethers.js","sources":["../../src/signers/http.ts","../../src/signers/validation.ts","../../src/signers/utils.ts","../../src/signers/vault.ts","../../src/signers/ethers.ts"],"sourcesContent":["import type { SignerConfig } from '../types/signers';\n\nfunction sanitizeErrorMessage(status: number, text: string): string {\n // Sanitize error messages to avoid leaking sensitive server information\n let errorMessage = `Emblem signer error ${status}`;\n\n if (status >= 500) {\n errorMessage += ': Internal server error';\n } else if (status === 401 || status === 403) {\n errorMessage += ': Authentication failed';\n } else if (status === 404) {\n errorMessage += ': Resource not found';\n } else if (status === 405) {\n errorMessage += ': Method not allowed';\n } else if (text) {\n // For 4xx client errors, include limited error details\n errorMessage += `: ${text.substring(0, 200)}`; // Limit to 200 chars\n }\n\n return errorMessage;\n}\n\nasync function resolveAuthHeaders(config: SignerConfig): Promise<Record<string, string>> {\n // Priority: custom headers -> jwt/getJwt/sdk -> apiKey (deprecated)\n if (typeof config.getAuthHeaders === 'function') {\n const h = await config.getAuthHeaders();\n if (h && typeof h === 'object') return h;\n }\n\n const tok =\n config.jwt ??\n (typeof config.getJwt === 'function' ? await config.getJwt() : undefined) ??\n config.sdk?.getSession()?.authToken ??\n undefined;\n\n if (tok) {\n return { Authorization: `Bearer ${tok}` };\n }\n\n // apiKey is deprecated but still supported as fallback\n if (config.apiKey) {\n return { 'x-api-key': config.apiKey };\n }\n\n throw new Error(\n 'No authentication available: provide jwt, getJwt(), getAuthHeaders(), sdk, or apiKey'\n );\n}\n\nexport async function emblemPost<T = unknown>(\n path: string,\n body: unknown,\n config: SignerConfig\n): Promise<T> {\n const baseUrl = config.baseUrl ?? 'https://api.emblemvault.ai';\n const authHeaders = await resolveAuthHeaders(config);\n const res = await fetch(`${baseUrl}${path}`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...authHeaders,\n },\n body: JSON.stringify(body, (_key: string, value: unknown) =>\n typeof value === 'bigint' ? value.toString() : value\n ),\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(sanitizeErrorMessage(res.status, text));\n }\n\n return res.json() as Promise<T>;\n}\n\nexport async function emblemGet<T = unknown>(path: string, config: SignerConfig): Promise<T> {\n const baseUrl = config.baseUrl ?? 'https://api.emblemvault.ai';\n const authHeaders = await resolveAuthHeaders(config);\n const res = await fetch(`${baseUrl}${path}`, {\n method: 'GET',\n headers: authHeaders,\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(sanitizeErrorMessage(res.status, text));\n }\n\n return res.json() as Promise<T>;\n}\n","import type { SignerConfig } from '../types/signers';\n\n/**\n * Environment detection utilities for warning about unsafe usage patterns\n */\n\n/**\n * Detect if code is running in a browser environment\n */\nexport function isBrowserEnvironment(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Check if we're in a Node.js server environment\n */\nexport function isNodeEnvironment(): boolean {\n return (\n typeof process !== 'undefined' && process.versions != null && process.versions.node != null\n );\n}\n\n/**\n * Validate baseUrl format\n */\nexport function validateBaseUrl(baseUrl?: string): void {\n if (!baseUrl) return; // undefined is ok, will use default\n\n if (!baseUrl.startsWith('http://') && !baseUrl.startsWith('https://')) {\n throw new Error('baseUrl must be a valid HTTP(S) URL');\n }\n\n // Warn about http (not https)\n if (\n baseUrl.startsWith('http://') &&\n !baseUrl.includes('localhost') &&\n !baseUrl.includes('127.0.0.1')\n ) {\n console.warn(\n '[Emblem Security Warning] baseUrl uses HTTP instead of HTTPS. This is insecure for production use.'\n );\n }\n}\n\n/**\n * Validate Ethereum address format\n */\nexport function validateEthereumAddress(address: string): void {\n if (!address || typeof address !== 'string') {\n throw new Error('Address is required');\n }\n\n if (!address.startsWith('0x')) {\n throw new Error('Address must start with 0x');\n }\n\n if (!/^0x[0-9a-fA-F]{40}$/.test(address)) {\n throw new Error('Invalid Ethereum address format');\n }\n}\n\n/**\n * Validate vault ID\n */\nexport function validateVaultId(vaultId: string): void {\n if (!vaultId || typeof vaultId !== 'string') {\n throw new Error('vaultId is required');\n }\n\n if (vaultId.trim() === '') {\n throw new Error('vaultId cannot be empty');\n }\n}\n\n/**\n * Safe number conversion with bounds checking\n */\nexport function toSafeNumber(value: unknown, fieldName: string): number {\n const num = Number(value);\n\n if (!Number.isSafeInteger(num)) {\n throw new Error(\n `${fieldName} value ${value} exceeds safe integer range (max: ${Number.MAX_SAFE_INTEGER})`\n );\n }\n\n return num;\n}\n\n/**\n * Extended config with security options\n */\nexport interface SignerSecurityConfig extends SignerConfig {\n /**\n * Enable debug logging for security-related checks\n * @default false\n */\n debugSecurity?: boolean;\n}\n\n/**\n * Validate signer configuration\n */\nexport function validateSignerConfig(config: SignerSecurityConfig): void {\n // Validate auth: require at least one method (jwt, getJwt, getAuthHeaders)\n const hasJwt = !!config.jwt;\n const hasGetJwt = typeof config.getJwt === 'function';\n const hasHeaders = typeof config.getAuthHeaders === 'function';\n\n if (!hasJwt && !hasGetJwt && !hasHeaders) {\n throw new Error('Authentication required: provide jwt, getJwt(), or getAuthHeaders()');\n }\n\n // Validate baseUrl if provided\n if (config.baseUrl) {\n validateBaseUrl(config.baseUrl);\n }\n\n // Security audit logging\n if (config.debugSecurity) {\n console.log('[Emblem Security Debug]', {\n environment: isBrowserEnvironment() ? 'browser' : 'node',\n hasBaseUrl: !!config.baseUrl,\n timestamp: new Date().toISOString(),\n });\n }\n}\n","import type { Hex } from '../types/signers';\nimport { toSafeNumber } from './validation';\n\nexport function toHexIfBigInt(v: unknown): unknown {\n return typeof v === 'bigint' ? '0x' + v.toString(16) : v;\n}\n\n/**\n * viem txs sometimes have bigint / hex / optional fields. Ethers serializers\n * accept hex strings for numeric fields. Normalize where helpful.\n */\nexport function normalizeTxForEmblem(tx: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = { ...tx };\n\n if (out.value !== undefined) out.value = toHexIfBigInt(out.value);\n if (out.gas !== undefined) {\n out.gasLimit = toHexIfBigInt(out.gas);\n delete out.gas;\n }\n if (out.gasLimit !== undefined) out.gasLimit = toHexIfBigInt(out.gasLimit);\n if (out.gasPrice !== undefined) out.gasPrice = toHexIfBigInt(out.gasPrice);\n if (out.maxFeePerGas !== undefined) out.maxFeePerGas = toHexIfBigInt(out.maxFeePerGas);\n if (out.maxPriorityFeePerGas !== undefined)\n out.maxPriorityFeePerGas = toHexIfBigInt(out.maxPriorityFeePerGas);\n if (out.nonce !== undefined) out.nonce = toSafeNumber(out.nonce, 'nonce');\n if (out.chainId !== undefined) out.chainId = toSafeNumber(out.chainId, 'chainId');\n\n // Some backends only accept legacy fields; fold EIP-1559 into gasPrice and drop unsupported keys\n if (out.maxFeePerGas !== undefined || out.maxPriorityFeePerGas !== undefined) {\n if (out.gasPrice === undefined && out.maxFeePerGas !== undefined) {\n out.gasPrice = out.maxFeePerGas;\n }\n delete out.maxFeePerGas;\n delete out.maxPriorityFeePerGas;\n }\n\n // Remove fields commonly unsupported by legacy serializers\n delete out.type;\n delete out.accessList;\n delete out.account;\n delete out.chain;\n delete out.from;\n\n return out;\n}\n\nexport function isHexString(value: unknown): value is Hex {\n return typeof value === 'string' && /^0x[0-9a-fA-F]*$/.test(value);\n}\n\nexport function bytesToHex(bytes: ArrayLike<number>): Hex {\n let out = '0x';\n for (let i = 0; i < bytes.length; i++) {\n out += (bytes[i] as number).toString(16).padStart(2, '0');\n }\n return out as Hex;\n}\n","import type { SignerConfig, SignerVaultInfo, Hex } from '../types/signers';\nimport { emblemPost } from './http';\n\nexport async function fetchVaultInfo(config: SignerConfig): Promise<SignerVaultInfo> {\n // Note: The server only supports POST for /vault/info\n const data: Partial<{\n vaultId: string;\n address: string;\n evmAddress: Hex;\n created_by?: string;\n }> = await emblemPost('/vault/info', {}, config);\n\n // Validate required response data (vaultId + evmAddress are required for EVM)\n if (!data || !data.vaultId || !data.evmAddress) {\n throw new Error('Invalid vault info response: missing required fields');\n }\n\n if (!String(data.evmAddress).startsWith('0x')) {\n throw new Error('Invalid evmAddress format in response');\n }\n\n return {\n vaultId: data.vaultId,\n tokenId: data.vaultId,\n address: data.address || '', // Solana address may be absent; keep optional\n evmAddress: data.evmAddress as Hex,\n created_by: data.created_by,\n };\n}\n","import type { Hex, SignerConfig, SignerVaultInfo } from '../types/signers';\nimport { emblemPost } from './http';\nimport { bytesToHex, normalizeTxForEmblem } from './utils';\nimport { fetchVaultInfo } from './vault';\n\n// ethers v6 compatible interface (like solana pattern - no runtime dependency)\nexport interface EmblemEthersWallet {\n getAddress(): Promise<string>;\n signMessage(message: string | Uint8Array): Promise<string>;\n signTypedData(\n domain: unknown,\n types: Record<string, Array<{ name: string; type: string }>>,\n value: Record<string, unknown>\n ): Promise<string>;\n signTransaction(tx: unknown): Promise<string>;\n sendTransaction(tx: unknown): Promise<unknown>;\n connect(provider: unknown): EmblemEthersWallet;\n provider: unknown;\n // Additional methods\n initialize(): Promise<void>;\n getVaultId(): string;\n setChainId(chainId: number): void;\n getChainId(): number;\n signAndBroadcast(transaction: unknown, waitForReceipt?: boolean): Promise<string>;\n}\n\nexport async function toEthersWallet(\n config: SignerConfig,\n provider?: unknown | null,\n infoOverride?: SignerVaultInfo\n): Promise<EmblemEthersWallet> {\n // Dynamic import - only loads ethers when this function is called\n let ethers: typeof import('ethers');\n try {\n ethers = await import('ethers');\n } catch {\n throw new Error('ethers is required for toEthersWallet(). Install it with: npm install ethers');\n }\n\n const { AbstractSigner, resolveAddress } = ethers;\n type AbstractProvider = import('ethers').AbstractProvider;\n type TransactionRequest = import('ethers').TransactionRequest;\n type TransactionResponse = import('ethers').TransactionResponse;\n type TransactionLike = import('ethers').TransactionLike<string>;\n type TypedDataDomain = import('ethers').TypedDataDomain;\n type TypedDataField = import('ethers').TypedDataField;\n\n const info = infoOverride ?? (await fetchVaultInfo(config));\n\n // Class defined inside function after dynamic import\n class EmblemEthersWalletImpl extends AbstractSigner {\n private readonly _config: SignerConfig;\n private _address: Hex | null = null;\n private _vaultId: string | null = null;\n private _chainId = 1;\n private _initPromise?: Promise<void>;\n\n constructor(\n signerConfig: SignerConfig,\n signerProvider?: AbstractProvider | null,\n seed?: { address?: Hex; vaultId?: string; chainId?: number }\n ) {\n super(signerProvider ?? null);\n this._config = signerConfig;\n if (seed?.address) this._address = seed.address;\n if (seed?.vaultId) this._vaultId = seed.vaultId;\n if (seed?.chainId) this._chainId = seed.chainId;\n }\n\n async initialize(): Promise<void> {\n if (this._initPromise) return this._initPromise;\n\n this._initPromise = fetchVaultInfo(this._config)\n .then((vaultInfo) => {\n this._address = vaultInfo.evmAddress;\n this._vaultId = vaultInfo.vaultId;\n })\n .catch((err) => {\n this._initPromise = undefined;\n throw err;\n });\n\n return this._initPromise;\n }\n\n async getAddress(): Promise<string> {\n if (!this._address) await this.initialize();\n return this._address!;\n }\n\n getVaultId(): string {\n if (!this._vaultId) throw new Error('Wallet not initialized. Call initialize() first.');\n return this._vaultId;\n }\n\n setChainId(chainId: number): void {\n this._chainId = chainId;\n }\n\n getChainId(): number {\n return this._chainId;\n }\n\n connect(newProvider: AbstractProvider): EmblemEthersWalletImpl {\n if (!newProvider) throw new Error('Provider cannot be null');\n return new EmblemEthersWalletImpl(this._config, newProvider, {\n address: this._address ?? undefined,\n vaultId: this._vaultId ?? undefined,\n chainId: this._chainId,\n });\n }\n\n async signMessage(message: string | Uint8Array): Promise<string> {\n if (!this._vaultId) await this.initialize();\n const payload = typeof message === 'string' ? message : bytesToHex(message);\n const data = await emblemPost<{ signerAddress: string; signature: Hex }>(\n '/sign-eth-message',\n { vaultId: this._vaultId!, message: payload },\n this._config\n );\n return data.signature;\n }\n\n async signTypedData(\n domain: TypedDataDomain,\n types: Record<string, Array<TypedDataField>>,\n value: Record<string, unknown>\n ): Promise<string> {\n if (!this._vaultId) await this.initialize();\n const cleanTypes = { ...types };\n if (cleanTypes && (cleanTypes as Record<string, unknown>).EIP712Domain) {\n delete (cleanTypes as Record<string, unknown>).EIP712Domain;\n }\n const data = await emblemPost<{ signerAddress: string; signature: Hex }>(\n '/sign-typed-message',\n { vaultId: this._vaultId!, domain, types: cleanTypes, message: value },\n this._config\n );\n return data.signature;\n }\n\n async _signTypedData(\n domain: TypedDataDomain,\n types: Record<string, Array<TypedDataField>>,\n value: Record<string, unknown>\n ): Promise<string> {\n return this.signTypedData(domain, types, value);\n }\n\n async signTransaction(tx: TransactionRequest): Promise<string> {\n if (!this._vaultId) await this.initialize();\n const from = (tx as Record<string, unknown>).from as string | undefined;\n const addr = await this.getAddress();\n\n if (from && from.toLowerCase() !== addr.toLowerCase()) {\n throw new Error('transaction from does not match signer address');\n }\n\n const toSign = this.provider\n ? ({ ...await this.populateTransaction(tx) } as Record<string, unknown>)\n : ({ ...tx } as Record<string, unknown>);\n if (toSign.from) delete toSign.from;\n if (!('to' in toSign) || !toSign.to) {\n throw new Error(\"Transaction must have a 'to' address\");\n }\n if (toSign.nonce === undefined || toSign.nonce === null) {\n throw new Error('Transaction must have a nonce');\n }\n const normalized = normalizeTxForEmblem(toSign);\n const resp = await emblemPost<{ signedTransaction: Hex }>(\n '/sign-eth-tx',\n { vaultId: this._vaultId!, transaction: normalized, options: { chainId: this._chainId } },\n this._config\n );\n return resp.signedTransaction;\n }\n\n async sendTransaction(tx: TransactionRequest): Promise<TransactionResponse> {\n if (!this.provider) throw new Error('Provider required to send transaction');\n const signed = await this.signTransaction(tx);\n return await this.provider.broadcastTransaction(signed);\n }\n\n async populateTransaction(transaction: TransactionRequest): Promise<TransactionLike> {\n const tx = { ...transaction } as TransactionRequest;\n if (!this.provider) throw new Error('Provider required to populate transaction');\n const fromAddress = tx.from\n ? await resolveAddress(tx.from, this.provider)\n : await this.getAddress();\n\n let chainId: bigint;\n if (!tx.chainId) {\n const network = await this.provider.getNetwork();\n chainId = network.chainId;\n this._chainId = Number(network.chainId);\n } else {\n chainId = BigInt(tx.chainId);\n this._chainId = Number(tx.chainId);\n }\n\n const nonce =\n tx.nonce != null\n ? Number(tx.nonce)\n : await this.provider.getTransactionCount(fromAddress, 'pending');\n const toAddress = tx.to ? await resolveAddress(tx.to, this.provider) : null;\n const value = tx.value ? BigInt(tx.value.toString()) : 0n;\n\n let gasLimit: bigint;\n if (!tx.gasLimit) {\n try {\n gasLimit = await this.provider.estimateGas({ ...tx, from: fromAddress });\n } catch {\n gasLimit = 21000n;\n }\n } else {\n gasLimit = BigInt(tx.gasLimit.toString());\n }\n\n let gasPrice: bigint | null = null;\n if (!tx.gasPrice && tx.type !== 2) {\n const feeData = await this.provider.getFeeData();\n gasPrice = feeData.gasPrice ?? null;\n } else if (tx.gasPrice) {\n gasPrice = BigInt(tx.gasPrice.toString());\n }\n\n const populated: TransactionLike = {\n from: fromAddress,\n to: toAddress,\n value,\n nonce,\n gasLimit,\n data: tx.data as string | undefined,\n chainId,\n type: tx.type || undefined,\n };\n if (gasPrice !== null) populated.gasPrice = gasPrice;\n if (tx.maxFeePerGas) populated.maxFeePerGas = BigInt(tx.maxFeePerGas.toString());\n if (tx.maxPriorityFeePerGas)\n populated.maxPriorityFeePerGas = BigInt(tx.maxPriorityFeePerGas.toString());\n return populated;\n }\n\n async signAndBroadcast(\n transaction: TransactionRequest,\n waitForReceipt: boolean = false\n ): Promise<string> {\n if (!this.provider) throw new Error('Provider required to send transaction');\n const signed = await this.signTransaction(transaction);\n const resp = await this.provider.broadcastTransaction(signed);\n const hash = resp.hash as string;\n if (waitForReceipt) {\n await this.provider.waitForTransaction(hash);\n }\n return hash;\n }\n }\n\n return new EmblemEthersWalletImpl(config, provider as AbstractProvider | null, {\n address: info.evmAddress,\n vaultId: info.vaultId,\n });\n}\n"],"names":["async","emblemPost","path","body","config","baseUrl","authHeaders","getAuthHeaders","h","tok","jwt","getJwt","undefined","sdk","getSession","authToken","Authorization","apiKey","Error","resolveAuthHeaders","res","fetch","method","headers","JSON","stringify","_key","value","toString","ok","text","catch","status","errorMessage","substring","sanitizeErrorMessage","json","toSafeNumber","fieldName","num","Number","isSafeInteger","MAX_SAFE_INTEGER","toHexIfBigInt","v","fetchVaultInfo","data","vaultId","evmAddress","String","startsWith","tokenId","address","created_by","provider","infoOverride","ethers","Promise","resolve","then","_interopNamespace","require","AbstractSigner","resolveAddress","info","EmblemEthersWalletImpl","constructor","signerConfig","signerProvider","seed","super","this","_address","_vaultId","_chainId","_config","chainId","initialize","_initPromise","vaultInfo","err","getAddress","getVaultId","setChainId","getChainId","connect","newProvider","signMessage","message","payload","bytes","out","i","length","padStart","bytesToHex","signature","signTypedData","domain","types","cleanTypes","EIP712Domain","_signTypedData","signTransaction","tx","from","addr","toLowerCase","toSign","populateTransaction","to","nonce","normalized","gas","gasLimit","gasPrice","maxFeePerGas","maxPriorityFeePerGas","type","accessList","account","chain","normalizeTxForEmblem","transaction","options","signedTransaction","sendTransaction","signed","broadcastTransaction","fromAddress","BigInt","network","getNetwork","getTransactionCount","toAddress","estimateGas","getFeeData","populated","signAndBroadcast","waitForReceipt","hash","waitForTransaction"],"mappings":"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"}
1
+ {"version":3,"file":"ethers.js","sources":["../../src/signers/http.ts","../../src/signers/validation.ts","../../src/signers/utils.ts","../../src/signers/vault.ts","../../src/signers/ethers.ts"],"sourcesContent":["import type { SignerConfig } from '../types/signers';\n\nfunction sanitizeErrorMessage(status: number, text: string): string {\n // Sanitize error messages to avoid leaking sensitive server information\n let errorMessage = `Emblem signer error ${status}`;\n\n if (status >= 500) {\n errorMessage += ': Internal server error';\n } else if (status === 401 || status === 403) {\n errorMessage += ': Authentication failed';\n } else if (status === 404) {\n errorMessage += ': Resource not found';\n } else if (status === 405) {\n errorMessage += ': Method not allowed';\n } else if (text) {\n // For 4xx client errors, include limited error details\n errorMessage += `: ${text.substring(0, 200)}`; // Limit to 200 chars\n }\n\n return errorMessage;\n}\n\nasync function resolveAuthHeaders(config: SignerConfig): Promise<Record<string, string>> {\n // Priority: custom headers -> jwt/getJwt/sdk -> apiKey (deprecated)\n if (typeof config.getAuthHeaders === 'function') {\n const h = await config.getAuthHeaders();\n if (h && typeof h === 'object') return h;\n }\n\n const tok =\n config.jwt ??\n (typeof config.getJwt === 'function' ? await config.getJwt() : undefined) ??\n config.sdk?.getSession()?.authToken ??\n undefined;\n\n if (tok) {\n return { Authorization: `Bearer ${tok}` };\n }\n\n // apiKey is deprecated but still supported as fallback\n if (config.apiKey) {\n return { 'x-api-key': config.apiKey };\n }\n\n throw new Error(\n 'No authentication available: provide jwt, getJwt(), getAuthHeaders(), sdk, or apiKey'\n );\n}\n\nexport async function emblemPost<T = unknown>(\n path: string,\n body: unknown,\n config: SignerConfig\n): Promise<T> {\n const baseUrl = config.baseUrl ?? 'https://api.emblemvault.ai';\n const authHeaders = await resolveAuthHeaders(config);\n const res = await fetch(`${baseUrl}${path}`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...authHeaders,\n },\n body: JSON.stringify(body, (_key: string, value: unknown) =>\n typeof value === 'bigint' ? value.toString() : value\n ),\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(sanitizeErrorMessage(res.status, text));\n }\n\n return res.json() as Promise<T>;\n}\n\nexport async function emblemGet<T = unknown>(path: string, config: SignerConfig): Promise<T> {\n const baseUrl = config.baseUrl ?? 'https://api.emblemvault.ai';\n const authHeaders = await resolveAuthHeaders(config);\n const res = await fetch(`${baseUrl}${path}`, {\n method: 'GET',\n headers: authHeaders,\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(sanitizeErrorMessage(res.status, text));\n }\n\n return res.json() as Promise<T>;\n}\n","import type { SignerConfig } from '../types/signers';\n\n/**\n * Environment detection utilities for warning about unsafe usage patterns\n */\n\n/**\n * Detect if code is running in a browser environment\n */\nexport function isBrowserEnvironment(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Check if we're in a Node.js server environment\n */\nexport function isNodeEnvironment(): boolean {\n return (\n typeof process !== 'undefined' && process.versions != null && process.versions.node != null\n );\n}\n\n/**\n * Validate baseUrl format\n */\nexport function validateBaseUrl(baseUrl?: string): void {\n if (!baseUrl) return; // undefined is ok, will use default\n\n if (!baseUrl.startsWith('http://') && !baseUrl.startsWith('https://')) {\n throw new Error('baseUrl must be a valid HTTP(S) URL');\n }\n\n // Warn about http (not https)\n if (\n baseUrl.startsWith('http://') &&\n !baseUrl.includes('localhost') &&\n !baseUrl.includes('127.0.0.1')\n ) {\n console.warn(\n '[Emblem Security Warning] baseUrl uses HTTP instead of HTTPS. This is insecure for production use.'\n );\n }\n}\n\n/**\n * Validate Ethereum address format\n */\nexport function validateEthereumAddress(address: string): void {\n if (!address || typeof address !== 'string') {\n throw new Error('Address is required');\n }\n\n if (!address.startsWith('0x')) {\n throw new Error('Address must start with 0x');\n }\n\n if (!/^0x[0-9a-fA-F]{40}$/.test(address)) {\n throw new Error('Invalid Ethereum address format');\n }\n}\n\n/**\n * Validate vault ID\n */\nexport function validateVaultId(vaultId: string): void {\n if (!vaultId || typeof vaultId !== 'string') {\n throw new Error('vaultId is required');\n }\n\n if (vaultId.trim() === '') {\n throw new Error('vaultId cannot be empty');\n }\n}\n\n/**\n * Safe number conversion with bounds checking\n */\nexport function toSafeNumber(value: unknown, fieldName: string): number {\n const num = Number(value);\n\n if (!Number.isSafeInteger(num)) {\n throw new Error(\n `${fieldName} value ${value} exceeds safe integer range (max: ${Number.MAX_SAFE_INTEGER})`\n );\n }\n\n return num;\n}\n\n/**\n * Extended config with security options\n */\nexport interface SignerSecurityConfig extends SignerConfig {\n /**\n * Enable debug logging for security-related checks\n * @default false\n */\n debugSecurity?: boolean;\n}\n\n/**\n * Validate signer configuration\n */\nexport function validateSignerConfig(config: SignerSecurityConfig): void {\n // Validate auth: require at least one method (jwt, getJwt, getAuthHeaders)\n const hasJwt = !!config.jwt;\n const hasGetJwt = typeof config.getJwt === 'function';\n const hasHeaders = typeof config.getAuthHeaders === 'function';\n\n if (!hasJwt && !hasGetJwt && !hasHeaders) {\n throw new Error('Authentication required: provide jwt, getJwt(), or getAuthHeaders()');\n }\n\n // Validate baseUrl if provided\n if (config.baseUrl) {\n validateBaseUrl(config.baseUrl);\n }\n\n // Security audit logging\n if (config.debugSecurity) {\n console.log('[Emblem Security Debug]', {\n environment: isBrowserEnvironment() ? 'browser' : 'node',\n hasBaseUrl: !!config.baseUrl,\n timestamp: new Date().toISOString(),\n });\n }\n}\n","import type { Hex } from '../types/signers';\nimport { toSafeNumber } from './validation';\n\nexport function toHexIfBigInt(v: unknown): unknown {\n return typeof v === 'bigint' ? '0x' + v.toString(16) : v;\n}\n\n/**\n * viem txs sometimes have bigint / hex / optional fields. Ethers serializers\n * accept hex strings for numeric fields. Normalize where helpful.\n */\nexport function normalizeTxForEmblem(tx: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = { ...tx };\n\n if (out.value !== undefined) out.value = toHexIfBigInt(out.value);\n if (out.gas !== undefined) {\n out.gasLimit = toHexIfBigInt(out.gas);\n delete out.gas;\n }\n if (out.gasLimit !== undefined) out.gasLimit = toHexIfBigInt(out.gasLimit);\n if (out.gasPrice !== undefined) out.gasPrice = toHexIfBigInt(out.gasPrice);\n if (out.maxFeePerGas !== undefined) out.maxFeePerGas = toHexIfBigInt(out.maxFeePerGas);\n if (out.maxPriorityFeePerGas !== undefined)\n out.maxPriorityFeePerGas = toHexIfBigInt(out.maxPriorityFeePerGas);\n if (out.nonce !== undefined) out.nonce = toSafeNumber(out.nonce, 'nonce');\n if (out.chainId !== undefined) out.chainId = toSafeNumber(out.chainId, 'chainId');\n\n // Some backends only accept legacy fields; fold EIP-1559 into gasPrice and drop unsupported keys\n if (out.maxFeePerGas !== undefined || out.maxPriorityFeePerGas !== undefined) {\n if (out.gasPrice === undefined && out.maxFeePerGas !== undefined) {\n out.gasPrice = out.maxFeePerGas;\n }\n delete out.maxFeePerGas;\n delete out.maxPriorityFeePerGas;\n }\n\n // Remove fields commonly unsupported by legacy serializers\n delete out.type;\n delete out.accessList;\n delete out.account;\n delete out.chain;\n delete out.from;\n\n return out;\n}\n\nexport function isHexString(value: unknown): value is Hex {\n return typeof value === 'string' && /^0x[0-9a-fA-F]*$/.test(value);\n}\n\nexport function bytesToHex(bytes: ArrayLike<number>): Hex {\n let out = '0x';\n for (let i = 0; i < bytes.length; i++) {\n out += (bytes[i] as number).toString(16).padStart(2, '0');\n }\n return out as Hex;\n}\n","import type { SignerConfig, SignerVaultInfo, Hex } from '../types/signers';\nimport { emblemPost } from './http';\n\nexport async function fetchVaultInfo(config: SignerConfig): Promise<SignerVaultInfo> {\n // Note: The server only supports POST for /vault/info\n const data: Partial<{\n vaultId: string;\n address: string;\n evmAddress: Hex;\n created_by?: string;\n }> = await emblemPost('/vault/info', {}, config);\n\n // Validate required response data (vaultId + evmAddress are required for EVM)\n if (!data || !data.vaultId || !data.evmAddress) {\n throw new Error('Invalid vault info response: missing required fields');\n }\n\n if (!String(data.evmAddress).startsWith('0x')) {\n throw new Error('Invalid evmAddress format in response');\n }\n\n return {\n vaultId: data.vaultId,\n tokenId: data.vaultId,\n address: data.address || '', // Solana address may be absent; keep optional\n evmAddress: data.evmAddress as Hex,\n created_by: data.created_by,\n };\n}\n","import type { Hex, SignerConfig, SignerVaultInfo } from '../types/signers';\nimport { emblemPost } from './http';\nimport { bytesToHex, normalizeTxForEmblem } from './utils';\nimport { fetchVaultInfo } from './vault';\n\n// ethers v6 compatible interface (like solana pattern - no runtime dependency)\nexport interface EmblemEthersWallet {\n getAddress(): Promise<string>;\n signMessage(message: string | Uint8Array): Promise<string>;\n signTypedData(\n domain: unknown,\n types: Record<string, Array<{ name: string; type: string }>>,\n value: Record<string, unknown>\n ): Promise<string>;\n signTransaction(tx: unknown): Promise<string>;\n sendTransaction(tx: unknown): Promise<unknown>;\n connect(provider: unknown): EmblemEthersWallet;\n provider: unknown;\n // Additional methods\n initialize(): Promise<void>;\n getVaultId(): string;\n setChainId(chainId: number): void;\n getChainId(): number;\n signAndBroadcast(transaction: unknown, waitForReceipt?: boolean): Promise<string>;\n}\n\nexport async function toEthersWallet(\n config: SignerConfig,\n provider?: unknown | null,\n infoOverride?: SignerVaultInfo\n): Promise<EmblemEthersWallet> {\n // Dynamic import - only loads ethers when this function is called\n // webpackIgnore comment prevents webpack from trying to resolve at build time\n let ethers: typeof import('ethers');\n try {\n ethers = await import(/* webpackIgnore: true */ 'ethers');\n } catch {\n throw new Error('ethers is required for toEthersWallet(). Install it with: npm install ethers');\n }\n\n const { AbstractSigner, resolveAddress } = ethers;\n type AbstractProvider = import('ethers').AbstractProvider;\n type TransactionRequest = import('ethers').TransactionRequest;\n type TransactionResponse = import('ethers').TransactionResponse;\n type TransactionLike = import('ethers').TransactionLike<string>;\n type TypedDataDomain = import('ethers').TypedDataDomain;\n type TypedDataField = import('ethers').TypedDataField;\n\n const info = infoOverride ?? (await fetchVaultInfo(config));\n\n // Class defined inside function after dynamic import\n class EmblemEthersWalletImpl extends AbstractSigner {\n private readonly _config: SignerConfig;\n private _address: Hex | null = null;\n private _vaultId: string | null = null;\n private _chainId = 1;\n private _initPromise?: Promise<void>;\n\n constructor(\n signerConfig: SignerConfig,\n signerProvider?: AbstractProvider | null,\n seed?: { address?: Hex; vaultId?: string; chainId?: number }\n ) {\n super(signerProvider ?? null);\n this._config = signerConfig;\n if (seed?.address) this._address = seed.address;\n if (seed?.vaultId) this._vaultId = seed.vaultId;\n if (seed?.chainId) this._chainId = seed.chainId;\n }\n\n async initialize(): Promise<void> {\n if (this._initPromise) return this._initPromise;\n\n this._initPromise = fetchVaultInfo(this._config)\n .then((vaultInfo) => {\n this._address = vaultInfo.evmAddress;\n this._vaultId = vaultInfo.vaultId;\n })\n .catch((err) => {\n this._initPromise = undefined;\n throw err;\n });\n\n return this._initPromise;\n }\n\n async getAddress(): Promise<string> {\n if (!this._address) await this.initialize();\n return this._address!;\n }\n\n getVaultId(): string {\n if (!this._vaultId) throw new Error('Wallet not initialized. Call initialize() first.');\n return this._vaultId;\n }\n\n setChainId(chainId: number): void {\n this._chainId = chainId;\n }\n\n getChainId(): number {\n return this._chainId;\n }\n\n connect(newProvider: AbstractProvider): EmblemEthersWalletImpl {\n if (!newProvider) throw new Error('Provider cannot be null');\n return new EmblemEthersWalletImpl(this._config, newProvider, {\n address: this._address ?? undefined,\n vaultId: this._vaultId ?? undefined,\n chainId: this._chainId,\n });\n }\n\n async signMessage(message: string | Uint8Array): Promise<string> {\n if (!this._vaultId) await this.initialize();\n const payload = typeof message === 'string' ? message : bytesToHex(message);\n const data = await emblemPost<{ signerAddress: string; signature: Hex }>(\n '/sign-eth-message',\n { vaultId: this._vaultId!, message: payload },\n this._config\n );\n return data.signature;\n }\n\n async signTypedData(\n domain: TypedDataDomain,\n types: Record<string, Array<TypedDataField>>,\n value: Record<string, unknown>\n ): Promise<string> {\n if (!this._vaultId) await this.initialize();\n const cleanTypes = { ...types };\n if (cleanTypes && (cleanTypes as Record<string, unknown>).EIP712Domain) {\n delete (cleanTypes as Record<string, unknown>).EIP712Domain;\n }\n const data = await emblemPost<{ signerAddress: string; signature: Hex }>(\n '/sign-typed-message',\n { vaultId: this._vaultId!, domain, types: cleanTypes, message: value },\n this._config\n );\n return data.signature;\n }\n\n async _signTypedData(\n domain: TypedDataDomain,\n types: Record<string, Array<TypedDataField>>,\n value: Record<string, unknown>\n ): Promise<string> {\n return this.signTypedData(domain, types, value);\n }\n\n async signTransaction(tx: TransactionRequest): Promise<string> {\n if (!this._vaultId) await this.initialize();\n const from = (tx as Record<string, unknown>).from as string | undefined;\n const addr = await this.getAddress();\n\n if (from && from.toLowerCase() !== addr.toLowerCase()) {\n throw new Error('transaction from does not match signer address');\n }\n\n const toSign = this.provider\n ? ({ ...await this.populateTransaction(tx) } as Record<string, unknown>)\n : ({ ...tx } as Record<string, unknown>);\n if (toSign.from) delete toSign.from;\n if (!('to' in toSign) || !toSign.to) {\n throw new Error(\"Transaction must have a 'to' address\");\n }\n if (toSign.nonce === undefined || toSign.nonce === null) {\n throw new Error('Transaction must have a nonce');\n }\n const normalized = normalizeTxForEmblem(toSign);\n const resp = await emblemPost<{ signedTransaction: Hex }>(\n '/sign-eth-tx',\n { vaultId: this._vaultId!, transaction: normalized, options: { chainId: this._chainId } },\n this._config\n );\n return resp.signedTransaction;\n }\n\n async sendTransaction(tx: TransactionRequest): Promise<TransactionResponse> {\n if (!this.provider) throw new Error('Provider required to send transaction');\n const signed = await this.signTransaction(tx);\n return await this.provider.broadcastTransaction(signed);\n }\n\n async populateTransaction(transaction: TransactionRequest): Promise<TransactionLike> {\n const tx = { ...transaction } as TransactionRequest;\n if (!this.provider) throw new Error('Provider required to populate transaction');\n const fromAddress = tx.from\n ? await resolveAddress(tx.from, this.provider)\n : await this.getAddress();\n\n let chainId: bigint;\n if (!tx.chainId) {\n const network = await this.provider.getNetwork();\n chainId = network.chainId;\n this._chainId = Number(network.chainId);\n } else {\n chainId = BigInt(tx.chainId);\n this._chainId = Number(tx.chainId);\n }\n\n const nonce =\n tx.nonce != null\n ? Number(tx.nonce)\n : await this.provider.getTransactionCount(fromAddress, 'pending');\n const toAddress = tx.to ? await resolveAddress(tx.to, this.provider) : null;\n const value = tx.value ? BigInt(tx.value.toString()) : 0n;\n\n let gasLimit: bigint;\n if (!tx.gasLimit) {\n try {\n gasLimit = await this.provider.estimateGas({ ...tx, from: fromAddress });\n } catch {\n gasLimit = 21000n;\n }\n } else {\n gasLimit = BigInt(tx.gasLimit.toString());\n }\n\n let gasPrice: bigint | null = null;\n if (!tx.gasPrice && tx.type !== 2) {\n const feeData = await this.provider.getFeeData();\n gasPrice = feeData.gasPrice ?? null;\n } else if (tx.gasPrice) {\n gasPrice = BigInt(tx.gasPrice.toString());\n }\n\n const populated: TransactionLike = {\n from: fromAddress,\n to: toAddress,\n value,\n nonce,\n gasLimit,\n data: tx.data as string | undefined,\n chainId,\n type: tx.type || undefined,\n };\n if (gasPrice !== null) populated.gasPrice = gasPrice;\n if (tx.maxFeePerGas) populated.maxFeePerGas = BigInt(tx.maxFeePerGas.toString());\n if (tx.maxPriorityFeePerGas)\n populated.maxPriorityFeePerGas = BigInt(tx.maxPriorityFeePerGas.toString());\n return populated;\n }\n\n async signAndBroadcast(\n transaction: TransactionRequest,\n waitForReceipt: boolean = false\n ): Promise<string> {\n if (!this.provider) throw new Error('Provider required to send transaction');\n const signed = await this.signTransaction(transaction);\n const resp = await this.provider.broadcastTransaction(signed);\n const hash = resp.hash as string;\n if (waitForReceipt) {\n await this.provider.waitForTransaction(hash);\n }\n return hash;\n }\n }\n\n return new EmblemEthersWalletImpl(config, provider as AbstractProvider | null, {\n address: info.evmAddress,\n vaultId: info.vaultId,\n });\n}\n"],"names":["async","emblemPost","path","body","config","baseUrl","authHeaders","getAuthHeaders","h","tok","jwt","getJwt","undefined","sdk","getSession","authToken","Authorization","apiKey","Error","resolveAuthHeaders","res","fetch","method","headers","JSON","stringify","_key","value","toString","ok","text","catch","status","errorMessage","substring","sanitizeErrorMessage","json","toSafeNumber","fieldName","num","Number","isSafeInteger","MAX_SAFE_INTEGER","toHexIfBigInt","v","fetchVaultInfo","data","vaultId","evmAddress","String","startsWith","tokenId","address","created_by","provider","infoOverride","ethers","Promise","AbstractSigner","resolveAddress","info","EmblemEthersWalletImpl","constructor","signerConfig","signerProvider","seed","super","this","_address","_vaultId","_chainId","_config","chainId","initialize","_initPromise","then","vaultInfo","err","getAddress","getVaultId","setChainId","getChainId","connect","newProvider","signMessage","message","payload","bytes","out","i","length","padStart","bytesToHex","signature","signTypedData","domain","types","cleanTypes","EIP712Domain","_signTypedData","signTransaction","tx","from","addr","toLowerCase","toSign","populateTransaction","to","nonce","normalized","gas","gasLimit","gasPrice","maxFeePerGas","maxPriorityFeePerGas","type","accessList","account","chain","normalizeTxForEmblem","transaction","options","signedTransaction","sendTransaction","signed","broadcastTransaction","fromAddress","BigInt","network","getNetwork","getTransactionCount","toAddress","estimateGas","getFeeData","populated","signAndBroadcast","waitForReceipt","hash","waitForTransaction"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ethers.mjs","sources":["../../src/signers/http.ts","../../src/signers/validation.ts","../../src/signers/utils.ts","../../src/signers/vault.ts","../../src/signers/ethers.ts"],"sourcesContent":["import type { SignerConfig } from '../types/signers';\n\nfunction sanitizeErrorMessage(status: number, text: string): string {\n // Sanitize error messages to avoid leaking sensitive server information\n let errorMessage = `Emblem signer error ${status}`;\n\n if (status >= 500) {\n errorMessage += ': Internal server error';\n } else if (status === 401 || status === 403) {\n errorMessage += ': Authentication failed';\n } else if (status === 404) {\n errorMessage += ': Resource not found';\n } else if (status === 405) {\n errorMessage += ': Method not allowed';\n } else if (text) {\n // For 4xx client errors, include limited error details\n errorMessage += `: ${text.substring(0, 200)}`; // Limit to 200 chars\n }\n\n return errorMessage;\n}\n\nasync function resolveAuthHeaders(config: SignerConfig): Promise<Record<string, string>> {\n // Priority: custom headers -> jwt/getJwt/sdk -> apiKey (deprecated)\n if (typeof config.getAuthHeaders === 'function') {\n const h = await config.getAuthHeaders();\n if (h && typeof h === 'object') return h;\n }\n\n const tok =\n config.jwt ??\n (typeof config.getJwt === 'function' ? await config.getJwt() : undefined) ??\n config.sdk?.getSession()?.authToken ??\n undefined;\n\n if (tok) {\n return { Authorization: `Bearer ${tok}` };\n }\n\n // apiKey is deprecated but still supported as fallback\n if (config.apiKey) {\n return { 'x-api-key': config.apiKey };\n }\n\n throw new Error(\n 'No authentication available: provide jwt, getJwt(), getAuthHeaders(), sdk, or apiKey'\n );\n}\n\nexport async function emblemPost<T = unknown>(\n path: string,\n body: unknown,\n config: SignerConfig\n): Promise<T> {\n const baseUrl = config.baseUrl ?? 'https://api.emblemvault.ai';\n const authHeaders = await resolveAuthHeaders(config);\n const res = await fetch(`${baseUrl}${path}`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...authHeaders,\n },\n body: JSON.stringify(body, (_key: string, value: unknown) =>\n typeof value === 'bigint' ? value.toString() : value\n ),\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(sanitizeErrorMessage(res.status, text));\n }\n\n return res.json() as Promise<T>;\n}\n\nexport async function emblemGet<T = unknown>(path: string, config: SignerConfig): Promise<T> {\n const baseUrl = config.baseUrl ?? 'https://api.emblemvault.ai';\n const authHeaders = await resolveAuthHeaders(config);\n const res = await fetch(`${baseUrl}${path}`, {\n method: 'GET',\n headers: authHeaders,\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(sanitizeErrorMessage(res.status, text));\n }\n\n return res.json() as Promise<T>;\n}\n","import type { SignerConfig } from '../types/signers';\n\n/**\n * Environment detection utilities for warning about unsafe usage patterns\n */\n\n/**\n * Detect if code is running in a browser environment\n */\nexport function isBrowserEnvironment(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Check if we're in a Node.js server environment\n */\nexport function isNodeEnvironment(): boolean {\n return (\n typeof process !== 'undefined' && process.versions != null && process.versions.node != null\n );\n}\n\n/**\n * Validate baseUrl format\n */\nexport function validateBaseUrl(baseUrl?: string): void {\n if (!baseUrl) return; // undefined is ok, will use default\n\n if (!baseUrl.startsWith('http://') && !baseUrl.startsWith('https://')) {\n throw new Error('baseUrl must be a valid HTTP(S) URL');\n }\n\n // Warn about http (not https)\n if (\n baseUrl.startsWith('http://') &&\n !baseUrl.includes('localhost') &&\n !baseUrl.includes('127.0.0.1')\n ) {\n console.warn(\n '[Emblem Security Warning] baseUrl uses HTTP instead of HTTPS. This is insecure for production use.'\n );\n }\n}\n\n/**\n * Validate Ethereum address format\n */\nexport function validateEthereumAddress(address: string): void {\n if (!address || typeof address !== 'string') {\n throw new Error('Address is required');\n }\n\n if (!address.startsWith('0x')) {\n throw new Error('Address must start with 0x');\n }\n\n if (!/^0x[0-9a-fA-F]{40}$/.test(address)) {\n throw new Error('Invalid Ethereum address format');\n }\n}\n\n/**\n * Validate vault ID\n */\nexport function validateVaultId(vaultId: string): void {\n if (!vaultId || typeof vaultId !== 'string') {\n throw new Error('vaultId is required');\n }\n\n if (vaultId.trim() === '') {\n throw new Error('vaultId cannot be empty');\n }\n}\n\n/**\n * Safe number conversion with bounds checking\n */\nexport function toSafeNumber(value: unknown, fieldName: string): number {\n const num = Number(value);\n\n if (!Number.isSafeInteger(num)) {\n throw new Error(\n `${fieldName} value ${value} exceeds safe integer range (max: ${Number.MAX_SAFE_INTEGER})`\n );\n }\n\n return num;\n}\n\n/**\n * Extended config with security options\n */\nexport interface SignerSecurityConfig extends SignerConfig {\n /**\n * Enable debug logging for security-related checks\n * @default false\n */\n debugSecurity?: boolean;\n}\n\n/**\n * Validate signer configuration\n */\nexport function validateSignerConfig(config: SignerSecurityConfig): void {\n // Validate auth: require at least one method (jwt, getJwt, getAuthHeaders)\n const hasJwt = !!config.jwt;\n const hasGetJwt = typeof config.getJwt === 'function';\n const hasHeaders = typeof config.getAuthHeaders === 'function';\n\n if (!hasJwt && !hasGetJwt && !hasHeaders) {\n throw new Error('Authentication required: provide jwt, getJwt(), or getAuthHeaders()');\n }\n\n // Validate baseUrl if provided\n if (config.baseUrl) {\n validateBaseUrl(config.baseUrl);\n }\n\n // Security audit logging\n if (config.debugSecurity) {\n console.log('[Emblem Security Debug]', {\n environment: isBrowserEnvironment() ? 'browser' : 'node',\n hasBaseUrl: !!config.baseUrl,\n timestamp: new Date().toISOString(),\n });\n }\n}\n","import type { Hex } from '../types/signers';\nimport { toSafeNumber } from './validation';\n\nexport function toHexIfBigInt(v: unknown): unknown {\n return typeof v === 'bigint' ? '0x' + v.toString(16) : v;\n}\n\n/**\n * viem txs sometimes have bigint / hex / optional fields. Ethers serializers\n * accept hex strings for numeric fields. Normalize where helpful.\n */\nexport function normalizeTxForEmblem(tx: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = { ...tx };\n\n if (out.value !== undefined) out.value = toHexIfBigInt(out.value);\n if (out.gas !== undefined) {\n out.gasLimit = toHexIfBigInt(out.gas);\n delete out.gas;\n }\n if (out.gasLimit !== undefined) out.gasLimit = toHexIfBigInt(out.gasLimit);\n if (out.gasPrice !== undefined) out.gasPrice = toHexIfBigInt(out.gasPrice);\n if (out.maxFeePerGas !== undefined) out.maxFeePerGas = toHexIfBigInt(out.maxFeePerGas);\n if (out.maxPriorityFeePerGas !== undefined)\n out.maxPriorityFeePerGas = toHexIfBigInt(out.maxPriorityFeePerGas);\n if (out.nonce !== undefined) out.nonce = toSafeNumber(out.nonce, 'nonce');\n if (out.chainId !== undefined) out.chainId = toSafeNumber(out.chainId, 'chainId');\n\n // Some backends only accept legacy fields; fold EIP-1559 into gasPrice and drop unsupported keys\n if (out.maxFeePerGas !== undefined || out.maxPriorityFeePerGas !== undefined) {\n if (out.gasPrice === undefined && out.maxFeePerGas !== undefined) {\n out.gasPrice = out.maxFeePerGas;\n }\n delete out.maxFeePerGas;\n delete out.maxPriorityFeePerGas;\n }\n\n // Remove fields commonly unsupported by legacy serializers\n delete out.type;\n delete out.accessList;\n delete out.account;\n delete out.chain;\n delete out.from;\n\n return out;\n}\n\nexport function isHexString(value: unknown): value is Hex {\n return typeof value === 'string' && /^0x[0-9a-fA-F]*$/.test(value);\n}\n\nexport function bytesToHex(bytes: ArrayLike<number>): Hex {\n let out = '0x';\n for (let i = 0; i < bytes.length; i++) {\n out += (bytes[i] as number).toString(16).padStart(2, '0');\n }\n return out as Hex;\n}\n","import type { SignerConfig, SignerVaultInfo, Hex } from '../types/signers';\nimport { emblemPost } from './http';\n\nexport async function fetchVaultInfo(config: SignerConfig): Promise<SignerVaultInfo> {\n // Note: The server only supports POST for /vault/info\n const data: Partial<{\n vaultId: string;\n address: string;\n evmAddress: Hex;\n created_by?: string;\n }> = await emblemPost('/vault/info', {}, config);\n\n // Validate required response data (vaultId + evmAddress are required for EVM)\n if (!data || !data.vaultId || !data.evmAddress) {\n throw new Error('Invalid vault info response: missing required fields');\n }\n\n if (!String(data.evmAddress).startsWith('0x')) {\n throw new Error('Invalid evmAddress format in response');\n }\n\n return {\n vaultId: data.vaultId,\n tokenId: data.vaultId,\n address: data.address || '', // Solana address may be absent; keep optional\n evmAddress: data.evmAddress as Hex,\n created_by: data.created_by,\n };\n}\n","import type { Hex, SignerConfig, SignerVaultInfo } from '../types/signers';\nimport { emblemPost } from './http';\nimport { bytesToHex, normalizeTxForEmblem } from './utils';\nimport { fetchVaultInfo } from './vault';\n\n// ethers v6 compatible interface (like solana pattern - no runtime dependency)\nexport interface EmblemEthersWallet {\n getAddress(): Promise<string>;\n signMessage(message: string | Uint8Array): Promise<string>;\n signTypedData(\n domain: unknown,\n types: Record<string, Array<{ name: string; type: string }>>,\n value: Record<string, unknown>\n ): Promise<string>;\n signTransaction(tx: unknown): Promise<string>;\n sendTransaction(tx: unknown): Promise<unknown>;\n connect(provider: unknown): EmblemEthersWallet;\n provider: unknown;\n // Additional methods\n initialize(): Promise<void>;\n getVaultId(): string;\n setChainId(chainId: number): void;\n getChainId(): number;\n signAndBroadcast(transaction: unknown, waitForReceipt?: boolean): Promise<string>;\n}\n\nexport async function toEthersWallet(\n config: SignerConfig,\n provider?: unknown | null,\n infoOverride?: SignerVaultInfo\n): Promise<EmblemEthersWallet> {\n // Dynamic import - only loads ethers when this function is called\n let ethers: typeof import('ethers');\n try {\n ethers = await import('ethers');\n } catch {\n throw new Error('ethers is required for toEthersWallet(). Install it with: npm install ethers');\n }\n\n const { AbstractSigner, resolveAddress } = ethers;\n type AbstractProvider = import('ethers').AbstractProvider;\n type TransactionRequest = import('ethers').TransactionRequest;\n type TransactionResponse = import('ethers').TransactionResponse;\n type TransactionLike = import('ethers').TransactionLike<string>;\n type TypedDataDomain = import('ethers').TypedDataDomain;\n type TypedDataField = import('ethers').TypedDataField;\n\n const info = infoOverride ?? (await fetchVaultInfo(config));\n\n // Class defined inside function after dynamic import\n class EmblemEthersWalletImpl extends AbstractSigner {\n private readonly _config: SignerConfig;\n private _address: Hex | null = null;\n private _vaultId: string | null = null;\n private _chainId = 1;\n private _initPromise?: Promise<void>;\n\n constructor(\n signerConfig: SignerConfig,\n signerProvider?: AbstractProvider | null,\n seed?: { address?: Hex; vaultId?: string; chainId?: number }\n ) {\n super(signerProvider ?? null);\n this._config = signerConfig;\n if (seed?.address) this._address = seed.address;\n if (seed?.vaultId) this._vaultId = seed.vaultId;\n if (seed?.chainId) this._chainId = seed.chainId;\n }\n\n async initialize(): Promise<void> {\n if (this._initPromise) return this._initPromise;\n\n this._initPromise = fetchVaultInfo(this._config)\n .then((vaultInfo) => {\n this._address = vaultInfo.evmAddress;\n this._vaultId = vaultInfo.vaultId;\n })\n .catch((err) => {\n this._initPromise = undefined;\n throw err;\n });\n\n return this._initPromise;\n }\n\n async getAddress(): Promise<string> {\n if (!this._address) await this.initialize();\n return this._address!;\n }\n\n getVaultId(): string {\n if (!this._vaultId) throw new Error('Wallet not initialized. Call initialize() first.');\n return this._vaultId;\n }\n\n setChainId(chainId: number): void {\n this._chainId = chainId;\n }\n\n getChainId(): number {\n return this._chainId;\n }\n\n connect(newProvider: AbstractProvider): EmblemEthersWalletImpl {\n if (!newProvider) throw new Error('Provider cannot be null');\n return new EmblemEthersWalletImpl(this._config, newProvider, {\n address: this._address ?? undefined,\n vaultId: this._vaultId ?? undefined,\n chainId: this._chainId,\n });\n }\n\n async signMessage(message: string | Uint8Array): Promise<string> {\n if (!this._vaultId) await this.initialize();\n const payload = typeof message === 'string' ? message : bytesToHex(message);\n const data = await emblemPost<{ signerAddress: string; signature: Hex }>(\n '/sign-eth-message',\n { vaultId: this._vaultId!, message: payload },\n this._config\n );\n return data.signature;\n }\n\n async signTypedData(\n domain: TypedDataDomain,\n types: Record<string, Array<TypedDataField>>,\n value: Record<string, unknown>\n ): Promise<string> {\n if (!this._vaultId) await this.initialize();\n const cleanTypes = { ...types };\n if (cleanTypes && (cleanTypes as Record<string, unknown>).EIP712Domain) {\n delete (cleanTypes as Record<string, unknown>).EIP712Domain;\n }\n const data = await emblemPost<{ signerAddress: string; signature: Hex }>(\n '/sign-typed-message',\n { vaultId: this._vaultId!, domain, types: cleanTypes, message: value },\n this._config\n );\n return data.signature;\n }\n\n async _signTypedData(\n domain: TypedDataDomain,\n types: Record<string, Array<TypedDataField>>,\n value: Record<string, unknown>\n ): Promise<string> {\n return this.signTypedData(domain, types, value);\n }\n\n async signTransaction(tx: TransactionRequest): Promise<string> {\n if (!this._vaultId) await this.initialize();\n const from = (tx as Record<string, unknown>).from as string | undefined;\n const addr = await this.getAddress();\n\n if (from && from.toLowerCase() !== addr.toLowerCase()) {\n throw new Error('transaction from does not match signer address');\n }\n\n const toSign = this.provider\n ? ({ ...await this.populateTransaction(tx) } as Record<string, unknown>)\n : ({ ...tx } as Record<string, unknown>);\n if (toSign.from) delete toSign.from;\n if (!('to' in toSign) || !toSign.to) {\n throw new Error(\"Transaction must have a 'to' address\");\n }\n if (toSign.nonce === undefined || toSign.nonce === null) {\n throw new Error('Transaction must have a nonce');\n }\n const normalized = normalizeTxForEmblem(toSign);\n const resp = await emblemPost<{ signedTransaction: Hex }>(\n '/sign-eth-tx',\n { vaultId: this._vaultId!, transaction: normalized, options: { chainId: this._chainId } },\n this._config\n );\n return resp.signedTransaction;\n }\n\n async sendTransaction(tx: TransactionRequest): Promise<TransactionResponse> {\n if (!this.provider) throw new Error('Provider required to send transaction');\n const signed = await this.signTransaction(tx);\n return await this.provider.broadcastTransaction(signed);\n }\n\n async populateTransaction(transaction: TransactionRequest): Promise<TransactionLike> {\n const tx = { ...transaction } as TransactionRequest;\n if (!this.provider) throw new Error('Provider required to populate transaction');\n const fromAddress = tx.from\n ? await resolveAddress(tx.from, this.provider)\n : await this.getAddress();\n\n let chainId: bigint;\n if (!tx.chainId) {\n const network = await this.provider.getNetwork();\n chainId = network.chainId;\n this._chainId = Number(network.chainId);\n } else {\n chainId = BigInt(tx.chainId);\n this._chainId = Number(tx.chainId);\n }\n\n const nonce =\n tx.nonce != null\n ? Number(tx.nonce)\n : await this.provider.getTransactionCount(fromAddress, 'pending');\n const toAddress = tx.to ? await resolveAddress(tx.to, this.provider) : null;\n const value = tx.value ? BigInt(tx.value.toString()) : 0n;\n\n let gasLimit: bigint;\n if (!tx.gasLimit) {\n try {\n gasLimit = await this.provider.estimateGas({ ...tx, from: fromAddress });\n } catch {\n gasLimit = 21000n;\n }\n } else {\n gasLimit = BigInt(tx.gasLimit.toString());\n }\n\n let gasPrice: bigint | null = null;\n if (!tx.gasPrice && tx.type !== 2) {\n const feeData = await this.provider.getFeeData();\n gasPrice = feeData.gasPrice ?? null;\n } else if (tx.gasPrice) {\n gasPrice = BigInt(tx.gasPrice.toString());\n }\n\n const populated: TransactionLike = {\n from: fromAddress,\n to: toAddress,\n value,\n nonce,\n gasLimit,\n data: tx.data as string | undefined,\n chainId,\n type: tx.type || undefined,\n };\n if (gasPrice !== null) populated.gasPrice = gasPrice;\n if (tx.maxFeePerGas) populated.maxFeePerGas = BigInt(tx.maxFeePerGas.toString());\n if (tx.maxPriorityFeePerGas)\n populated.maxPriorityFeePerGas = BigInt(tx.maxPriorityFeePerGas.toString());\n return populated;\n }\n\n async signAndBroadcast(\n transaction: TransactionRequest,\n waitForReceipt: boolean = false\n ): Promise<string> {\n if (!this.provider) throw new Error('Provider required to send transaction');\n const signed = await this.signTransaction(transaction);\n const resp = await this.provider.broadcastTransaction(signed);\n const hash = resp.hash as string;\n if (waitForReceipt) {\n await this.provider.waitForTransaction(hash);\n }\n return hash;\n }\n }\n\n return new EmblemEthersWalletImpl(config, provider as AbstractProvider | null, {\n address: info.evmAddress,\n vaultId: info.vaultId,\n });\n}\n"],"names":["async","emblemPost","path","body","config","baseUrl","authHeaders","getAuthHeaders","h","tok","jwt","getJwt","undefined","sdk","getSession","authToken","Authorization","apiKey","Error","resolveAuthHeaders","res","fetch","method","headers","JSON","stringify","_key","value","toString","ok","text","catch","status","errorMessage","substring","sanitizeErrorMessage","json","toSafeNumber","fieldName","num","Number","isSafeInteger","MAX_SAFE_INTEGER","toHexIfBigInt","v","fetchVaultInfo","data","vaultId","evmAddress","String","startsWith","tokenId","address","created_by","toEthersWallet","provider","infoOverride","ethers","import","AbstractSigner","resolveAddress","info","EmblemEthersWalletImpl","constructor","signerConfig","signerProvider","seed","super","this","_address","_vaultId","_chainId","_config","chainId","initialize","_initPromise","then","vaultInfo","err","getAddress","getVaultId","setChainId","getChainId","connect","newProvider","signMessage","message","payload","bytes","out","i","length","padStart","bytesToHex","signature","signTypedData","domain","types","cleanTypes","EIP712Domain","_signTypedData","signTransaction","tx","from","addr","toLowerCase","toSign","populateTransaction","to","nonce","normalized","gas","gasLimit","gasPrice","maxFeePerGas","maxPriorityFeePerGas","type","accessList","account","chain","normalizeTxForEmblem","transaction","options","signedTransaction","sendTransaction","signed","broadcastTransaction","fromAddress","BigInt","network","getNetwork","getTransactionCount","toAddress","estimateGas","getFeeData","populated","signAndBroadcast","waitForReceipt","hash","waitForTransaction"],"mappings":"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"}
1
+ {"version":3,"file":"ethers.mjs","sources":["../../src/signers/http.ts","../../src/signers/validation.ts","../../src/signers/utils.ts","../../src/signers/vault.ts","../../src/signers/ethers.ts"],"sourcesContent":["import type { SignerConfig } from '../types/signers';\n\nfunction sanitizeErrorMessage(status: number, text: string): string {\n // Sanitize error messages to avoid leaking sensitive server information\n let errorMessage = `Emblem signer error ${status}`;\n\n if (status >= 500) {\n errorMessage += ': Internal server error';\n } else if (status === 401 || status === 403) {\n errorMessage += ': Authentication failed';\n } else if (status === 404) {\n errorMessage += ': Resource not found';\n } else if (status === 405) {\n errorMessage += ': Method not allowed';\n } else if (text) {\n // For 4xx client errors, include limited error details\n errorMessage += `: ${text.substring(0, 200)}`; // Limit to 200 chars\n }\n\n return errorMessage;\n}\n\nasync function resolveAuthHeaders(config: SignerConfig): Promise<Record<string, string>> {\n // Priority: custom headers -> jwt/getJwt/sdk -> apiKey (deprecated)\n if (typeof config.getAuthHeaders === 'function') {\n const h = await config.getAuthHeaders();\n if (h && typeof h === 'object') return h;\n }\n\n const tok =\n config.jwt ??\n (typeof config.getJwt === 'function' ? await config.getJwt() : undefined) ??\n config.sdk?.getSession()?.authToken ??\n undefined;\n\n if (tok) {\n return { Authorization: `Bearer ${tok}` };\n }\n\n // apiKey is deprecated but still supported as fallback\n if (config.apiKey) {\n return { 'x-api-key': config.apiKey };\n }\n\n throw new Error(\n 'No authentication available: provide jwt, getJwt(), getAuthHeaders(), sdk, or apiKey'\n );\n}\n\nexport async function emblemPost<T = unknown>(\n path: string,\n body: unknown,\n config: SignerConfig\n): Promise<T> {\n const baseUrl = config.baseUrl ?? 'https://api.emblemvault.ai';\n const authHeaders = await resolveAuthHeaders(config);\n const res = await fetch(`${baseUrl}${path}`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...authHeaders,\n },\n body: JSON.stringify(body, (_key: string, value: unknown) =>\n typeof value === 'bigint' ? value.toString() : value\n ),\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(sanitizeErrorMessage(res.status, text));\n }\n\n return res.json() as Promise<T>;\n}\n\nexport async function emblemGet<T = unknown>(path: string, config: SignerConfig): Promise<T> {\n const baseUrl = config.baseUrl ?? 'https://api.emblemvault.ai';\n const authHeaders = await resolveAuthHeaders(config);\n const res = await fetch(`${baseUrl}${path}`, {\n method: 'GET',\n headers: authHeaders,\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(sanitizeErrorMessage(res.status, text));\n }\n\n return res.json() as Promise<T>;\n}\n","import type { SignerConfig } from '../types/signers';\n\n/**\n * Environment detection utilities for warning about unsafe usage patterns\n */\n\n/**\n * Detect if code is running in a browser environment\n */\nexport function isBrowserEnvironment(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Check if we're in a Node.js server environment\n */\nexport function isNodeEnvironment(): boolean {\n return (\n typeof process !== 'undefined' && process.versions != null && process.versions.node != null\n );\n}\n\n/**\n * Validate baseUrl format\n */\nexport function validateBaseUrl(baseUrl?: string): void {\n if (!baseUrl) return; // undefined is ok, will use default\n\n if (!baseUrl.startsWith('http://') && !baseUrl.startsWith('https://')) {\n throw new Error('baseUrl must be a valid HTTP(S) URL');\n }\n\n // Warn about http (not https)\n if (\n baseUrl.startsWith('http://') &&\n !baseUrl.includes('localhost') &&\n !baseUrl.includes('127.0.0.1')\n ) {\n console.warn(\n '[Emblem Security Warning] baseUrl uses HTTP instead of HTTPS. This is insecure for production use.'\n );\n }\n}\n\n/**\n * Validate Ethereum address format\n */\nexport function validateEthereumAddress(address: string): void {\n if (!address || typeof address !== 'string') {\n throw new Error('Address is required');\n }\n\n if (!address.startsWith('0x')) {\n throw new Error('Address must start with 0x');\n }\n\n if (!/^0x[0-9a-fA-F]{40}$/.test(address)) {\n throw new Error('Invalid Ethereum address format');\n }\n}\n\n/**\n * Validate vault ID\n */\nexport function validateVaultId(vaultId: string): void {\n if (!vaultId || typeof vaultId !== 'string') {\n throw new Error('vaultId is required');\n }\n\n if (vaultId.trim() === '') {\n throw new Error('vaultId cannot be empty');\n }\n}\n\n/**\n * Safe number conversion with bounds checking\n */\nexport function toSafeNumber(value: unknown, fieldName: string): number {\n const num = Number(value);\n\n if (!Number.isSafeInteger(num)) {\n throw new Error(\n `${fieldName} value ${value} exceeds safe integer range (max: ${Number.MAX_SAFE_INTEGER})`\n );\n }\n\n return num;\n}\n\n/**\n * Extended config with security options\n */\nexport interface SignerSecurityConfig extends SignerConfig {\n /**\n * Enable debug logging for security-related checks\n * @default false\n */\n debugSecurity?: boolean;\n}\n\n/**\n * Validate signer configuration\n */\nexport function validateSignerConfig(config: SignerSecurityConfig): void {\n // Validate auth: require at least one method (jwt, getJwt, getAuthHeaders)\n const hasJwt = !!config.jwt;\n const hasGetJwt = typeof config.getJwt === 'function';\n const hasHeaders = typeof config.getAuthHeaders === 'function';\n\n if (!hasJwt && !hasGetJwt && !hasHeaders) {\n throw new Error('Authentication required: provide jwt, getJwt(), or getAuthHeaders()');\n }\n\n // Validate baseUrl if provided\n if (config.baseUrl) {\n validateBaseUrl(config.baseUrl);\n }\n\n // Security audit logging\n if (config.debugSecurity) {\n console.log('[Emblem Security Debug]', {\n environment: isBrowserEnvironment() ? 'browser' : 'node',\n hasBaseUrl: !!config.baseUrl,\n timestamp: new Date().toISOString(),\n });\n }\n}\n","import type { Hex } from '../types/signers';\nimport { toSafeNumber } from './validation';\n\nexport function toHexIfBigInt(v: unknown): unknown {\n return typeof v === 'bigint' ? '0x' + v.toString(16) : v;\n}\n\n/**\n * viem txs sometimes have bigint / hex / optional fields. Ethers serializers\n * accept hex strings for numeric fields. Normalize where helpful.\n */\nexport function normalizeTxForEmblem(tx: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = { ...tx };\n\n if (out.value !== undefined) out.value = toHexIfBigInt(out.value);\n if (out.gas !== undefined) {\n out.gasLimit = toHexIfBigInt(out.gas);\n delete out.gas;\n }\n if (out.gasLimit !== undefined) out.gasLimit = toHexIfBigInt(out.gasLimit);\n if (out.gasPrice !== undefined) out.gasPrice = toHexIfBigInt(out.gasPrice);\n if (out.maxFeePerGas !== undefined) out.maxFeePerGas = toHexIfBigInt(out.maxFeePerGas);\n if (out.maxPriorityFeePerGas !== undefined)\n out.maxPriorityFeePerGas = toHexIfBigInt(out.maxPriorityFeePerGas);\n if (out.nonce !== undefined) out.nonce = toSafeNumber(out.nonce, 'nonce');\n if (out.chainId !== undefined) out.chainId = toSafeNumber(out.chainId, 'chainId');\n\n // Some backends only accept legacy fields; fold EIP-1559 into gasPrice and drop unsupported keys\n if (out.maxFeePerGas !== undefined || out.maxPriorityFeePerGas !== undefined) {\n if (out.gasPrice === undefined && out.maxFeePerGas !== undefined) {\n out.gasPrice = out.maxFeePerGas;\n }\n delete out.maxFeePerGas;\n delete out.maxPriorityFeePerGas;\n }\n\n // Remove fields commonly unsupported by legacy serializers\n delete out.type;\n delete out.accessList;\n delete out.account;\n delete out.chain;\n delete out.from;\n\n return out;\n}\n\nexport function isHexString(value: unknown): value is Hex {\n return typeof value === 'string' && /^0x[0-9a-fA-F]*$/.test(value);\n}\n\nexport function bytesToHex(bytes: ArrayLike<number>): Hex {\n let out = '0x';\n for (let i = 0; i < bytes.length; i++) {\n out += (bytes[i] as number).toString(16).padStart(2, '0');\n }\n return out as Hex;\n}\n","import type { SignerConfig, SignerVaultInfo, Hex } from '../types/signers';\nimport { emblemPost } from './http';\n\nexport async function fetchVaultInfo(config: SignerConfig): Promise<SignerVaultInfo> {\n // Note: The server only supports POST for /vault/info\n const data: Partial<{\n vaultId: string;\n address: string;\n evmAddress: Hex;\n created_by?: string;\n }> = await emblemPost('/vault/info', {}, config);\n\n // Validate required response data (vaultId + evmAddress are required for EVM)\n if (!data || !data.vaultId || !data.evmAddress) {\n throw new Error('Invalid vault info response: missing required fields');\n }\n\n if (!String(data.evmAddress).startsWith('0x')) {\n throw new Error('Invalid evmAddress format in response');\n }\n\n return {\n vaultId: data.vaultId,\n tokenId: data.vaultId,\n address: data.address || '', // Solana address may be absent; keep optional\n evmAddress: data.evmAddress as Hex,\n created_by: data.created_by,\n };\n}\n","import type { Hex, SignerConfig, SignerVaultInfo } from '../types/signers';\nimport { emblemPost } from './http';\nimport { bytesToHex, normalizeTxForEmblem } from './utils';\nimport { fetchVaultInfo } from './vault';\n\n// ethers v6 compatible interface (like solana pattern - no runtime dependency)\nexport interface EmblemEthersWallet {\n getAddress(): Promise<string>;\n signMessage(message: string | Uint8Array): Promise<string>;\n signTypedData(\n domain: unknown,\n types: Record<string, Array<{ name: string; type: string }>>,\n value: Record<string, unknown>\n ): Promise<string>;\n signTransaction(tx: unknown): Promise<string>;\n sendTransaction(tx: unknown): Promise<unknown>;\n connect(provider: unknown): EmblemEthersWallet;\n provider: unknown;\n // Additional methods\n initialize(): Promise<void>;\n getVaultId(): string;\n setChainId(chainId: number): void;\n getChainId(): number;\n signAndBroadcast(transaction: unknown, waitForReceipt?: boolean): Promise<string>;\n}\n\nexport async function toEthersWallet(\n config: SignerConfig,\n provider?: unknown | null,\n infoOverride?: SignerVaultInfo\n): Promise<EmblemEthersWallet> {\n // Dynamic import - only loads ethers when this function is called\n // webpackIgnore comment prevents webpack from trying to resolve at build time\n let ethers: typeof import('ethers');\n try {\n ethers = await import(/* webpackIgnore: true */ 'ethers');\n } catch {\n throw new Error('ethers is required for toEthersWallet(). Install it with: npm install ethers');\n }\n\n const { AbstractSigner, resolveAddress } = ethers;\n type AbstractProvider = import('ethers').AbstractProvider;\n type TransactionRequest = import('ethers').TransactionRequest;\n type TransactionResponse = import('ethers').TransactionResponse;\n type TransactionLike = import('ethers').TransactionLike<string>;\n type TypedDataDomain = import('ethers').TypedDataDomain;\n type TypedDataField = import('ethers').TypedDataField;\n\n const info = infoOverride ?? (await fetchVaultInfo(config));\n\n // Class defined inside function after dynamic import\n class EmblemEthersWalletImpl extends AbstractSigner {\n private readonly _config: SignerConfig;\n private _address: Hex | null = null;\n private _vaultId: string | null = null;\n private _chainId = 1;\n private _initPromise?: Promise<void>;\n\n constructor(\n signerConfig: SignerConfig,\n signerProvider?: AbstractProvider | null,\n seed?: { address?: Hex; vaultId?: string; chainId?: number }\n ) {\n super(signerProvider ?? null);\n this._config = signerConfig;\n if (seed?.address) this._address = seed.address;\n if (seed?.vaultId) this._vaultId = seed.vaultId;\n if (seed?.chainId) this._chainId = seed.chainId;\n }\n\n async initialize(): Promise<void> {\n if (this._initPromise) return this._initPromise;\n\n this._initPromise = fetchVaultInfo(this._config)\n .then((vaultInfo) => {\n this._address = vaultInfo.evmAddress;\n this._vaultId = vaultInfo.vaultId;\n })\n .catch((err) => {\n this._initPromise = undefined;\n throw err;\n });\n\n return this._initPromise;\n }\n\n async getAddress(): Promise<string> {\n if (!this._address) await this.initialize();\n return this._address!;\n }\n\n getVaultId(): string {\n if (!this._vaultId) throw new Error('Wallet not initialized. Call initialize() first.');\n return this._vaultId;\n }\n\n setChainId(chainId: number): void {\n this._chainId = chainId;\n }\n\n getChainId(): number {\n return this._chainId;\n }\n\n connect(newProvider: AbstractProvider): EmblemEthersWalletImpl {\n if (!newProvider) throw new Error('Provider cannot be null');\n return new EmblemEthersWalletImpl(this._config, newProvider, {\n address: this._address ?? undefined,\n vaultId: this._vaultId ?? undefined,\n chainId: this._chainId,\n });\n }\n\n async signMessage(message: string | Uint8Array): Promise<string> {\n if (!this._vaultId) await this.initialize();\n const payload = typeof message === 'string' ? message : bytesToHex(message);\n const data = await emblemPost<{ signerAddress: string; signature: Hex }>(\n '/sign-eth-message',\n { vaultId: this._vaultId!, message: payload },\n this._config\n );\n return data.signature;\n }\n\n async signTypedData(\n domain: TypedDataDomain,\n types: Record<string, Array<TypedDataField>>,\n value: Record<string, unknown>\n ): Promise<string> {\n if (!this._vaultId) await this.initialize();\n const cleanTypes = { ...types };\n if (cleanTypes && (cleanTypes as Record<string, unknown>).EIP712Domain) {\n delete (cleanTypes as Record<string, unknown>).EIP712Domain;\n }\n const data = await emblemPost<{ signerAddress: string; signature: Hex }>(\n '/sign-typed-message',\n { vaultId: this._vaultId!, domain, types: cleanTypes, message: value },\n this._config\n );\n return data.signature;\n }\n\n async _signTypedData(\n domain: TypedDataDomain,\n types: Record<string, Array<TypedDataField>>,\n value: Record<string, unknown>\n ): Promise<string> {\n return this.signTypedData(domain, types, value);\n }\n\n async signTransaction(tx: TransactionRequest): Promise<string> {\n if (!this._vaultId) await this.initialize();\n const from = (tx as Record<string, unknown>).from as string | undefined;\n const addr = await this.getAddress();\n\n if (from && from.toLowerCase() !== addr.toLowerCase()) {\n throw new Error('transaction from does not match signer address');\n }\n\n const toSign = this.provider\n ? ({ ...await this.populateTransaction(tx) } as Record<string, unknown>)\n : ({ ...tx } as Record<string, unknown>);\n if (toSign.from) delete toSign.from;\n if (!('to' in toSign) || !toSign.to) {\n throw new Error(\"Transaction must have a 'to' address\");\n }\n if (toSign.nonce === undefined || toSign.nonce === null) {\n throw new Error('Transaction must have a nonce');\n }\n const normalized = normalizeTxForEmblem(toSign);\n const resp = await emblemPost<{ signedTransaction: Hex }>(\n '/sign-eth-tx',\n { vaultId: this._vaultId!, transaction: normalized, options: { chainId: this._chainId } },\n this._config\n );\n return resp.signedTransaction;\n }\n\n async sendTransaction(tx: TransactionRequest): Promise<TransactionResponse> {\n if (!this.provider) throw new Error('Provider required to send transaction');\n const signed = await this.signTransaction(tx);\n return await this.provider.broadcastTransaction(signed);\n }\n\n async populateTransaction(transaction: TransactionRequest): Promise<TransactionLike> {\n const tx = { ...transaction } as TransactionRequest;\n if (!this.provider) throw new Error('Provider required to populate transaction');\n const fromAddress = tx.from\n ? await resolveAddress(tx.from, this.provider)\n : await this.getAddress();\n\n let chainId: bigint;\n if (!tx.chainId) {\n const network = await this.provider.getNetwork();\n chainId = network.chainId;\n this._chainId = Number(network.chainId);\n } else {\n chainId = BigInt(tx.chainId);\n this._chainId = Number(tx.chainId);\n }\n\n const nonce =\n tx.nonce != null\n ? Number(tx.nonce)\n : await this.provider.getTransactionCount(fromAddress, 'pending');\n const toAddress = tx.to ? await resolveAddress(tx.to, this.provider) : null;\n const value = tx.value ? BigInt(tx.value.toString()) : 0n;\n\n let gasLimit: bigint;\n if (!tx.gasLimit) {\n try {\n gasLimit = await this.provider.estimateGas({ ...tx, from: fromAddress });\n } catch {\n gasLimit = 21000n;\n }\n } else {\n gasLimit = BigInt(tx.gasLimit.toString());\n }\n\n let gasPrice: bigint | null = null;\n if (!tx.gasPrice && tx.type !== 2) {\n const feeData = await this.provider.getFeeData();\n gasPrice = feeData.gasPrice ?? null;\n } else if (tx.gasPrice) {\n gasPrice = BigInt(tx.gasPrice.toString());\n }\n\n const populated: TransactionLike = {\n from: fromAddress,\n to: toAddress,\n value,\n nonce,\n gasLimit,\n data: tx.data as string | undefined,\n chainId,\n type: tx.type || undefined,\n };\n if (gasPrice !== null) populated.gasPrice = gasPrice;\n if (tx.maxFeePerGas) populated.maxFeePerGas = BigInt(tx.maxFeePerGas.toString());\n if (tx.maxPriorityFeePerGas)\n populated.maxPriorityFeePerGas = BigInt(tx.maxPriorityFeePerGas.toString());\n return populated;\n }\n\n async signAndBroadcast(\n transaction: TransactionRequest,\n waitForReceipt: boolean = false\n ): Promise<string> {\n if (!this.provider) throw new Error('Provider required to send transaction');\n const signed = await this.signTransaction(transaction);\n const resp = await this.provider.broadcastTransaction(signed);\n const hash = resp.hash as string;\n if (waitForReceipt) {\n await this.provider.waitForTransaction(hash);\n }\n return hash;\n }\n }\n\n return new EmblemEthersWalletImpl(config, provider as AbstractProvider | null, {\n address: info.evmAddress,\n vaultId: info.vaultId,\n });\n}\n"],"names":["async","emblemPost","path","body","config","baseUrl","authHeaders","getAuthHeaders","h","tok","jwt","getJwt","undefined","sdk","getSession","authToken","Authorization","apiKey","Error","resolveAuthHeaders","res","fetch","method","headers","JSON","stringify","_key","value","toString","ok","text","catch","status","errorMessage","substring","sanitizeErrorMessage","json","toSafeNumber","fieldName","num","Number","isSafeInteger","MAX_SAFE_INTEGER","toHexIfBigInt","v","fetchVaultInfo","data","vaultId","evmAddress","String","startsWith","tokenId","address","created_by","toEthersWallet","provider","infoOverride","ethers","import","AbstractSigner","resolveAddress","info","EmblemEthersWalletImpl","constructor","signerConfig","signerProvider","seed","super","this","_address","_vaultId","_chainId","_config","chainId","initialize","_initPromise","then","vaultInfo","err","getAddress","getVaultId","setChainId","getChainId","connect","newProvider","signMessage","message","payload","bytes","out","i","length","padStart","bytesToHex","signature","signTypedData","domain","types","cleanTypes","EIP712Domain","_signTypedData","signTransaction","tx","from","addr","toLowerCase","toSign","populateTransaction","to","nonce","normalized","gas","gasLimit","gasPrice","maxFeePerGas","maxPriorityFeePerGas","type","accessList","account","chain","normalizeTxForEmblem","transaction","options","signedTransaction","sendTransaction","signed","broadcastTransaction","fromAddress","BigInt","network","getNetwork","getTransactionCount","toAddress","estimateGas","getFeeData","populated","signAndBroadcast","waitForReceipt","hash","waitForTransaction"],"mappings":"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"}