@unicitylabs/sphere-sdk 0.1.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../core/bech32.ts","../../l1/addressToScriptHash.ts","../../core/crypto.ts","../../l1/crypto.ts","../../l1/address.ts","../../l1/network.ts","../../l1/tx.ts","../../l1/vesting.ts","../../l1/vestingState.ts","../../l1/addressHelpers.ts","../../modules/payments/L1PaymentsModule.ts","../../modules/payments/TokenSplitCalculator.ts","../../modules/payments/TokenSplitExecutor.ts","../../modules/payments/NametagMinter.ts","../../constants.ts","../../types/txf.ts","../../serialization/txf-serializer.ts","../../modules/payments/PaymentsModule.ts","../../modules/communications/CommunicationsModule.ts","../../core/encryption.ts","../../serialization/wallet-text.ts","../../core/utils.ts","../../serialization/wallet-dat.ts","../../core/Sphere.ts","../../core/currency.ts"],"sourcesContent":["/**\n * Bech32 Encoding/Decoding\n * BIP-173 implementation for address encoding\n */\n\n// =============================================================================\n// Constants\n// =============================================================================\n\n/** Bech32 character set from BIP-173 */\nexport const CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';\n\n/** Generator polynomial for checksum */\nconst GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];\n\n// =============================================================================\n// Bit Conversion\n// =============================================================================\n\n/**\n * Convert between bit arrays (8→5 or 5→8)\n */\nexport function convertBits(\n data: number[],\n fromBits: number,\n toBits: number,\n pad: boolean\n): number[] | null {\n let acc = 0;\n let bits = 0;\n const ret: number[] = [];\n const maxv = (1 << toBits) - 1;\n\n for (let i = 0; i < data.length; i++) {\n const value = data[i];\n if (value < 0 || value >> fromBits !== 0) return null;\n acc = (acc << fromBits) | value;\n bits += fromBits;\n while (bits >= toBits) {\n bits -= toBits;\n ret.push((acc >> bits) & maxv);\n }\n }\n\n if (pad) {\n if (bits > 0) {\n ret.push((acc << (toBits - bits)) & maxv);\n }\n } else if (bits >= fromBits || (acc << (toBits - bits)) & maxv) {\n return null;\n }\n\n return ret;\n}\n\n// =============================================================================\n// Internal Functions\n// =============================================================================\n\n/**\n * Expand HRP for checksum calculation\n */\nfunction hrpExpand(hrp: string): number[] {\n const ret: number[] = [];\n for (let i = 0; i < hrp.length; i++) ret.push(hrp.charCodeAt(i) >> 5);\n ret.push(0);\n for (let i = 0; i < hrp.length; i++) ret.push(hrp.charCodeAt(i) & 31);\n return ret;\n}\n\n/**\n * Calculate polymod checksum\n */\nfunction bech32Polymod(values: number[]): number {\n let chk = 1;\n for (let p = 0; p < values.length; p++) {\n const top = chk >> 25;\n chk = ((chk & 0x1ffffff) << 5) ^ values[p];\n for (let i = 0; i < 5; i++) {\n if ((top >> i) & 1) chk ^= GENERATOR[i];\n }\n }\n return chk;\n}\n\n/**\n * Create checksum for bech32\n */\nfunction bech32Checksum(hrp: string, data: number[]): number[] {\n const values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]);\n const mod = bech32Polymod(values) ^ 1;\n\n const ret: number[] = [];\n for (let p = 0; p < 6; p++) {\n ret.push((mod >> (5 * (5 - p))) & 31);\n }\n return ret;\n}\n\n// =============================================================================\n// Public API\n// =============================================================================\n\n/**\n * Encode data to bech32 address\n *\n * @example\n * ```ts\n * const address = encodeBech32('alpha', 1, pubkeyHash);\n * // 'alpha1qw...'\n * ```\n */\nexport function encodeBech32(\n hrp: string,\n version: number,\n program: Uint8Array\n): string {\n if (version < 0 || version > 16) {\n throw new Error('Invalid witness version');\n }\n\n const converted = convertBits(Array.from(program), 8, 5, true);\n if (!converted) {\n throw new Error('Failed to convert bits');\n }\n\n const data = [version].concat(converted);\n const checksum = bech32Checksum(hrp, data);\n const combined = data.concat(checksum);\n\n let out = hrp + '1';\n for (let i = 0; i < combined.length; i++) {\n out += CHARSET[combined[i]];\n }\n\n return out;\n}\n\n/**\n * Decode bech32 address\n *\n * @example\n * ```ts\n * const result = decodeBech32('alpha1qw...');\n * // { hrp: 'alpha', witnessVersion: 1, data: Uint8Array }\n * ```\n */\nexport function decodeBech32(\n addr: string\n): { hrp: string; witnessVersion: number; data: Uint8Array } | null {\n addr = addr.toLowerCase();\n\n const pos = addr.lastIndexOf('1');\n if (pos < 1) return null;\n\n const hrp = addr.substring(0, pos);\n const dataStr = addr.substring(pos + 1);\n\n const data: number[] = [];\n for (let i = 0; i < dataStr.length; i++) {\n const val = CHARSET.indexOf(dataStr[i]);\n if (val === -1) return null;\n data.push(val);\n }\n\n // Validate checksum\n const checksum = bech32Checksum(hrp, data.slice(0, -6));\n for (let i = 0; i < 6; i++) {\n if (checksum[i] !== data[data.length - 6 + i]) {\n return null;\n }\n }\n\n const version = data[0];\n const program = convertBits(data.slice(1, -6), 5, 8, false);\n if (!program) return null;\n\n return {\n hrp,\n witnessVersion: version,\n data: Uint8Array.from(program),\n };\n}\n\n/**\n * Create address from public key hash\n *\n * @example\n * ```ts\n * const address = createAddress('alpha', pubkeyHash);\n * // 'alpha1...'\n * ```\n */\nexport function createAddress(hrp: string, pubkeyHash: Uint8Array | string): string {\n const hashBytes = typeof pubkeyHash === 'string'\n ? Uint8Array.from(Buffer.from(pubkeyHash, 'hex'))\n : pubkeyHash;\n\n return encodeBech32(hrp, 1, hashBytes);\n}\n\n/**\n * Validate bech32 address\n */\nexport function isValidBech32(addr: string): boolean {\n return decodeBech32(addr) !== null;\n}\n\n/**\n * Get HRP from address\n */\nexport function getAddressHrp(addr: string): string | null {\n const result = decodeBech32(addr);\n return result?.hrp ?? null;\n}\n\n// =============================================================================\n// Aliases for L1 SDK compatibility\n// =============================================================================\n\n/**\n * Alias for encodeBech32 (L1 SDK compatibility)\n */\nexport const createBech32 = encodeBech32;\n","import { decodeBech32 } from \"../core/bech32\";\nimport CryptoJS from \"crypto-js\";\n\n/** Convert bytes to hex */\nfunction bytesToHex(buf: Uint8Array) {\n return Array.from(buf)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/**\n * Convert \"alpha1xxxx\" Bech32 → Electrum script hash\n * Required for:\n * - blockchain.scripthash.get_history\n * - blockchain.scripthash.listunspent\n */\nexport function addressToScriptHash(address: string): string {\n const decoded = decodeBech32(address);\n if (!decoded) throw new Error(\"Invalid bech32 address: \" + address);\n\n // witness program always starts with OP_0 + PUSH20 (for P2WPKH)\n const scriptHex = \"0014\" + bytesToHex(decoded.data);\n\n // SHA256\n const sha = CryptoJS.SHA256(CryptoJS.enc.Hex.parse(scriptHex)).toString();\n\n // Electrum requires reversed byte order\n return sha.match(/../g)!.reverse().join(\"\");\n}\n","/**\n * Cryptographic utilities for SDK2\n *\n * Provides BIP39 mnemonic and BIP32 key derivation functions.\n * Platform-independent - no browser-specific APIs.\n */\n\nimport * as bip39 from 'bip39';\nimport CryptoJS from 'crypto-js';\nimport elliptic from 'elliptic';\nimport { encodeBech32 } from './bech32';\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst ec = new elliptic.ec('secp256k1');\n\n/** secp256k1 curve order */\nconst CURVE_ORDER = BigInt(\n '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141'\n);\n\n/** Default derivation path for Unicity (BIP44) */\nexport const DEFAULT_DERIVATION_PATH = \"m/44'/0'/0'\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface MasterKey {\n privateKey: string;\n chainCode: string;\n}\n\nexport interface DerivedKey {\n privateKey: string;\n chainCode: string;\n}\n\nexport interface KeyPair {\n privateKey: string;\n publicKey: string;\n}\n\nexport interface AddressInfo extends KeyPair {\n address: string;\n path: string;\n index: number;\n}\n\n// =============================================================================\n// BIP39 Mnemonic Functions\n// =============================================================================\n\n/**\n * Generate a new BIP39 mnemonic phrase\n * @param strength - Entropy bits (128 = 12 words, 256 = 24 words)\n */\nexport function generateMnemonic(strength: 128 | 256 = 128): string {\n return bip39.generateMnemonic(strength);\n}\n\n/**\n * Validate a BIP39 mnemonic phrase\n */\nexport function validateMnemonic(mnemonic: string): boolean {\n return bip39.validateMnemonic(mnemonic);\n}\n\n/**\n * Convert mnemonic to seed (64-byte hex string)\n * @param mnemonic - BIP39 mnemonic phrase\n * @param passphrase - Optional passphrase for additional security\n */\nexport async function mnemonicToSeed(\n mnemonic: string,\n passphrase: string = ''\n): Promise<string> {\n const seedBuffer = await bip39.mnemonicToSeed(mnemonic, passphrase);\n return Buffer.from(seedBuffer).toString('hex');\n}\n\n/**\n * Synchronous version of mnemonicToSeed\n */\nexport function mnemonicToSeedSync(\n mnemonic: string,\n passphrase: string = ''\n): string {\n const seedBuffer = bip39.mnemonicToSeedSync(mnemonic, passphrase);\n return Buffer.from(seedBuffer).toString('hex');\n}\n\n/**\n * Convert mnemonic to entropy (for recovery purposes)\n */\nexport function mnemonicToEntropy(mnemonic: string): string {\n return bip39.mnemonicToEntropy(mnemonic);\n}\n\n/**\n * Convert entropy to mnemonic\n */\nexport function entropyToMnemonic(entropy: string): string {\n return bip39.entropyToMnemonic(entropy);\n}\n\n// =============================================================================\n// BIP32 Key Derivation\n// =============================================================================\n\n/**\n * Generate master key from seed (BIP32 standard)\n * Uses HMAC-SHA512 with key \"Bitcoin seed\"\n */\nexport function generateMasterKey(seedHex: string): MasterKey {\n const I = CryptoJS.HmacSHA512(\n CryptoJS.enc.Hex.parse(seedHex),\n CryptoJS.enc.Utf8.parse('Bitcoin seed')\n ).toString();\n\n const IL = I.substring(0, 64); // Left 32 bytes - master private key\n const IR = I.substring(64); // Right 32 bytes - master chain code\n\n // Validate master key\n const masterKeyBigInt = BigInt('0x' + IL);\n if (masterKeyBigInt === 0n || masterKeyBigInt >= CURVE_ORDER) {\n throw new Error('Invalid master key generated');\n }\n\n return {\n privateKey: IL,\n chainCode: IR,\n };\n}\n\n/**\n * Derive child key using BIP32 standard\n * @param parentPrivKey - Parent private key (64 hex chars)\n * @param parentChainCode - Parent chain code (64 hex chars)\n * @param index - Child index (>= 0x80000000 for hardened)\n */\nexport function deriveChildKey(\n parentPrivKey: string,\n parentChainCode: string,\n index: number\n): DerivedKey {\n const isHardened = index >= 0x80000000;\n let data: string;\n\n if (isHardened) {\n // Hardened derivation: 0x00 || parentPrivKey || index\n const indexHex = index.toString(16).padStart(8, '0');\n data = '00' + parentPrivKey + indexHex;\n } else {\n // Non-hardened derivation: compressedPubKey || index\n const keyPair = ec.keyFromPrivate(parentPrivKey, 'hex');\n const compressedPubKey = keyPair.getPublic(true, 'hex');\n const indexHex = index.toString(16).padStart(8, '0');\n data = compressedPubKey + indexHex;\n }\n\n // HMAC-SHA512 with chain code as key\n const I = CryptoJS.HmacSHA512(\n CryptoJS.enc.Hex.parse(data),\n CryptoJS.enc.Hex.parse(parentChainCode)\n ).toString();\n\n const IL = I.substring(0, 64); // Left 32 bytes\n const IR = I.substring(64); // Right 32 bytes (new chain code)\n\n // Add IL to parent key mod n (curve order)\n const ilBigInt = BigInt('0x' + IL);\n const parentKeyBigInt = BigInt('0x' + parentPrivKey);\n\n // Check IL is valid (less than curve order)\n if (ilBigInt >= CURVE_ORDER) {\n throw new Error('Invalid key: IL >= curve order');\n }\n\n const childKeyBigInt = (ilBigInt + parentKeyBigInt) % CURVE_ORDER;\n\n // Check child key is valid (not zero)\n if (childKeyBigInt === 0n) {\n throw new Error('Invalid key: child key is zero');\n }\n\n const childPrivKey = childKeyBigInt.toString(16).padStart(64, '0');\n\n return {\n privateKey: childPrivKey,\n chainCode: IR,\n };\n}\n\n/**\n * Derive key at a full BIP32/BIP44 path\n * @param masterPrivKey - Master private key\n * @param masterChainCode - Master chain code\n * @param path - BIP44 path like \"m/44'/0'/0'/0/0\"\n */\nexport function deriveKeyAtPath(\n masterPrivKey: string,\n masterChainCode: string,\n path: string\n): DerivedKey {\n const pathParts = path.replace('m/', '').split('/');\n\n let currentKey = masterPrivKey;\n let currentChainCode = masterChainCode;\n\n for (const part of pathParts) {\n const isHardened = part.endsWith(\"'\") || part.endsWith('h');\n const indexStr = part.replace(/['h]$/, '');\n let index = parseInt(indexStr, 10);\n\n if (isHardened) {\n index += 0x80000000; // Add hardened offset\n }\n\n const derived = deriveChildKey(currentKey, currentChainCode, index);\n currentKey = derived.privateKey;\n currentChainCode = derived.chainCode;\n }\n\n return {\n privateKey: currentKey,\n chainCode: currentChainCode,\n };\n}\n\n// =============================================================================\n// Key Pair Operations\n// =============================================================================\n\n/**\n * Get public key from private key\n * @param privateKey - Private key as hex string\n * @param compressed - Return compressed public key (default: true)\n */\nexport function getPublicKey(privateKey: string, compressed: boolean = true): string {\n const keyPair = ec.keyFromPrivate(privateKey, 'hex');\n return keyPair.getPublic(compressed, 'hex');\n}\n\n/**\n * Create key pair from private key\n */\nexport function createKeyPair(privateKey: string): KeyPair {\n return {\n privateKey,\n publicKey: getPublicKey(privateKey),\n };\n}\n\n// =============================================================================\n// Hash Functions\n// =============================================================================\n\n/**\n * Compute SHA256 hash\n */\nexport function sha256(data: string, inputEncoding: 'hex' | 'utf8' = 'hex'): string {\n const parsed =\n inputEncoding === 'hex'\n ? CryptoJS.enc.Hex.parse(data)\n : CryptoJS.enc.Utf8.parse(data);\n return CryptoJS.SHA256(parsed).toString();\n}\n\n/**\n * Compute RIPEMD160 hash\n */\nexport function ripemd160(data: string, inputEncoding: 'hex' | 'utf8' = 'hex'): string {\n const parsed =\n inputEncoding === 'hex'\n ? CryptoJS.enc.Hex.parse(data)\n : CryptoJS.enc.Utf8.parse(data);\n return CryptoJS.RIPEMD160(parsed).toString();\n}\n\n/**\n * Compute HASH160 (SHA256 -> RIPEMD160)\n */\nexport function hash160(data: string): string {\n const sha = sha256(data, 'hex');\n return ripemd160(sha, 'hex');\n}\n\n/**\n * Compute double SHA256\n */\nexport function doubleSha256(data: string, inputEncoding: 'hex' | 'utf8' = 'hex'): string {\n const first = sha256(data, inputEncoding);\n return sha256(first, 'hex');\n}\n\n/**\n * Alias for hash160 (L1 SDK compatibility)\n */\nexport const computeHash160 = hash160;\n\n/**\n * Convert hex string to Uint8Array for witness program\n */\nexport function hash160ToBytes(hash160Hex: string): Uint8Array {\n const matches = hash160Hex.match(/../g);\n if (!matches) return new Uint8Array(0);\n return Uint8Array.from(matches.map((x) => parseInt(x, 16)));\n}\n\n/**\n * Generate bech32 address from public key\n * @param publicKey - Compressed public key as hex string\n * @param prefix - Address prefix (default: \"alpha\")\n * @param witnessVersion - Witness version (default: 0 for P2WPKH)\n * @returns Bech32 encoded address\n */\nexport function publicKeyToAddress(\n publicKey: string,\n prefix: string = 'alpha',\n witnessVersion: number = 0\n): string {\n const pubKeyHash = hash160(publicKey);\n const programBytes = hash160ToBytes(pubKeyHash);\n return encodeBech32(prefix, witnessVersion, programBytes);\n}\n\n/**\n * Get address info from private key\n */\nexport function privateKeyToAddressInfo(\n privateKey: string,\n prefix: string = 'alpha'\n): { address: string; publicKey: string } {\n const publicKey = getPublicKey(privateKey);\n const address = publicKeyToAddress(publicKey, prefix);\n return { address, publicKey };\n}\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\n/**\n * Convert hex string to Uint8Array\n */\nexport function hexToBytes(hex: string): Uint8Array {\n const matches = hex.match(/../g);\n if (!matches) {\n return new Uint8Array(0);\n }\n return Uint8Array.from(matches.map((x) => parseInt(x, 16)));\n}\n\n/**\n * Convert Uint8Array to hex string\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/**\n * Generate random bytes as hex string\n */\nexport function randomBytes(length: number): string {\n const words = CryptoJS.lib.WordArray.random(length);\n return words.toString(CryptoJS.enc.Hex);\n}\n\n// =============================================================================\n// High-Level Functions\n// =============================================================================\n\n/**\n * Generate identity from mnemonic\n * Returns master key derived from mnemonic seed\n */\nexport async function identityFromMnemonic(\n mnemonic: string,\n passphrase: string = ''\n): Promise<MasterKey> {\n if (!validateMnemonic(mnemonic)) {\n throw new Error('Invalid mnemonic phrase');\n }\n const seedHex = await mnemonicToSeed(mnemonic, passphrase);\n return generateMasterKey(seedHex);\n}\n\n/**\n * Synchronous version of identityFromMnemonic\n */\nexport function identityFromMnemonicSync(\n mnemonic: string,\n passphrase: string = ''\n): MasterKey {\n if (!validateMnemonic(mnemonic)) {\n throw new Error('Invalid mnemonic phrase');\n }\n const seedHex = mnemonicToSeedSync(mnemonic, passphrase);\n return generateMasterKey(seedHex);\n}\n\n/**\n * Derive address info at a specific path\n * @param masterKey - Master key with privateKey and chainCode\n * @param basePath - Base derivation path (e.g., \"m/44'/0'/0'\")\n * @param index - Address index\n * @param isChange - Whether this is a change address (chain 1 vs 0)\n * @param prefix - Address prefix (default: \"alpha\")\n */\nexport function deriveAddressInfo(\n masterKey: MasterKey,\n basePath: string,\n index: number,\n isChange: boolean = false,\n prefix: string = 'alpha'\n): AddressInfo {\n const chain = isChange ? 1 : 0;\n const fullPath = `${basePath}/${chain}/${index}`;\n\n const derived = deriveKeyAtPath(masterKey.privateKey, masterKey.chainCode, fullPath);\n const publicKey = getPublicKey(derived.privateKey);\n const address = publicKeyToAddress(publicKey, prefix);\n\n return {\n privateKey: derived.privateKey,\n publicKey,\n address,\n path: fullPath,\n index,\n };\n}\n\n/**\n * Generate full address info from private key with index and path\n * (L1 SDK compatibility)\n */\nexport function generateAddressInfo(\n privateKey: string,\n index: number,\n path: string,\n prefix: string = 'alpha'\n): AddressInfo {\n const { address, publicKey } = privateKeyToAddressInfo(privateKey, prefix);\n return {\n privateKey,\n publicKey,\n address,\n path,\n index,\n };\n}\n\n// Re-export elliptic instance for advanced use cases\nexport { ec };\n","import CryptoJS from \"crypto-js\";\n\nconst SALT = \"alpha_wallet_salt\";\nconst PBKDF2_ITERATIONS = 100000;\n\nexport function encrypt(text: string, password: string): string {\n return CryptoJS.AES.encrypt(text, password).toString();\n}\n\nexport function decrypt(encrypted: string, password: string): string {\n const bytes = CryptoJS.AES.decrypt(encrypted, password);\n return bytes.toString(CryptoJS.enc.Utf8);\n}\n\nexport function generatePrivateKey(): string {\n return CryptoJS.lib.WordArray.random(32).toString();\n}\n\n/**\n * Encrypt wallet master key with password using PBKDF2 + AES\n */\nexport function encryptWallet(\n masterPrivateKey: string,\n password: string\n): string {\n const passwordKey = CryptoJS.PBKDF2(password, SALT, {\n keySize: 256 / 32,\n iterations: PBKDF2_ITERATIONS,\n }).toString();\n\n const encrypted = CryptoJS.AES.encrypt(\n masterPrivateKey,\n passwordKey\n ).toString();\n\n return encrypted;\n}\n\n/**\n * Decrypt wallet master key with password\n */\nexport function decryptWallet(\n encryptedData: string,\n password: string\n): string {\n const passwordKey = CryptoJS.PBKDF2(password, SALT, {\n keySize: 256 / 32,\n iterations: PBKDF2_ITERATIONS,\n }).toString();\n\n const decrypted = CryptoJS.AES.decrypt(encryptedData, passwordKey);\n return decrypted.toString(CryptoJS.enc.Utf8);\n}\n\n/**\n * Convert hex private key to WIF format\n */\nexport function hexToWIF(hexKey: string): string {\n // Alpha mainnet version byte is 0x80\n const versionByte = \"80\";\n const extendedKey = versionByte + hexKey;\n\n // Calculate checksum\n const hash1 = CryptoJS.SHA256(CryptoJS.enc.Hex.parse(extendedKey)).toString();\n const hash2 = CryptoJS.SHA256(CryptoJS.enc.Hex.parse(hash1)).toString();\n const checksum = hash2.substring(0, 8);\n\n // Combine and encode\n const finalHex = extendedKey + checksum;\n\n // Convert to Base58\n return base58Encode(finalHex);\n}\n\n/**\n * Base58 encoding\n */\nfunction base58Encode(hex: string): string {\n const ALPHABET = \"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz\";\n\n // Convert hex to big integer\n let num = BigInt(\"0x\" + hex);\n let encoded = \"\";\n\n while (num > 0n) {\n const remainder = Number(num % 58n);\n num = num / 58n;\n encoded = ALPHABET[remainder] + encoded;\n }\n\n // Add leading 1s for leading 0s in hex\n for (let i = 0; i < hex.length && hex.substring(i, i + 2) === \"00\"; i += 2) {\n encoded = \"1\" + encoded;\n }\n\n return encoded;\n}\n","/**\n * L1 Address Derivation\n *\n * Uses core crypto functions for standard BIP32 derivation,\n * plus legacy functions for backward compatibility with old wallets.\n */\n\nimport CryptoJS from 'crypto-js';\nimport {\n deriveChildKey as coreDeriveChildKey,\n deriveKeyAtPath as coreDeriveKeyAtPath,\n generateMasterKey,\n generateAddressInfo,\n ec,\n} from '../core/crypto';\n\n// Re-export core functions with L1 naming conventions\nexport { ec };\n\n/**\n * Standard BIP32 child key derivation\n * Re-export from core with L1 naming convention\n */\nexport const deriveChildKeyBIP32 = coreDeriveChildKey;\n\n/**\n * Derive key at a full BIP44 path\n * Re-export from core\n */\nexport const deriveKeyAtPath = coreDeriveKeyAtPath;\n\n/**\n * Generate master key and chain code from seed (BIP32 standard)\n * Wrapper around core function with L1 return type naming\n */\nexport function generateMasterKeyFromSeed(seedHex: string): {\n masterPrivateKey: string;\n masterChainCode: string;\n} {\n const result = generateMasterKey(seedHex);\n return {\n masterPrivateKey: result.privateKey,\n masterChainCode: result.chainCode,\n };\n}\n\n/**\n * Generate HD address using standard BIP32\n * Standard path: m/44'/0'/0'/0/{index} (external chain, non-hardened)\n * For change addresses, use isChange = true to get m/44'/0'/0'/1/{index}\n */\nexport function generateHDAddressBIP32(\n masterPriv: string,\n chainCode: string,\n index: number,\n basePath: string = \"m/44'/0'/0'\",\n isChange: boolean = false\n) {\n // Chain: 0 = external (receiving), 1 = internal (change)\n const chain = isChange ? 1 : 0;\n const fullPath = `${basePath}/${chain}/${index}`;\n\n const derived = coreDeriveKeyAtPath(masterPriv, chainCode, fullPath);\n\n return generateAddressInfo(derived.privateKey, index, fullPath);\n}\n\n// ============================================\n// Original index.html compatible derivation\n// ============================================\n\n/**\n * Generate address from master private key using HMAC-SHA512 derivation\n * This matches exactly the original index.html implementation\n * NOTE: This is NON-STANDARD derivation for legacy wallet compatibility\n *\n * @param masterPrivateKey - 32-byte hex private key (64 chars)\n * @param index - Address index\n */\nexport function generateAddressFromMasterKey(\n masterPrivateKey: string,\n index: number\n) {\n const derivationPath = `m/44'/0'/${index}'`;\n\n // HMAC-SHA512 with path as key (matching index.html exactly)\n const hmacInput = CryptoJS.enc.Hex.parse(masterPrivateKey);\n const hmacKey = CryptoJS.enc.Utf8.parse(derivationPath);\n const hmacOutput = CryptoJS.HmacSHA512(hmacInput, hmacKey).toString();\n\n // Use left 32 bytes for private key\n const childPrivateKey = hmacOutput.substring(0, 64);\n\n return generateAddressInfo(childPrivateKey, index, derivationPath);\n}\n\n// ============================================\n// Legacy functions for backward compatibility\n// ============================================\n\n/**\n * @deprecated Use deriveChildKeyBIP32 for new wallets\n * Legacy HMAC-SHA512 derivation (non-standard)\n * Kept for backward compatibility with old wallets\n */\nexport function deriveChildKey(\n masterPriv: string,\n chainCode: string,\n index: number\n) {\n const data = masterPriv + index.toString(16).padStart(8, '0');\n\n const I = CryptoJS.HmacSHA512(\n CryptoJS.enc.Hex.parse(data),\n CryptoJS.enc.Hex.parse(chainCode)\n ).toString();\n\n return {\n privateKey: I.substring(0, 64),\n nextChainCode: I.substring(64),\n };\n}\n\n/**\n * @deprecated Use generateHDAddressBIP32 for new wallets\n * Legacy HD address generation (non-standard derivation)\n */\nexport function generateHDAddress(\n masterPriv: string,\n chainCode: string,\n index: number\n) {\n const child = deriveChildKey(masterPriv, chainCode, index);\n const path = `m/44'/0'/0'/${index}`;\n\n return generateAddressInfo(child.privateKey, index, path);\n}\n","// L1 Network - Fulcrum WebSocket client\n\nimport { addressToScriptHash } from './addressToScriptHash';\nimport type { UTXO } from './types';\n\nconst DEFAULT_ENDPOINT = 'wss://fulcrum.unicity.network:50004';\n\ninterface PendingRequest {\n resolve: (result: unknown) => void;\n reject: (err: unknown) => void;\n}\n\nexport interface BlockHeader {\n height: number;\n hex: string;\n [key: string]: unknown;\n}\n\ninterface BalanceResult {\n confirmed: number;\n unconfirmed: number;\n}\n\nlet ws: WebSocket | null = null;\nlet isConnected = false;\nlet isConnecting = false;\nlet requestId = 0;\nlet intentionalClose = false;\nlet reconnectAttempts = 0;\nlet isBlockSubscribed = false;\nlet lastBlockHeader: BlockHeader | null = null;\n\n// Store timeout IDs for pending requests\ninterface PendingRequestWithTimeout extends PendingRequest {\n timeoutId?: ReturnType<typeof setTimeout>;\n}\n\nconst pending: Record<number, PendingRequestWithTimeout> = {};\nconst blockSubscribers: ((header: BlockHeader) => void)[] = [];\n\n// Connection state callbacks with cleanup support\ninterface ConnectionCallback {\n resolve: () => void;\n reject: (err: Error) => void;\n timeoutId?: ReturnType<typeof setTimeout>;\n}\nconst connectionCallbacks: ConnectionCallback[] = [];\n\n// Reconnect configuration\nconst MAX_RECONNECT_ATTEMPTS = 10;\nconst BASE_DELAY = 2000;\nconst MAX_DELAY = 60000; // 1 minute\n\n// Timeout configuration\nconst RPC_TIMEOUT = 30000; // 30 seconds\nconst CONNECTION_TIMEOUT = 30000; // 30 seconds\n\n// ----------------------------------------\n// CONNECTION STATE\n// ----------------------------------------\nexport function isWebSocketConnected(): boolean {\n return isConnected && ws !== null && ws.readyState === WebSocket.OPEN;\n}\n\nexport function waitForConnection(): Promise<void> {\n if (isWebSocketConnected()) {\n return Promise.resolve();\n }\n\n return new Promise((resolve, reject) => {\n const callback: ConnectionCallback = {\n resolve: () => {\n if (callback.timeoutId) clearTimeout(callback.timeoutId);\n resolve();\n },\n reject: (err: Error) => {\n if (callback.timeoutId) clearTimeout(callback.timeoutId);\n reject(err);\n },\n };\n\n callback.timeoutId = setTimeout(() => {\n // Remove from callbacks array\n const idx = connectionCallbacks.indexOf(callback);\n if (idx > -1) connectionCallbacks.splice(idx, 1);\n reject(new Error('Connection timeout'));\n }, CONNECTION_TIMEOUT);\n\n connectionCallbacks.push(callback);\n });\n}\n\n// ----------------------------------------\n// SINGLETON CONNECT — prevents double connect\n// ----------------------------------------\nexport function connect(endpoint: string = DEFAULT_ENDPOINT): Promise<void> {\n if (isConnected) {\n return Promise.resolve();\n }\n\n if (isConnecting) {\n return waitForConnection();\n }\n\n isConnecting = true;\n\n return new Promise((resolve, reject) => {\n let hasResolved = false;\n\n try {\n ws = new WebSocket(endpoint);\n } catch (err) {\n console.error('[L1] WebSocket constructor threw exception:', err);\n isConnecting = false;\n reject(err);\n return;\n }\n\n ws.onopen = () => {\n isConnected = true;\n isConnecting = false;\n reconnectAttempts = 0; // Reset reconnect counter on successful connection\n hasResolved = true;\n resolve();\n\n // Notify all waiting callbacks (clear their timeouts first)\n connectionCallbacks.forEach((cb) => {\n if (cb.timeoutId) clearTimeout(cb.timeoutId);\n cb.resolve();\n });\n connectionCallbacks.length = 0;\n };\n\n ws.onclose = () => {\n isConnected = false;\n isBlockSubscribed = false; // Reset block subscription on disconnect\n\n // Reject all pending requests and clear their timeouts\n Object.values(pending).forEach((req) => {\n if (req.timeoutId) clearTimeout(req.timeoutId);\n req.reject(new Error('WebSocket connection closed'));\n });\n Object.keys(pending).forEach((key) => delete pending[Number(key)]);\n\n // Don't reconnect if this was an intentional close\n if (intentionalClose) {\n intentionalClose = false;\n isConnecting = false;\n reconnectAttempts = 0;\n\n // Reject if we haven't resolved yet\n if (!hasResolved) {\n hasResolved = true;\n reject(new Error('WebSocket connection closed intentionally'));\n }\n return;\n }\n\n // Check if we've exceeded max reconnect attempts\n if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {\n console.error('[L1] Max reconnect attempts reached. Giving up.');\n isConnecting = false;\n\n // Reject all waiting callbacks\n const error = new Error('Max reconnect attempts reached');\n connectionCallbacks.forEach((cb) => {\n if (cb.timeoutId) clearTimeout(cb.timeoutId);\n cb.reject(error);\n });\n connectionCallbacks.length = 0;\n\n // Reject if we haven't resolved yet\n if (!hasResolved) {\n hasResolved = true;\n reject(error);\n }\n return;\n }\n\n // Calculate exponential backoff delay\n const delay = Math.min(BASE_DELAY * Math.pow(2, reconnectAttempts), MAX_DELAY);\n\n reconnectAttempts++;\n console.warn(\n `[L1] WebSocket closed unexpectedly. Reconnecting in ${delay}ms (attempt ${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})...`\n );\n\n // Keep isConnecting true so callers know reconnection is in progress\n // The resolve/reject will happen when reconnection succeeds or fails\n setTimeout(() => {\n connect(endpoint)\n .then(() => {\n if (!hasResolved) {\n hasResolved = true;\n resolve();\n }\n })\n .catch((err) => {\n if (!hasResolved) {\n hasResolved = true;\n reject(err);\n }\n });\n }, delay);\n };\n\n ws.onerror = (err: Event) => {\n console.error('[L1] WebSocket error:', err);\n // Note: Browser WebSocket errors don't provide detailed error info for security reasons\n // The actual connection error details are only visible in browser DevTools Network tab\n // Error alone doesn't mean connection failed - onclose will be called\n };\n\n ws.onmessage = (msg) => handleMessage(msg);\n });\n}\n\nfunction handleMessage(event: MessageEvent) {\n const data = JSON.parse(event.data);\n\n if (data.id && pending[data.id]) {\n const request = pending[data.id];\n delete pending[data.id];\n if (data.error) {\n request.reject(data.error);\n } else {\n request.resolve(data.result);\n }\n }\n\n if (data.method === 'blockchain.headers.subscribe') {\n const header = data.params[0] as BlockHeader;\n lastBlockHeader = header; // Cache for late subscribers\n blockSubscribers.forEach((cb) => cb(header));\n }\n}\n\n// ----------------------------------------\n// SAFE RPC - Auto-connects and waits if needed\n// ----------------------------------------\nexport async function rpc(method: string, params: unknown[] = []): Promise<unknown> {\n // Auto-connect if not connected\n if (!isConnected && !isConnecting) {\n await connect();\n }\n\n // Wait for connection if connecting\n if (!isWebSocketConnected()) {\n await waitForConnection();\n }\n\n return new Promise((resolve, reject) => {\n if (!ws || ws.readyState !== WebSocket.OPEN) {\n return reject(new Error('WebSocket not connected (OPEN)'));\n }\n\n const id = ++requestId;\n\n // Set up timeout for this request\n const timeoutId = setTimeout(() => {\n if (pending[id]) {\n delete pending[id];\n reject(new Error(`RPC timeout: ${method}`));\n }\n }, RPC_TIMEOUT);\n\n pending[id] = {\n resolve: (result) => {\n clearTimeout(timeoutId);\n resolve(result);\n },\n reject: (err) => {\n clearTimeout(timeoutId);\n reject(err);\n },\n timeoutId,\n };\n\n ws.send(JSON.stringify({ jsonrpc: '2.0', id, method, params }));\n });\n}\n\n// ----------------------------------------\n// API METHODS\n// ----------------------------------------\n\nexport async function getUtxo(address: string) {\n const scripthash = addressToScriptHash(address);\n\n const result = await rpc('blockchain.scripthash.listunspent', [scripthash]);\n\n if (!Array.isArray(result)) {\n console.warn('listunspent returned non-array:', result);\n return [];\n }\n\n return result.map((u: UTXO) => ({\n tx_hash: u.tx_hash,\n tx_pos: u.tx_pos,\n value: u.value,\n height: u.height,\n address,\n }));\n}\n\nexport async function getBalance(address: string) {\n const scriptHash = addressToScriptHash(address);\n const result = (await rpc('blockchain.scripthash.get_balance', [scriptHash])) as BalanceResult;\n\n const confirmed = result.confirmed || 0;\n const unconfirmed = result.unconfirmed || 0;\n\n const totalSats = confirmed + unconfirmed;\n\n // Convert sats → ALPHA\n const alpha = totalSats / 100_000_000;\n\n return alpha;\n}\n\nexport async function broadcast(rawHex: string) {\n return await rpc('blockchain.transaction.broadcast', [rawHex]);\n}\n\nexport async function subscribeBlocks(cb: (header: BlockHeader) => void): Promise<() => void> {\n // Auto-connect if not connected (same as rpc())\n if (!isConnected && !isConnecting) {\n await connect();\n }\n\n // Wait for connection to be established\n if (!isWebSocketConnected()) {\n await waitForConnection();\n }\n\n blockSubscribers.push(cb);\n\n // Only send RPC subscription if not already subscribed\n // This prevents duplicate server-side subscriptions\n if (!isBlockSubscribed) {\n isBlockSubscribed = true;\n const header = (await rpc('blockchain.headers.subscribe', [])) as BlockHeader;\n if (header) {\n lastBlockHeader = header;\n // Notify ALL current subscribers with the initial header\n blockSubscribers.forEach((subscriber) => subscriber(header));\n }\n } else if (lastBlockHeader) {\n // For late subscribers, immediately notify with cached header\n cb(lastBlockHeader);\n }\n\n // Return unsubscribe function\n return () => {\n const index = blockSubscribers.indexOf(cb);\n if (index > -1) {\n blockSubscribers.splice(index, 1);\n }\n };\n}\n\nexport interface TransactionHistoryItem {\n tx_hash: string;\n height: number;\n fee?: number;\n}\n\nexport interface TransactionDetail {\n txid: string;\n version: number;\n locktime: number;\n vin: Array<{\n txid: string;\n vout: number;\n scriptSig?: {\n hex: string;\n };\n sequence: number;\n }>;\n vout: Array<{\n value: number;\n n: number;\n scriptPubKey: {\n hex: string;\n type: string;\n addresses?: string[];\n address?: string;\n };\n }>;\n blockhash?: string;\n confirmations?: number;\n time?: number;\n blocktime?: number;\n}\n\nexport async function getTransactionHistory(address: string): Promise<TransactionHistoryItem[]> {\n const scriptHash = addressToScriptHash(address);\n const result = await rpc('blockchain.scripthash.get_history', [scriptHash]);\n\n if (!Array.isArray(result)) {\n console.warn('get_history returned non-array:', result);\n return [];\n }\n\n return result as TransactionHistoryItem[];\n}\n\nexport async function getTransaction(txid: string) {\n return await rpc('blockchain.transaction.get', [txid, true]);\n}\n\nexport async function getBlockHeader(height: number) {\n return await rpc('blockchain.block.header', [height, height]);\n}\n\nexport async function getCurrentBlockHeight(): Promise<number> {\n try {\n const header = (await rpc('blockchain.headers.subscribe', [])) as BlockHeader;\n return header?.height || 0;\n } catch (err) {\n console.error('Error getting current block height:', err);\n return 0;\n }\n}\n\nexport function disconnect() {\n if (ws) {\n intentionalClose = true;\n ws.close();\n ws = null;\n }\n isConnected = false;\n isConnecting = false;\n reconnectAttempts = 0;\n isBlockSubscribed = false;\n\n // Clear all pending request timeouts\n Object.values(pending).forEach((req) => {\n if (req.timeoutId) clearTimeout(req.timeoutId);\n });\n Object.keys(pending).forEach((key) => delete pending[Number(key)]);\n\n // Clear connection callback timeouts\n connectionCallbacks.forEach((cb) => {\n if (cb.timeoutId) clearTimeout(cb.timeoutId);\n });\n connectionCallbacks.length = 0;\n}\n","/**\n * Transaction handling - Strict copy of index.html logic\n */\nimport { getUtxo, broadcast } from \"./network\";\nimport { decodeBech32 } from \"../core/bech32\";\nimport CryptoJS from \"crypto-js\";\nimport elliptic from \"elliptic\";\nimport type { Wallet, TransactionPlan, Transaction, UTXO } from \"./types\";\nimport { vestingState } from \"./vestingState\";\nimport { WalletAddressHelper } from \"./addressHelpers\";\n\nconst ec = new elliptic.ec(\"secp256k1\");\n\n// Constants\nconst FEE = 10_000; // sats per transaction\nconst DUST = 546; // dust threshold\nconst SAT = 100_000_000; // sats in 1 ALPHA\n\n/**\n * Create scriptPubKey for address (P2WPKH for bech32)\n * Exact copy from index.html\n */\nexport function createScriptPubKey(address: string): string {\n if (!address || typeof address !== \"string\") {\n throw new Error(\"Invalid address: must be a string\");\n }\n\n const decoded = decodeBech32(address);\n if (!decoded) {\n throw new Error(\"Invalid bech32 address: \" + address);\n }\n\n // Convert data array to hex string\n const dataHex = Array.from(decoded.data)\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\");\n\n // P2WPKH scriptPubKey: OP_0 <20-byte-key-hash>\n return \"0014\" + dataHex;\n}\n\n/**\n * Create signature hash for SegWit (BIP143)\n * Exact copy from index.html createSignatureHash()\n */\nfunction createSignatureHash(\n txPlan: { input: { tx_hash: string; tx_pos: number; value: number }; outputs: Array<{ value: number; address: string }> },\n publicKey: string\n): string {\n let preimage = \"\";\n\n // 1. nVersion (4 bytes, little-endian)\n preimage += \"02000000\";\n\n // 2. hashPrevouts (32 bytes)\n const txidBytes = txPlan.input.tx_hash.match(/../g)!.reverse().join(\"\");\n const voutBytes = (\"00000000\" + txPlan.input.tx_pos.toString(16)).slice(-8).match(/../g)!.reverse().join(\"\");\n const prevouts = txidBytes + voutBytes;\n const hashPrevouts = CryptoJS.SHA256(CryptoJS.SHA256(CryptoJS.enc.Hex.parse(prevouts))).toString();\n preimage += hashPrevouts;\n\n // 3. hashSequence (32 bytes)\n const sequence = \"feffffff\";\n const hashSequence = CryptoJS.SHA256(CryptoJS.SHA256(CryptoJS.enc.Hex.parse(sequence))).toString();\n preimage += hashSequence;\n\n // 4. outpoint (36 bytes)\n preimage += txPlan.input.tx_hash.match(/../g)!.reverse().join(\"\");\n preimage += (\"00000000\" + txPlan.input.tx_pos.toString(16)).slice(-8).match(/../g)!.reverse().join(\"\");\n\n // 5. scriptCode for P2WPKH (includes length prefix)\n const pubKeyHash = CryptoJS.RIPEMD160(CryptoJS.SHA256(CryptoJS.enc.Hex.parse(publicKey))).toString();\n const scriptCode = \"1976a914\" + pubKeyHash + \"88ac\";\n preimage += scriptCode;\n\n // 6. amount (8 bytes, little-endian)\n const amountHex = txPlan.input.value.toString(16).padStart(16, \"0\");\n preimage += amountHex.match(/../g)!.reverse().join(\"\");\n\n // 7. nSequence (4 bytes, little-endian)\n preimage += sequence;\n\n // 8. hashOutputs (32 bytes)\n let outputs = \"\";\n for (const output of txPlan.outputs) {\n const outAmountHex = output.value.toString(16).padStart(16, \"0\");\n outputs += outAmountHex.match(/../g)!.reverse().join(\"\");\n const scriptPubKey = createScriptPubKey(output.address);\n const scriptLength = (scriptPubKey.length / 2).toString(16).padStart(2, \"0\");\n outputs += scriptLength;\n outputs += scriptPubKey;\n }\n const hashOutputs = CryptoJS.SHA256(CryptoJS.SHA256(CryptoJS.enc.Hex.parse(outputs))).toString();\n preimage += hashOutputs;\n\n // 9. nLocktime (4 bytes, little-endian)\n preimage += \"00000000\";\n\n // 10. sighash type (4 bytes, little-endian)\n preimage += \"01000000\"; // SIGHASH_ALL\n\n // Double SHA256\n const hash1 = CryptoJS.SHA256(CryptoJS.enc.Hex.parse(preimage));\n const hash2 = CryptoJS.SHA256(hash1);\n return hash2.toString();\n}\n\n/**\n * Create witness data for the transaction\n * Exact copy from index.html createWitnessData()\n */\nfunction createWitnessData(\n txPlan: { input: { tx_hash: string; tx_pos: number; value: number }; outputs: Array<{ value: number; address: string }> },\n keyPair: elliptic.ec.KeyPair,\n publicKey: string\n): string {\n // Create signature hash for witness\n const sigHash = createSignatureHash(txPlan, publicKey);\n\n // Sign the hash\n const signature = keyPair.sign(sigHash);\n\n // Ensure low-S canonical signature (BIP62)\n const halfOrder = ec.curve.n!.shrn(1);\n if (signature.s.cmp(halfOrder) > 0) {\n signature.s = ec.curve.n!.sub(signature.s);\n }\n\n const derSig = signature.toDER(\"hex\") + \"01\"; // SIGHASH_ALL\n\n // Build witness\n let witness = \"\";\n witness += \"02\"; // 2 stack items\n\n // Signature\n const sigLen = (derSig.length / 2).toString(16).padStart(2, \"0\");\n witness += sigLen;\n witness += derSig;\n\n // Public key\n const pubKeyLen = (publicKey.length / 2).toString(16).padStart(2, \"0\");\n witness += pubKeyLen;\n witness += publicKey;\n\n return witness;\n}\n\n/**\n * Build a proper SegWit transaction\n * Exact copy from index.html buildSegWitTransaction()\n */\nexport function buildSegWitTransaction(\n txPlan: { input: { tx_hash: string; tx_pos: number; value: number }; outputs: Array<{ value: number; address: string }> },\n keyPair: elliptic.ec.KeyPair,\n publicKey: string\n): { hex: string; txid: string } {\n let txHex = \"\";\n\n // Version (4 bytes, little-endian)\n txHex += \"02000000\"; // version 2\n\n // Marker and flag for SegWit\n txHex += \"00\"; // marker\n txHex += \"01\"; // flag\n\n // Number of inputs (varint)\n txHex += \"01\"; // 1 input\n\n // Input - Previous tx hash (32 bytes, reversed for little-endian)\n const prevTxHash = txPlan.input.tx_hash;\n const reversedHash = prevTxHash.match(/../g)!.reverse().join(\"\");\n txHex += reversedHash;\n\n // Previous output index (4 bytes, little-endian)\n const vout = txPlan.input.tx_pos;\n txHex += (\"00000000\" + vout.toString(16)).slice(-8).match(/../g)!.reverse().join(\"\");\n\n // Script length (varint) - 0 for witness transactions\n txHex += \"00\";\n\n // Sequence (4 bytes)\n txHex += \"feffffff\";\n\n // Number of outputs (varint)\n const outputCount = txPlan.outputs.length;\n txHex += (\"0\" + outputCount.toString(16)).slice(-2);\n\n // Outputs\n for (const output of txPlan.outputs) {\n // Amount (8 bytes, little-endian)\n const amountHex = output.value.toString(16).padStart(16, \"0\");\n txHex += amountHex.match(/../g)!.reverse().join(\"\");\n\n // Script pubkey\n const scriptPubKey = createScriptPubKey(output.address);\n const scriptLength = (scriptPubKey.length / 2).toString(16).padStart(2, \"0\");\n txHex += scriptLength;\n txHex += scriptPubKey;\n }\n\n // Witness data\n const witnessData = createWitnessData(txPlan, keyPair, publicKey);\n txHex += witnessData;\n\n // Locktime (4 bytes)\n txHex += \"00000000\";\n\n // Calculate transaction ID (double SHA256 of tx without witness data)\n let txForId = \"\";\n\n // Version (4 bytes)\n txForId += \"02000000\";\n\n // Input count (1 byte)\n txForId += \"01\";\n\n // Input: txid (32 bytes reversed) + vout (4 bytes)\n const inputTxidBytes = txPlan.input.tx_hash.match(/../g)!.reverse().join(\"\");\n txForId += inputTxidBytes;\n txForId += (\"00000000\" + txPlan.input.tx_pos.toString(16)).slice(-8).match(/../g)!.reverse().join(\"\");\n\n // Script sig (empty for P2WPKH)\n txForId += \"00\";\n\n // Sequence (4 bytes)\n txForId += \"feffffff\";\n\n // Output count\n txForId += (\"0\" + txPlan.outputs.length.toString(16)).slice(-2);\n\n // Add all outputs\n for (const output of txPlan.outputs) {\n const amountHex = (\"0000000000000000\" + output.value.toString(16)).slice(-16);\n const amountLittleEndian = amountHex.match(/../g)!.reverse().join(\"\");\n txForId += amountLittleEndian;\n\n const scriptPubKey = createScriptPubKey(output.address);\n const scriptLength = (\"0\" + (scriptPubKey.length / 2).toString(16)).slice(-2);\n txForId += scriptLength;\n txForId += scriptPubKey;\n }\n\n // Locktime (4 bytes)\n txForId += \"00000000\";\n\n // Calculate the correct txid\n const hash1 = CryptoJS.SHA256(CryptoJS.enc.Hex.parse(txForId));\n const hash2 = CryptoJS.SHA256(hash1);\n const txid = hash2.toString().match(/../g)!.reverse().join(\"\");\n\n return {\n hex: txHex,\n txid: txid,\n };\n}\n\n/**\n * Create and sign a transaction\n * Uses the private key for the specific address being spent from\n */\nexport function createAndSignTransaction(\n wallet: Wallet,\n txPlan: Transaction\n): { raw: string; txid: string } {\n // Find the address entry that matches the input address\n const fromAddress = txPlan.input.address;\n const addressEntry = wallet.addresses.find(a => a.address === fromAddress);\n\n // Use the private key from the address entry, or fall back to childPrivateKey/masterPrivateKey\n let privateKeyHex: string | undefined;\n\n if (addressEntry?.privateKey) {\n // Use the specific private key for this address\n privateKeyHex = addressEntry.privateKey;\n } else if (wallet.childPrivateKey) {\n // Fall back to childPrivateKey (first address)\n privateKeyHex = wallet.childPrivateKey;\n } else {\n // Last resort: use master key\n privateKeyHex = wallet.masterPrivateKey;\n }\n\n if (!privateKeyHex) {\n throw new Error(\"No private key available for address: \" + fromAddress);\n }\n\n const keyPair = ec.keyFromPrivate(privateKeyHex, \"hex\");\n const publicKey = keyPair.getPublic(true, \"hex\"); // compressed\n\n // Convert Transaction to the format expected by buildSegWitTransaction\n const txPlanForBuild = {\n input: {\n tx_hash: txPlan.input.txid,\n tx_pos: txPlan.input.vout,\n value: txPlan.input.value,\n },\n outputs: txPlan.outputs,\n };\n\n const tx = buildSegWitTransaction(txPlanForBuild, keyPair, publicKey);\n\n return {\n raw: tx.hex,\n txid: tx.txid,\n };\n}\n\n/**\n * Collect UTXOs for required amount\n * Based on index.html collectUtxosForAmount()\n *\n * Strategy: First try to find a single UTXO that can cover amount + fee.\n * If not found, fall back to combining multiple UTXOs.\n */\nexport function collectUtxosForAmount(\n utxoList: UTXO[],\n amountSats: number,\n recipientAddress: string,\n senderAddress: string\n): TransactionPlan {\n const totalAvailable = utxoList.reduce((sum, u) => sum + u.value, 0);\n\n if (totalAvailable < amountSats + FEE) {\n return {\n success: false,\n transactions: [],\n error: `Insufficient funds. Available: ${totalAvailable / SAT} ALPHA, Required: ${(amountSats + FEE) / SAT} ALPHA (including fee)`,\n };\n }\n\n // Strategy 1: Find a single UTXO that covers amount + fee\n // Sort by value ascending to find the smallest sufficient UTXO\n const sortedByValue = [...utxoList].sort((a, b) => a.value - b.value);\n const sufficientUtxo = sortedByValue.find(u => u.value >= amountSats + FEE);\n\n if (sufficientUtxo) {\n const changeAmount = sufficientUtxo.value - amountSats - FEE;\n const tx: Transaction = {\n input: {\n txid: sufficientUtxo.txid ?? sufficientUtxo.tx_hash ?? \"\",\n vout: sufficientUtxo.vout ?? sufficientUtxo.tx_pos ?? 0,\n value: sufficientUtxo.value,\n address: sufficientUtxo.address ?? senderAddress,\n },\n outputs: [{ address: recipientAddress, value: amountSats }],\n fee: FEE,\n changeAmount: changeAmount,\n changeAddress: senderAddress,\n };\n\n // Add change output if above dust\n if (changeAmount > DUST) {\n tx.outputs.push({ value: changeAmount, address: senderAddress });\n }\n\n return {\n success: true,\n transactions: [tx],\n };\n }\n\n // Strategy 2: No single UTXO is sufficient, combine multiple UTXOs\n // Sort descending to use larger UTXOs first (fewer transactions)\n const sortedDescending = [...utxoList].sort((a, b) => b.value - a.value);\n\n const transactions: Transaction[] = [];\n let remainingAmount = amountSats;\n\n for (const utxo of sortedDescending) {\n if (remainingAmount <= 0) break;\n\n const utxoValue = utxo.value;\n let txAmount = 0;\n let changeAmount = 0;\n\n if (utxoValue >= remainingAmount + FEE) {\n // This UTXO covers the remaining amount plus fee\n txAmount = remainingAmount;\n changeAmount = utxoValue - remainingAmount - FEE;\n remainingAmount = 0;\n } else {\n // Use entire UTXO minus fee\n txAmount = utxoValue - FEE;\n if (txAmount <= 0) continue; // Skip UTXOs too small to cover fee\n remainingAmount -= txAmount;\n }\n\n const tx: Transaction = {\n input: {\n txid: utxo.txid ?? utxo.tx_hash ?? \"\",\n vout: utxo.vout ?? utxo.tx_pos ?? 0,\n value: utxo.value,\n address: utxo.address ?? senderAddress,\n },\n outputs: [{ address: recipientAddress, value: txAmount }],\n fee: FEE,\n changeAmount: changeAmount,\n changeAddress: senderAddress,\n };\n\n // Add change output if above dust\n if (changeAmount > DUST) {\n tx.outputs.push({ value: changeAmount, address: senderAddress });\n }\n\n transactions.push(tx);\n }\n\n if (remainingAmount > 0) {\n return {\n success: false,\n transactions: [],\n error: `Unable to collect enough UTXOs. Short by ${remainingAmount / SAT} ALPHA after fees.`,\n };\n }\n\n return {\n success: true,\n transactions,\n };\n}\n\n/**\n * Create transaction plan from wallet\n * @param wallet - The wallet\n * @param toAddress - Recipient address\n * @param amountAlpha - Amount in ALPHA\n * @param fromAddress - Optional: specific address to send from (defaults to first address)\n */\nexport async function createTransactionPlan(\n wallet: Wallet,\n toAddress: string,\n amountAlpha: number,\n fromAddress?: string\n): Promise<TransactionPlan> {\n if (!decodeBech32(toAddress)) {\n throw new Error(\"Invalid recipient address\");\n }\n\n // Use specified fromAddress or default to first external address\n const defaultAddr = WalletAddressHelper.getDefault(wallet);\n const senderAddress = fromAddress || defaultAddr.address;\n const amountSats = Math.floor(amountAlpha * SAT);\n\n // Get UTXOs filtered by current vesting mode (set in SendModal)\n let utxos: UTXO[];\n const currentMode = vestingState.getMode();\n\n if (vestingState.hasClassifiedData(senderAddress)) {\n // Use vesting-filtered UTXOs based on selected mode\n utxos = vestingState.getFilteredUtxos(senderAddress);\n console.log(`Using ${utxos.length} ${currentMode} UTXOs`);\n } else {\n // Fall back to all UTXOs if not yet classified\n utxos = await getUtxo(senderAddress);\n console.log(`Using ${utxos.length} UTXOs (vesting not classified yet)`);\n }\n\n if (!Array.isArray(utxos) || utxos.length === 0) {\n const modeText = currentMode !== 'all' ? ` (${currentMode} coins)` : '';\n throw new Error(`No UTXOs available${modeText} for address: ` + senderAddress);\n }\n\n return collectUtxosForAmount(utxos, amountSats, toAddress, senderAddress);\n}\n\n/**\n * Send ALPHA to address\n * @param wallet - The wallet\n * @param toAddress - Recipient address\n * @param amountAlpha - Amount in ALPHA\n * @param fromAddress - Optional: specific address to send from\n */\nexport async function sendAlpha(\n wallet: Wallet,\n toAddress: string,\n amountAlpha: number,\n fromAddress?: string\n) {\n const plan = await createTransactionPlan(wallet, toAddress, amountAlpha, fromAddress);\n\n if (!plan.success) {\n throw new Error(plan.error || \"Transaction planning failed\");\n }\n\n const results = [];\n\n for (const tx of plan.transactions) {\n const signed = createAndSignTransaction(wallet, tx);\n const result = await broadcast(signed.raw);\n results.push({\n txid: signed.txid,\n raw: signed.raw,\n broadcastResult: result,\n });\n }\n\n return results;\n}\n","/**\n * VestingClassifier - Traces UTXOs to their coinbase origin to determine vesting status\n * VESTED: Coins from coinbase transactions in blocks <= VESTING_THRESHOLD (280000)\n * UNVESTED: Coins from coinbase transactions in blocks > VESTING_THRESHOLD\n *\n * Direct port from index.html VestingClassifier\n */\nimport { getTransaction, getCurrentBlockHeight } from \"./network\";\nimport type { UTXO, ClassifiedUTXO, ClassificationResult } from \"./types\";\n\nexport const VESTING_THRESHOLD = 280000;\n\n// Current block height - updated during classification\nlet currentBlockHeight: number | null = null;\n\ninterface CacheEntry {\n blockHeight: number | null; // null means \"not computed yet\"\n isCoinbase: boolean;\n inputTxId: string | null;\n}\n\ninterface TransactionData {\n txid: string;\n confirmations?: number;\n height?: number;\n vin?: Array<{\n txid?: string;\n coinbase?: string;\n }>;\n}\n\nclass VestingClassifier {\n private memoryCache = new Map<string, CacheEntry>();\n private dbName = \"SphereVestingCacheV5\"; // V5 - new cache with proper null handling\n private storeName = \"vestingCache\";\n private db: IDBDatabase | null = null;\n\n /**\n * Initialize IndexedDB for persistent caching\n */\n async initDB(): Promise<void> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(this.dbName, 1);\n\n request.onupgradeneeded = (event) => {\n const db = (event.target as IDBOpenDBRequest).result;\n if (!db.objectStoreNames.contains(this.storeName)) {\n db.createObjectStore(this.storeName, { keyPath: \"txHash\" });\n }\n };\n\n request.onsuccess = (event) => {\n this.db = (event.target as IDBOpenDBRequest).result;\n resolve();\n };\n\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Check if transaction is coinbase\n */\n private isCoinbaseTransaction(txData: TransactionData): boolean {\n if (txData.vin && txData.vin.length === 1) {\n const vin = txData.vin[0];\n // Check for coinbase field or missing txid\n if (vin.coinbase || (!vin.txid && vin.coinbase !== undefined)) {\n return true;\n }\n // Some formats use empty txid for coinbase\n if (vin.txid === \"0000000000000000000000000000000000000000000000000000000000000000\") {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Load from IndexedDB cache\n */\n private async loadFromDB(txHash: string): Promise<CacheEntry | null> {\n if (!this.db) return null;\n\n return new Promise((resolve) => {\n const tx = this.db!.transaction(this.storeName, \"readonly\");\n const store = tx.objectStore(this.storeName);\n const request = store.get(txHash);\n\n request.onsuccess = () => {\n if (request.result) {\n resolve({\n blockHeight: request.result.blockHeight,\n isCoinbase: request.result.isCoinbase,\n inputTxId: request.result.inputTxId,\n });\n } else {\n resolve(null);\n }\n };\n request.onerror = () => resolve(null);\n });\n }\n\n /**\n * Save to IndexedDB cache\n */\n private async saveToDB(txHash: string, entry: CacheEntry): Promise<void> {\n if (!this.db) return;\n\n return new Promise((resolve) => {\n const tx = this.db!.transaction(this.storeName, \"readwrite\");\n const store = tx.objectStore(this.storeName);\n store.put({ txHash, ...entry });\n tx.oncomplete = () => resolve();\n tx.onerror = () => resolve();\n });\n }\n\n /**\n * Trace a transaction to its coinbase origin\n * Alpha blockchain has single-input transactions, making this a linear trace\n */\n async traceToOrigin(txHash: string): Promise<{ coinbaseHeight: number | null; error?: string }> {\n let currentTxHash = txHash;\n let iterations = 0;\n const MAX_ITERATIONS = 10000;\n\n while (iterations < MAX_ITERATIONS) {\n iterations++;\n\n // Check memory cache first\n const cached = this.memoryCache.get(currentTxHash);\n if (cached) {\n if (cached.isCoinbase) {\n // Skip cache if blockHeight is null - needs re-fetch\n if (cached.blockHeight !== null && cached.blockHeight !== undefined) {\n return { coinbaseHeight: cached.blockHeight };\n }\n // Fall through to re-fetch\n } else if (cached.inputTxId) {\n // Follow the input chain\n currentTxHash = cached.inputTxId;\n continue;\n }\n }\n\n // Check IndexedDB cache\n const dbCached = await this.loadFromDB(currentTxHash);\n if (dbCached) {\n // Also store in memory cache\n this.memoryCache.set(currentTxHash, dbCached);\n if (dbCached.isCoinbase) {\n // Skip cache if blockHeight is null - needs re-fetch\n if (dbCached.blockHeight !== null && dbCached.blockHeight !== undefined) {\n return { coinbaseHeight: dbCached.blockHeight };\n }\n // Fall through to re-fetch\n } else if (dbCached.inputTxId) {\n currentTxHash = dbCached.inputTxId;\n continue;\n }\n }\n\n // Fetch from network\n const txData = await getTransaction(currentTxHash) as TransactionData;\n if (!txData || !txData.txid) {\n return { coinbaseHeight: null, error: `Failed to fetch tx ${currentTxHash}` };\n }\n\n // Determine if this is a coinbase transaction\n const isCoinbase = this.isCoinbaseTransaction(txData);\n\n // Calculate block height from confirmations (like index.html does)\n let blockHeight: number | null = null;\n if (txData.confirmations && currentBlockHeight !== null && currentBlockHeight !== undefined) {\n blockHeight = currentBlockHeight - txData.confirmations + 1;\n }\n\n // Get input transaction ID (if not coinbase)\n let inputTxId: string | null = null;\n if (!isCoinbase && txData.vin && txData.vin.length > 0 && txData.vin[0].txid) {\n inputTxId = txData.vin[0].txid;\n }\n\n // Cache the result\n const cacheEntry: CacheEntry = {\n blockHeight, // Can be null if confirmations not available\n isCoinbase,\n inputTxId,\n };\n this.memoryCache.set(currentTxHash, cacheEntry);\n await this.saveToDB(currentTxHash, cacheEntry);\n\n if (isCoinbase) {\n return { coinbaseHeight: blockHeight };\n }\n\n if (!inputTxId) {\n return { coinbaseHeight: null, error: \"Could not find input transaction\" };\n }\n\n currentTxHash = inputTxId;\n }\n\n return { coinbaseHeight: null, error: \"Max iterations exceeded\" };\n }\n\n /**\n * Classify a single UTXO\n */\n async classifyUtxo(utxo: UTXO): Promise<ClassificationResult> {\n const txHash = utxo.tx_hash || utxo.txid;\n if (!txHash) {\n return { isVested: false, coinbaseHeight: null, error: \"No transaction hash\" };\n }\n\n try {\n const result = await this.traceToOrigin(txHash);\n if (result.error || result.coinbaseHeight === null) {\n return { isVested: false, coinbaseHeight: null, error: result.error || \"Could not trace to origin\" };\n }\n return {\n isVested: result.coinbaseHeight <= VESTING_THRESHOLD,\n coinbaseHeight: result.coinbaseHeight,\n };\n } catch (err) {\n return {\n isVested: false,\n coinbaseHeight: null,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n\n /**\n * Classify multiple UTXOs with progress callback\n */\n async classifyUtxos(\n utxos: UTXO[],\n onProgress?: (current: number, total: number) => void\n ): Promise<{\n vested: ClassifiedUTXO[];\n unvested: ClassifiedUTXO[];\n errors: Array<{ utxo: UTXO; error: string }>;\n }> {\n // Get current block height before classification\n currentBlockHeight = await getCurrentBlockHeight();\n\n // Clear memory cache to force re-fetch with current block height\n this.memoryCache.clear();\n\n const vested: ClassifiedUTXO[] = [];\n const unvested: ClassifiedUTXO[] = [];\n const errors: Array<{ utxo: UTXO; error: string }> = [];\n\n for (let i = 0; i < utxos.length; i++) {\n const utxo = utxos[i];\n const result = await this.classifyUtxo(utxo);\n\n if (result.error) {\n errors.push({ utxo, error: result.error });\n // Default to unvested on error for safety\n unvested.push({\n ...utxo,\n vestingStatus: \"error\",\n coinbaseHeight: null,\n });\n } else if (result.isVested) {\n vested.push({\n ...utxo,\n vestingStatus: \"vested\",\n coinbaseHeight: result.coinbaseHeight,\n });\n } else {\n unvested.push({\n ...utxo,\n vestingStatus: \"unvested\",\n coinbaseHeight: result.coinbaseHeight,\n });\n }\n\n // Report progress\n if (onProgress) {\n onProgress(i + 1, utxos.length);\n }\n\n // Yield every 5 UTXOs\n if (i % 5 === 0) {\n await new Promise((resolve) => setTimeout(resolve, 0));\n }\n }\n\n return { vested, unvested, errors };\n }\n\n /**\n * Clear all caches\n */\n clearCaches(): void {\n this.memoryCache.clear();\n if (this.db) {\n const tx = this.db.transaction(this.storeName, \"readwrite\");\n tx.objectStore(this.storeName).clear();\n }\n }\n}\n\nexport const vestingClassifier = new VestingClassifier();\n","import { vestingClassifier } from \"./vesting\";\nimport type {\n UTXO,\n ClassifiedUTXO,\n VestingMode,\n VestingBalances,\n} from \"./types\";\n\ninterface AddressVestingCache {\n classifiedUtxos: {\n vested: ClassifiedUTXO[];\n unvested: ClassifiedUTXO[];\n all: ClassifiedUTXO[];\n };\n vestingBalances: VestingBalances;\n}\n\nclass VestingStateManager {\n private currentMode: VestingMode = \"all\";\n private addressCache = new Map<string, AddressVestingCache>();\n private classificationInProgress = false;\n\n /**\n * Set the current vesting mode\n */\n setMode(mode: VestingMode): void {\n if (![\"all\", \"vested\", \"unvested\"].includes(mode)) {\n throw new Error(`Invalid vesting mode: ${mode}`);\n }\n this.currentMode = mode;\n }\n\n getMode(): VestingMode {\n return this.currentMode;\n }\n\n /**\n * Classify all UTXOs for an address\n */\n async classifyAddressUtxos(\n address: string,\n utxos: UTXO[],\n onProgress?: (current: number, total: number) => void\n ): Promise<void> {\n if (this.classificationInProgress) return;\n\n this.classificationInProgress = true;\n\n try {\n await vestingClassifier.initDB();\n\n const result = await vestingClassifier.classifyUtxos(utxos, onProgress);\n\n // Calculate balances\n const vestedBalance = result.vested.reduce(\n (sum, utxo) => sum + BigInt(utxo.value),\n 0n\n );\n const unvestedBalance = result.unvested.reduce(\n (sum, utxo) => sum + BigInt(utxo.value),\n 0n\n );\n\n // Store in cache\n this.addressCache.set(address, {\n classifiedUtxos: {\n vested: result.vested,\n unvested: result.unvested,\n all: [...result.vested, ...result.unvested],\n },\n vestingBalances: {\n vested: vestedBalance,\n unvested: unvestedBalance,\n all: vestedBalance + unvestedBalance,\n },\n });\n\n // Log any errors\n if (result.errors.length > 0) {\n console.warn(`Vesting classification errors: ${result.errors.length}`);\n result.errors.slice(0, 5).forEach((err) => {\n const txHash = err.utxo.tx_hash || err.utxo.txid;\n console.warn(` ${txHash}: ${err.error}`);\n });\n }\n } finally {\n this.classificationInProgress = false;\n }\n }\n\n /**\n * Get filtered UTXOs based on current vesting mode\n */\n getFilteredUtxos(address: string): ClassifiedUTXO[] {\n const cache = this.addressCache.get(address);\n if (!cache) return [];\n\n switch (this.currentMode) {\n case \"vested\":\n return cache.classifiedUtxos.vested;\n case \"unvested\":\n return cache.classifiedUtxos.unvested;\n default:\n return cache.classifiedUtxos.all;\n }\n }\n\n /**\n * Get all UTXOs regardless of vesting mode (for transactions)\n */\n getAllUtxos(address: string): ClassifiedUTXO[] {\n const cache = this.addressCache.get(address);\n if (!cache) return [];\n return cache.classifiedUtxos.all;\n }\n\n /**\n * Get balance for current vesting mode (in satoshis)\n */\n getBalance(address: string): bigint {\n const cache = this.addressCache.get(address);\n if (!cache) return 0n;\n\n return cache.vestingBalances[this.currentMode];\n }\n\n /**\n * Get all balances for display\n */\n getAllBalances(address: string): VestingBalances {\n const cache = this.addressCache.get(address);\n if (!cache) {\n return { vested: 0n, unvested: 0n, all: 0n };\n }\n return cache.vestingBalances;\n }\n\n /**\n * Check if address has been classified\n */\n hasClassifiedData(address: string): boolean {\n return this.addressCache.has(address);\n }\n\n /**\n * Check if classification is in progress\n */\n isClassifying(): boolean {\n return this.classificationInProgress;\n }\n\n /**\n * Clear cache for an address\n */\n clearAddressCache(address: string): void {\n this.addressCache.delete(address);\n }\n\n /**\n * Clear all caches\n */\n clearAllCaches(): void {\n this.addressCache.clear();\n vestingClassifier.clearCaches();\n }\n}\n\nexport const vestingState = new VestingStateManager();\n","/**\n * WalletAddressHelper - Path-based address lookup and mutation utilities\n *\n * Key principle: A BIP32 path ALWAYS derives the same address from a given master key.\n * - If we try to add a different address for an existing path → FATAL ERROR\n * - This indicates corruption, wrong derivation, or data integrity issue\n *\n * Performance: O(n) lookup is negligible for typical wallet sizes (5-100 addresses)\n */\n\nimport type { Wallet, WalletAddress } from \"./types\";\n\nexport class WalletAddressHelper {\n /**\n * Find address by BIP32 derivation path\n * @param wallet - The wallet to search\n * @param path - Full BIP32 path like \"m/84'/1'/0'/0/5\"\n * @returns The address if found, undefined otherwise\n */\n static findByPath(wallet: Wallet, path: string): WalletAddress | undefined {\n return wallet.addresses.find((a) => a.path === path);\n }\n\n /**\n * Get the default address (first external/non-change address)\n * This replaces `wallet.addresses[0]` pattern for safer access\n *\n * @param wallet - The wallet\n * @returns First non-change address, or first address if all are change\n */\n static getDefault(wallet: Wallet): WalletAddress {\n return wallet.addresses.find((a) => !a.isChange) ?? wallet.addresses[0];\n }\n\n /**\n * Get the default address, or undefined if wallet has no addresses\n * Safe version that doesn't throw on empty wallet\n */\n static getDefaultOrNull(wallet: Wallet): WalletAddress | undefined {\n if (!wallet.addresses || wallet.addresses.length === 0) {\n return undefined;\n }\n return wallet.addresses.find((a) => !a.isChange) ?? wallet.addresses[0];\n }\n\n /**\n * Add new address to wallet (immutable operation)\n *\n * THROWS if address with same path but different address string already exists.\n * This indicates a serious derivation or data corruption issue.\n *\n * If the same path+address already exists, returns wallet unchanged (idempotent).\n *\n * @param wallet - The wallet to add to\n * @param newAddress - The address to add\n * @returns New wallet object with address added\n * @throws Error if path exists with different address (corruption indicator)\n */\n static add(wallet: Wallet, newAddress: WalletAddress): Wallet {\n if (!newAddress.path) {\n throw new Error(\"Cannot add address without a path\");\n }\n\n const existing = this.findByPath(wallet, newAddress.path);\n\n if (existing) {\n // Path exists - verify it's the SAME address\n if (existing.address !== newAddress.address) {\n throw new Error(\n `CRITICAL: Attempted to overwrite address for path ${newAddress.path}\\n` +\n `Existing: ${existing.address}\\n` +\n `New: ${newAddress.address}\\n` +\n `This indicates master key corruption or derivation logic error.`\n );\n }\n\n // Same path + same address = idempotent, return unchanged\n return wallet;\n }\n\n // New path - add to array\n return {\n ...wallet,\n addresses: [...wallet.addresses, newAddress],\n };\n }\n\n /**\n * Remove address by path (immutable operation)\n * @param wallet - The wallet to modify\n * @param path - The path of the address to remove\n * @returns New wallet object with address removed\n */\n static removeByPath(wallet: Wallet, path: string): Wallet {\n return {\n ...wallet,\n addresses: wallet.addresses.filter((a) => a.path !== path),\n };\n }\n\n /**\n * Get all external (non-change) addresses\n * @param wallet - The wallet\n * @returns Array of external addresses\n */\n static getExternal(wallet: Wallet): WalletAddress[] {\n return wallet.addresses.filter((a) => !a.isChange);\n }\n\n /**\n * Get all change addresses\n * @param wallet - The wallet\n * @returns Array of change addresses\n */\n static getChange(wallet: Wallet): WalletAddress[] {\n return wallet.addresses.filter((a) => a.isChange);\n }\n\n /**\n * Check if wallet has an address with the given path\n * @param wallet - The wallet to check\n * @param path - The path to look for\n * @returns true if path exists\n */\n static hasPath(wallet: Wallet, path: string): boolean {\n return wallet.addresses.some((a) => a.path === path);\n }\n\n /**\n * Validate wallet address array integrity\n * Checks for duplicate paths which indicate data corruption\n *\n * @param wallet - The wallet to validate\n * @throws Error if duplicate paths found\n */\n static validate(wallet: Wallet): void {\n const paths = wallet.addresses.map((a) => a.path).filter(Boolean);\n const uniquePaths = new Set(paths);\n\n if (paths.length !== uniquePaths.size) {\n // Find duplicates for error message\n const duplicates = paths.filter((p, i) => paths.indexOf(p) !== i);\n throw new Error(\n `CRITICAL: Wallet has duplicate paths: ${duplicates.join(\", \")}\\n` +\n `This indicates data corruption. Please restore from backup.`\n );\n }\n }\n\n /**\n * Sort addresses with external first, then change, each sorted by index\n * Useful for display purposes\n *\n * @param wallet - The wallet\n * @returns New wallet with sorted addresses\n */\n static sortAddresses(wallet: Wallet): Wallet {\n const sorted = [...wallet.addresses].sort((a, b) => {\n // External addresses first (isChange = false/undefined)\n const aIsChange = a.isChange ? 1 : 0;\n const bIsChange = b.isChange ? 1 : 0;\n if (aIsChange !== bIsChange) return aIsChange - bIsChange;\n // Then by index\n return a.index - b.index;\n });\n\n return {\n ...wallet,\n addresses: sorted,\n };\n }\n}\n","/**\n * L1 Payments Sub-Module\n *\n * Handles Layer 1 (ALPHA blockchain) transactions including:\n * - Balance queries\n * - UTXO management\n * - Transaction sending\n * - Vesting classification\n * - Transaction history\n */\n\nimport type { FullIdentity } from '../../types';\nimport {\n connect as l1Connect,\n disconnect as l1Disconnect,\n isWebSocketConnected,\n getUtxo,\n getBalance as l1GetBalance,\n getTransactionHistory,\n getTransaction as l1GetTransaction,\n getCurrentBlockHeight,\n sendAlpha as l1SendAlpha,\n createTransactionPlan as l1CreateTransactionPlan,\n vestingClassifier,\n VESTING_THRESHOLD,\n type UTXO,\n type Wallet,\n type TransactionHistoryItem,\n type TransactionDetail,\n} from '../../l1';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface L1SendRequest {\n /** Recipient address */\n to: string;\n /** Amount in satoshis */\n amount: string;\n /** Fee rate in sat/byte */\n feeRate?: number;\n /** Use vested coins only */\n useVested?: boolean;\n /** Memo/OP_RETURN data */\n memo?: string;\n}\n\nexport interface L1SendResult {\n success: boolean;\n txHash?: string;\n fee?: string;\n error?: string;\n}\n\nexport interface L1Balance {\n confirmed: string;\n unconfirmed: string;\n vested: string;\n unvested: string;\n total: string;\n}\n\nexport interface L1Utxo {\n txid: string;\n vout: number;\n amount: string;\n address: string;\n isVested: boolean;\n confirmations: number;\n coinbaseHeight?: number;\n}\n\nexport interface L1Transaction {\n txid: string;\n type: 'send' | 'receive';\n amount: string;\n fee?: string;\n address: string;\n confirmations: number;\n timestamp: number;\n blockHeight?: number;\n}\n\n// =============================================================================\n// Configuration\n// =============================================================================\n\nexport interface L1PaymentsModuleConfig {\n /** Fulcrum server URL */\n electrumUrl?: string;\n /** Network: mainnet or testnet */\n network?: 'mainnet' | 'testnet';\n /** Default fee rate */\n defaultFeeRate?: number;\n /** Enable vesting classification */\n enableVesting?: boolean;\n}\n\n// =============================================================================\n// Dependencies\n// =============================================================================\n\nexport interface L1PaymentsModuleDependencies {\n identity: FullIdentity;\n chainCode?: string;\n addresses?: string[];\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\n/**\n * L1 Payments Module - Full Implementation\n *\n * Handles all L1 (ALPHA blockchain) operations including balance queries,\n * transaction sending, UTXO management, and vesting classification.\n */\nexport class L1PaymentsModule {\n private _initialized = false;\n private _config: L1PaymentsModuleConfig;\n private _identity?: FullIdentity;\n private _chainCode?: string;\n private _addresses: string[] = [];\n private _wallet?: Wallet;\n\n constructor(config?: L1PaymentsModuleConfig) {\n this._config = {\n electrumUrl: config?.electrumUrl ?? 'wss://fulcrum.alpha.unicity.network:50004',\n network: config?.network ?? 'mainnet',\n defaultFeeRate: config?.defaultFeeRate ?? 10,\n enableVesting: config?.enableVesting ?? true,\n };\n }\n\n async initialize(deps: L1PaymentsModuleDependencies): Promise<void> {\n this._identity = deps.identity;\n this._chainCode = deps.chainCode;\n this._addresses = deps.addresses ?? [];\n\n // Build wallet object for L1 SDK functions\n this._wallet = {\n masterPrivateKey: deps.identity.privateKey,\n chainCode: deps.chainCode,\n addresses: [\n {\n address: deps.identity.address,\n publicKey: deps.identity.publicKey,\n privateKey: deps.identity.privateKey,\n path: 'm/0',\n index: 0,\n },\n ],\n };\n\n // Add additional addresses\n for (const addr of this._addresses) {\n if (addr !== deps.identity.address) {\n this._wallet.addresses.push({\n address: addr,\n path: null,\n index: this._wallet.addresses.length,\n });\n }\n }\n\n // Connect to Fulcrum WebSocket\n if (this._config.electrumUrl) {\n await l1Connect(this._config.electrumUrl);\n }\n\n this._initialized = true;\n }\n\n destroy(): void {\n if (isWebSocketConnected()) {\n l1Disconnect();\n }\n this._initialized = false;\n this._identity = undefined;\n this._chainCode = undefined;\n this._addresses = [];\n this._wallet = undefined;\n }\n\n async send(request: L1SendRequest): Promise<L1SendResult> {\n this.ensureInitialized();\n\n if (!this._wallet || !this._identity) {\n return { success: false, error: 'No wallet available' };\n }\n\n try {\n // Convert amount from satoshis to ALPHA\n const amountAlpha = parseInt(request.amount, 10) / 100_000_000;\n\n // Send using the L1 SDK\n const results = await l1SendAlpha(\n this._wallet,\n request.to,\n amountAlpha,\n this._identity.address\n );\n\n if (results && results.length > 0) {\n // Calculate total fee from all transactions\n const txids = results.map((r) => r.txid);\n return {\n success: true,\n txHash: txids[0], // Return first txid (usually only one)\n };\n } else {\n return {\n success: false,\n error: 'Transaction failed - no results returned',\n };\n }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n }\n\n async getBalance(): Promise<L1Balance> {\n this.ensureInitialized();\n\n const addresses = this._getWatchedAddresses();\n let totalAlpha = 0;\n let vestedSats = BigInt(0);\n let unvestedSats = BigInt(0);\n\n // Get balance for all addresses\n for (const address of addresses) {\n const balance = await l1GetBalance(address);\n totalAlpha += balance;\n }\n\n const totalSats = BigInt(Math.floor(totalAlpha * 100_000_000));\n\n // Calculate vesting if enabled\n if (this._config.enableVesting) {\n await vestingClassifier.initDB();\n const allUtxos = await this._getAllUtxos();\n const classified = await vestingClassifier.classifyUtxos(allUtxos);\n\n for (const utxo of classified.vested) {\n vestedSats += BigInt(utxo.value);\n }\n for (const utxo of classified.unvested) {\n unvestedSats += BigInt(utxo.value);\n }\n }\n\n return {\n confirmed: totalSats.toString(),\n unconfirmed: '0', // Simplified - would need separate tracking\n vested: vestedSats.toString(),\n unvested: unvestedSats.toString(),\n total: totalSats.toString(),\n };\n }\n\n async getUtxos(): Promise<L1Utxo[]> {\n this.ensureInitialized();\n\n const result: L1Utxo[] = [];\n const currentHeight = await getCurrentBlockHeight();\n const allUtxos = await this._getAllUtxos();\n\n // Classify if vesting is enabled\n const classifiedVested: Set<string> = new Set();\n const classifiedCoinbaseHeights: Map<string, number | null> = new Map();\n\n if (this._config.enableVesting) {\n await vestingClassifier.initDB();\n const classified = await vestingClassifier.classifyUtxos(allUtxos);\n\n for (const utxo of classified.vested) {\n const key = `${utxo.tx_hash}:${utxo.tx_pos}`;\n classifiedVested.add(key);\n classifiedCoinbaseHeights.set(key, utxo.coinbaseHeight ?? null);\n }\n for (const utxo of classified.unvested) {\n const key = `${utxo.tx_hash}:${utxo.tx_pos}`;\n classifiedCoinbaseHeights.set(key, utxo.coinbaseHeight ?? null);\n }\n }\n\n for (const utxo of allUtxos) {\n const key = `${utxo.tx_hash}:${utxo.tx_pos}`;\n const isVested = classifiedVested.has(key);\n const coinbaseHeight = classifiedCoinbaseHeights.get(key) ?? undefined;\n\n result.push({\n txid: utxo.tx_hash ?? utxo.txid ?? '',\n vout: utxo.tx_pos ?? utxo.vout ?? 0,\n amount: utxo.value.toString(),\n address: utxo.address ?? '',\n isVested,\n confirmations: currentHeight - (utxo.height || currentHeight),\n coinbaseHeight: coinbaseHeight ?? undefined,\n });\n }\n\n return result;\n }\n\n async getHistory(limit?: number): Promise<L1Transaction[]> {\n this.ensureInitialized();\n\n const addresses = this._getWatchedAddresses();\n const transactions: L1Transaction[] = [];\n const seenTxids = new Set<string>();\n const currentHeight = await getCurrentBlockHeight();\n\n for (const address of addresses) {\n const history = await getTransactionHistory(address);\n\n for (const item of history) {\n if (seenTxids.has(item.tx_hash)) continue;\n seenTxids.add(item.tx_hash);\n\n const tx = (await l1GetTransaction(item.tx_hash)) as TransactionDetail | null;\n if (!tx) continue;\n\n // Determine if this is a send or receive\n const isSend = tx.vin?.some((vin) =>\n addresses.includes(vin.txid ?? '')\n );\n\n // Calculate amount from outputs going to our addresses\n let amount = '0';\n let txAddress = address;\n if (tx.vout) {\n for (const vout of tx.vout) {\n const voutAddresses = vout.scriptPubKey?.addresses ?? [];\n if (vout.scriptPubKey?.address) {\n voutAddresses.push(vout.scriptPubKey.address);\n }\n const matchedAddr = voutAddresses.find((a) => addresses.includes(a));\n if (matchedAddr) {\n amount = Math.floor((vout.value ?? 0) * 100_000_000).toString();\n txAddress = matchedAddr;\n break;\n }\n }\n }\n\n transactions.push({\n txid: item.tx_hash,\n type: isSend ? 'send' : 'receive',\n amount,\n address: txAddress,\n confirmations: item.height > 0 ? currentHeight - item.height : 0,\n timestamp: tx.time ? tx.time * 1000 : Date.now(),\n blockHeight: item.height > 0 ? item.height : undefined,\n });\n }\n }\n\n // Sort by block height descending\n transactions.sort((a, b) => (b.blockHeight ?? 0) - (a.blockHeight ?? 0));\n\n return limit ? transactions.slice(0, limit) : transactions;\n }\n\n async getTransaction(txid: string): Promise<L1Transaction | null> {\n this.ensureInitialized();\n\n const tx = (await l1GetTransaction(txid)) as TransactionDetail | null;\n if (!tx) return null;\n\n const addresses = this._getWatchedAddresses();\n const currentHeight = await getCurrentBlockHeight();\n\n // Determine if this is a send (our address in inputs)\n const isSend = tx.vin?.some((vin) =>\n addresses.includes(vin.txid ?? '')\n );\n\n let amount = '0';\n let txAddress = '';\n if (tx.vout) {\n for (const vout of tx.vout) {\n const voutAddresses = vout.scriptPubKey?.addresses ?? [];\n if (vout.scriptPubKey?.address) {\n voutAddresses.push(vout.scriptPubKey.address);\n }\n const matchedAddr = voutAddresses.find((a) => addresses.includes(a));\n if (matchedAddr) {\n amount = Math.floor((vout.value ?? 0) * 100_000_000).toString();\n txAddress = matchedAddr;\n break;\n }\n }\n }\n\n return {\n txid,\n type: isSend ? 'send' : 'receive',\n amount,\n address: txAddress,\n confirmations: tx.confirmations ?? 0,\n timestamp: tx.time ? tx.time * 1000 : Date.now(),\n blockHeight: tx.confirmations ? currentHeight - tx.confirmations + 1 : undefined,\n };\n }\n\n async estimateFee(\n to: string,\n amount: string\n ): Promise<{ fee: string; feeRate: number }> {\n this.ensureInitialized();\n\n if (!this._wallet) {\n return { fee: '0', feeRate: this._config.defaultFeeRate ?? 10 };\n }\n\n try {\n // Convert satoshis to ALPHA\n const amountAlpha = parseInt(amount, 10) / 100_000_000;\n\n const plan = await l1CreateTransactionPlan(\n this._wallet,\n to,\n amountAlpha\n );\n\n if (!plan.success) {\n return { fee: '0', feeRate: this._config.defaultFeeRate ?? 10 };\n }\n\n // Sum fees from all transactions\n const totalFee = plan.transactions.reduce((sum, tx) => sum + tx.fee, 0);\n\n return {\n fee: totalFee.toString(),\n feeRate: this._config.defaultFeeRate ?? 10,\n };\n } catch {\n return { fee: '10000', feeRate: this._config.defaultFeeRate ?? 10 };\n }\n }\n\n getAddresses(): string[] {\n return [...this._addresses];\n }\n\n addAddress(address: string): void {\n if (!this._addresses.includes(address)) {\n this._addresses.push(address);\n\n // Also add to wallet object\n if (this._wallet) {\n this._wallet.addresses.push({\n address,\n path: null,\n index: this._wallet.addresses.length,\n });\n }\n }\n }\n\n getVestingThreshold(): number {\n return VESTING_THRESHOLD;\n }\n\n isConnected(): boolean {\n return isWebSocketConnected();\n }\n\n private ensureInitialized(): void {\n if (!this._initialized) {\n throw new Error('L1PaymentsModule not initialized');\n }\n }\n\n private _getWatchedAddresses(): string[] {\n const addresses = [...this._addresses];\n if (this._identity?.address && !addresses.includes(this._identity.address)) {\n addresses.unshift(this._identity.address);\n }\n return addresses;\n }\n\n private async _getAllUtxos(): Promise<UTXO[]> {\n const addresses = this._getWatchedAddresses();\n const allUtxos: UTXO[] = [];\n\n for (const addr of addresses) {\n const utxos = await getUtxo(addr);\n allUtxos.push(...utxos);\n }\n\n return allUtxos;\n }\n}\n\n// =============================================================================\n// Factory\n// =============================================================================\n\nexport function createL1PaymentsModule(\n config?: L1PaymentsModuleConfig\n): L1PaymentsModule {\n return new L1PaymentsModule(config);\n}\n","/**\n * Token Split Calculator\n * Calculates optimal token splits for partial transfers\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type { Token } from '../../types';\nimport { Token as SdkToken } from '@unicitylabs/state-transition-sdk/lib/token/Token';\nimport { CoinId } from '@unicitylabs/state-transition-sdk/lib/token/fungible/CoinId';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface TokenWithAmount {\n sdkToken: SdkToken<any>;\n amount: bigint;\n uiToken: Token;\n}\n\nexport interface SplitPlan {\n /** Tokens that can be transferred directly (exact match or combination) */\n tokensToTransferDirectly: TokenWithAmount[];\n /** Token that needs to be split (if requiresSplit is true) */\n tokenToSplit: TokenWithAmount | null;\n /** Amount to send to recipient from split token */\n splitAmount: bigint | null;\n /** Amount to keep as change from split token */\n remainderAmount: bigint | null;\n /** Total amount being transferred */\n totalTransferAmount: bigint;\n /** Coin type being transferred */\n coinId: string;\n /** Whether a split operation is required */\n requiresSplit: boolean;\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\nexport class TokenSplitCalculator {\n /**\n * Calculate optimal split plan for transferring a specific amount\n *\n * Strategy:\n * 1. Try to find exact match (single token = amount)\n * 2. Try to find combination of tokens that sum to exact amount\n * 3. If no exact match, determine which token to split\n */\n async calculateOptimalSplit(\n availableTokens: Token[],\n targetAmount: bigint,\n targetCoinIdHex: string\n ): Promise<SplitPlan | null> {\n console.log(\n `[SplitCalculator] Calculating split for ${targetAmount} of ${targetCoinIdHex}`\n );\n console.log(`[SplitCalculator] Available tokens: ${availableTokens.length}`);\n\n const candidates: TokenWithAmount[] = [];\n\n // Build candidate list from available tokens\n for (const t of availableTokens) {\n console.log(`[SplitCalculator] Token ${t.id}: coinId=${t.coinId}, status=${t.status}, hasSdkData=${!!t.sdkData}`);\n if (t.coinId !== targetCoinIdHex) {\n console.log(`[SplitCalculator] Skipping token ${t.id}: coinId mismatch (${t.coinId} !== ${targetCoinIdHex})`);\n continue;\n }\n if (t.status !== 'confirmed') {\n console.log(`[SplitCalculator] Skipping token ${t.id}: status is ${t.status}`);\n continue;\n }\n if (!t.sdkData) {\n console.log(`[SplitCalculator] Skipping token ${t.id}: no sdkData`);\n continue;\n }\n\n try {\n const parsed = JSON.parse(t.sdkData);\n const sdkToken = await SdkToken.fromJSON(parsed);\n const realAmount = this.getTokenBalance(sdkToken, targetCoinIdHex);\n\n if (realAmount <= 0n) {\n console.warn(`[SplitCalculator] Token ${t.id} has 0 balance for coinId ${targetCoinIdHex}`);\n continue;\n }\n\n candidates.push({\n sdkToken,\n amount: realAmount,\n uiToken: t,\n });\n } catch (e) {\n console.warn('[SplitCalculator] Failed to parse token', t.id, e);\n }\n }\n\n // Sort by amount (ascending) for greedy algorithm\n candidates.sort((a, b) => (a.amount < b.amount ? -1 : 1));\n\n // Check total available\n const totalAvailable = candidates.reduce((sum, t) => sum + t.amount, 0n);\n if (totalAvailable < targetAmount) {\n console.error(\n `[SplitCalculator] Insufficient funds. Available: ${totalAvailable}, Required: ${targetAmount}`\n );\n return null;\n }\n\n // Strategy 1: Find exact match\n const exactMatch = candidates.find((t) => t.amount === targetAmount);\n if (exactMatch) {\n console.log('[SplitCalculator] Found exact match token');\n return this.createDirectPlan([exactMatch], targetAmount, targetCoinIdHex);\n }\n\n // Strategy 2: Try to find combination of tokens (up to 5)\n const maxCombinationSize = Math.min(5, candidates.length);\n for (let size = 2; size <= maxCombinationSize; size++) {\n const combo = this.findCombinationOfSize(candidates, targetAmount, size);\n if (combo) {\n console.log(`[SplitCalculator] Found exact combination of ${size} tokens`);\n return this.createDirectPlan(combo, targetAmount, targetCoinIdHex);\n }\n }\n\n // Strategy 3: Greedy selection with split\n const toTransfer: TokenWithAmount[] = [];\n let currentSum = 0n;\n\n for (const candidate of candidates) {\n const newSum = currentSum + candidate.amount;\n\n if (newSum === targetAmount) {\n // Perfect match found during greedy\n toTransfer.push(candidate);\n return this.createDirectPlan(toTransfer, targetAmount, targetCoinIdHex);\n } else if (newSum < targetAmount) {\n // Add to transfer set\n toTransfer.push(candidate);\n currentSum = newSum;\n } else {\n // Need to split this token\n const neededFromThisToken = targetAmount - currentSum;\n const remainderForSender = candidate.amount - neededFromThisToken;\n\n console.log(\n `[SplitCalculator] Split required. Sending: ${neededFromThisToken}, Remainder: ${remainderForSender}`\n );\n\n return {\n tokensToTransferDirectly: toTransfer,\n tokenToSplit: candidate,\n splitAmount: neededFromThisToken,\n remainderAmount: remainderForSender,\n totalTransferAmount: targetAmount,\n coinId: targetCoinIdHex,\n requiresSplit: true,\n };\n }\n }\n\n // Should not reach here if totalAvailable >= targetAmount\n return null;\n }\n\n /**\n * Get balance of a specific coin from token (lottery-compatible)\n */\n private getTokenBalance(sdkToken: SdkToken<any>, coinIdHex: string): bigint {\n try {\n if (!sdkToken.coins) {\n console.log('[SplitCalculator] Token has no coins');\n return 0n;\n }\n const coinId = CoinId.fromJSON(coinIdHex);\n const balance = sdkToken.coins.get(coinId);\n console.log(`[SplitCalculator] Token balance for ${coinIdHex.slice(0, 8)}...: ${balance ?? 0n}`);\n return balance ?? 0n;\n } catch (e) {\n console.error('[SplitCalculator] Error getting token balance:', e);\n return 0n;\n }\n }\n\n /**\n * Create a plan for direct transfer (no split needed)\n */\n private createDirectPlan(\n tokens: TokenWithAmount[],\n total: bigint,\n coinId: string\n ): SplitPlan {\n return {\n tokensToTransferDirectly: tokens,\n tokenToSplit: null,\n splitAmount: null,\n remainderAmount: null,\n totalTransferAmount: total,\n coinId,\n requiresSplit: false,\n };\n }\n\n /**\n * Find a combination of exactly `size` tokens that sum to targetAmount\n */\n private findCombinationOfSize(\n tokens: TokenWithAmount[],\n targetAmount: bigint,\n size: number\n ): TokenWithAmount[] | null {\n const generator = this.generateCombinations(tokens, size);\n\n for (const combo of generator) {\n const sum = combo.reduce((acc, t) => acc + t.amount, 0n);\n if (sum === targetAmount) {\n return combo;\n }\n }\n return null;\n }\n\n /**\n * Generator for k-combinations of tokens\n */\n private *generateCombinations(\n tokens: TokenWithAmount[],\n k: number,\n start: number = 0,\n current: TokenWithAmount[] = []\n ): Generator<TokenWithAmount[]> {\n if (k === 0) {\n yield current;\n return;\n }\n\n for (let i = start; i < tokens.length; i++) {\n yield* this.generateCombinations(tokens, k - 1, i + 1, [\n ...current,\n tokens[i],\n ]);\n }\n }\n}\n\n// =============================================================================\n// Factory\n// =============================================================================\n\nexport function createTokenSplitCalculator(): TokenSplitCalculator {\n return new TokenSplitCalculator();\n}\n","/**\n * Token Split Executor\n * Token split operations for payments\n *\n * Split flow:\n * 1. Burn original token\n * 2. Mint two new tokens: one for recipient, one for sender (change)\n * 3. Create transfer commitment for recipient token\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { Token } from '@unicitylabs/state-transition-sdk/lib/token/Token';\nimport { TokenId } from '@unicitylabs/state-transition-sdk/lib/token/TokenId';\nimport { TokenState } from '@unicitylabs/state-transition-sdk/lib/token/TokenState';\nimport { CoinId } from '@unicitylabs/state-transition-sdk/lib/token/fungible/CoinId';\nimport { TokenCoinData } from '@unicitylabs/state-transition-sdk/lib/token/fungible/TokenCoinData';\nimport { TokenSplitBuilder } from '@unicitylabs/state-transition-sdk/lib/transaction/split/TokenSplitBuilder';\nimport { HashAlgorithm } from '@unicitylabs/state-transition-sdk/lib/hash/HashAlgorithm';\nimport { UnmaskedPredicate } from '@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicate';\nimport { UnmaskedPredicateReference } from '@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicateReference';\nimport { TransferCommitment } from '@unicitylabs/state-transition-sdk/lib/transaction/TransferCommitment';\nimport { waitInclusionProof } from '@unicitylabs/state-transition-sdk/lib/util/InclusionProofUtils';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface SplitResult {\n tokenForRecipient: any;\n tokenForSender: any;\n recipientTransferTx: any;\n}\n\nexport interface TokenSplitExecutorConfig {\n stateTransitionClient: any;\n trustBase: any;\n signingService: any;\n}\n\n// =============================================================================\n// Hash Utilities\n// =============================================================================\n\nasync function sha256(input: string | Uint8Array): Promise<Uint8Array> {\n const data = typeof input === 'string' ? new TextEncoder().encode(input) : input;\n const buffer = new ArrayBuffer(data.length);\n new Uint8Array(buffer).set(data);\n const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);\n return new Uint8Array(hashBuffer);\n}\n\nfunction toHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\nfunction fromHex(hex: string): Uint8Array {\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);\n }\n return bytes;\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\nexport class TokenSplitExecutor {\n private client: any;\n private trustBase: any;\n private signingService: any;\n\n constructor(config: TokenSplitExecutorConfig) {\n this.client = config.stateTransitionClient;\n this.trustBase = config.trustBase;\n this.signingService = config.signingService;\n }\n\n async executeSplit(\n tokenToSplit: any,\n splitAmount: bigint,\n remainderAmount: bigint,\n coinIdHex: string,\n recipientAddress: any\n ): Promise<SplitResult> {\n const tokenIdHex = toHex(tokenToSplit.id.bytes);\n console.log(`[TokenSplitExecutor] Splitting token ${tokenIdHex.slice(0, 8)}...`);\n\n const coinId = new CoinId(fromHex(coinIdHex));\n const seedString = `${tokenIdHex}_${splitAmount.toString()}_${remainderAmount.toString()}`;\n\n // Generate IDs and salts\n const recipientTokenId = new TokenId(await sha256(seedString));\n const senderTokenId = new TokenId(await sha256(seedString + '_sender'));\n const recipientSalt = await sha256(seedString + '_recipient_salt');\n const senderSalt = await sha256(seedString + '_sender_salt');\n\n // Create sender address\n const senderAddressRef = await UnmaskedPredicateReference.create(\n tokenToSplit.type,\n this.signingService.algorithm,\n this.signingService.publicKey,\n HashAlgorithm.SHA256\n );\n const senderAddress = await senderAddressRef.toAddress();\n\n // Build split\n const builder = new TokenSplitBuilder();\n\n const coinDataA = TokenCoinData.create([[coinId, splitAmount]]);\n builder.createToken(recipientTokenId, tokenToSplit.type, new Uint8Array(0), coinDataA, senderAddress, recipientSalt, null);\n\n const coinDataB = TokenCoinData.create([[coinId, remainderAmount]]);\n builder.createToken(senderTokenId, tokenToSplit.type, new Uint8Array(0), coinDataB, senderAddress, senderSalt, null);\n\n const split = await builder.build(tokenToSplit);\n\n // Step 1: Burn\n console.log('[TokenSplitExecutor] Step 1: Burning original token...');\n const burnSalt = await sha256(seedString + '_burn_salt');\n const burnCommitment = await split.createBurnCommitment(burnSalt, this.signingService);\n\n const burnResponse = await this.client.submitTransferCommitment(burnCommitment);\n if (burnResponse.status !== 'SUCCESS' && burnResponse.status !== 'REQUEST_ID_EXISTS') {\n throw new Error(`Burn failed: ${burnResponse.status}`);\n }\n\n const burnInclusionProof = await waitInclusionProof(this.trustBase, this.client, burnCommitment);\n const burnTransaction = burnCommitment.toTransaction(burnInclusionProof);\n console.log('[TokenSplitExecutor] Original token burned.');\n\n // Step 2: Mint\n console.log('[TokenSplitExecutor] Step 2: Minting split tokens...');\n const mintCommitments = await split.createSplitMintCommitments(this.trustBase, burnTransaction);\n\n const mintedTokensInfo: Array<{ commitment: any; inclusionProof: any; isForRecipient: boolean; tokenId: any; salt: Uint8Array }> = [];\n\n for (const commitment of mintCommitments) {\n const res = await this.client.submitMintCommitment(commitment);\n if (res.status !== 'SUCCESS' && res.status !== 'REQUEST_ID_EXISTS') {\n throw new Error(`Mint split token failed: ${res.status}`);\n }\n\n const proof = await waitInclusionProof(this.trustBase, this.client, commitment);\n const commTokenIdHex = toHex(commitment.transactionData.tokenId.bytes);\n const recipientIdHex = toHex(recipientTokenId.bytes);\n\n mintedTokensInfo.push({\n commitment,\n inclusionProof: proof,\n isForRecipient: commTokenIdHex === recipientIdHex,\n tokenId: commitment.transactionData.tokenId,\n salt: commitment.transactionData.salt,\n });\n }\n console.log('[TokenSplitExecutor] Split tokens minted.');\n\n // Step 3: Reconstruct tokens\n const recipientInfo = mintedTokensInfo.find((t) => t.isForRecipient)!;\n const senderInfo = mintedTokensInfo.find((t) => !t.isForRecipient)!;\n\n const createToken = async (info: typeof recipientInfo, label: string) => {\n const predicate = await UnmaskedPredicate.create(info.tokenId, tokenToSplit.type, this.signingService, HashAlgorithm.SHA256, info.salt);\n const state = new TokenState(predicate, null);\n const token = await Token.mint(this.trustBase, state, info.commitment.toTransaction(info.inclusionProof));\n const verification = await token.verify(this.trustBase);\n if (!verification.isSuccessful) throw new Error(`Token verification failed: ${label}`);\n return token;\n };\n\n const recipientTokenBeforeTransfer = await createToken(recipientInfo, 'Recipient');\n const senderToken = await createToken(senderInfo, 'Sender');\n\n // Step 4: Transfer\n console.log('[TokenSplitExecutor] Step 3: Transferring to recipient...');\n const transferSalt = await sha256(seedString + '_transfer_salt');\n\n const transferCommitment = await TransferCommitment.create(\n recipientTokenBeforeTransfer,\n recipientAddress,\n transferSalt,\n null,\n null,\n this.signingService\n );\n\n const transferRes = await this.client.submitTransferCommitment(transferCommitment);\n if (transferRes.status !== 'SUCCESS' && transferRes.status !== 'REQUEST_ID_EXISTS') {\n throw new Error(`Transfer failed: ${transferRes.status}`);\n }\n\n const transferProof = await waitInclusionProof(this.trustBase, this.client, transferCommitment);\n const transferTx = transferCommitment.toTransaction(transferProof);\n\n console.log('[TokenSplitExecutor] Split transfer complete!');\n\n return {\n tokenForRecipient: recipientTokenBeforeTransfer,\n tokenForSender: senderToken,\n recipientTransferTx: transferTx,\n };\n }\n}\n\nexport function createTokenSplitExecutor(config: TokenSplitExecutorConfig): TokenSplitExecutor {\n return new TokenSplitExecutor(config);\n}\n","/**\n * Nametag Minter\n * Mints nametag tokens on-chain for PROXY address support\n *\n * Flow (same as Sphere wallet and lottery):\n * 1. Generate salt\n * 2. Create MintTransactionData from nametag\n * 3. Create MintCommitment\n * 4. Submit to aggregator\n * 5. Wait for inclusion proof\n * 6. Create Token with proof\n * 7. Return token for storage\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { Token } from '@unicitylabs/state-transition-sdk/lib/token/Token';\nimport { TokenId } from '@unicitylabs/state-transition-sdk/lib/token/TokenId';\nimport { TokenType } from '@unicitylabs/state-transition-sdk/lib/token/TokenType';\nimport { TokenState } from '@unicitylabs/state-transition-sdk/lib/token/TokenState';\nimport { MintTransactionData } from '@unicitylabs/state-transition-sdk/lib/transaction/MintTransactionData';\nimport { MintCommitment } from '@unicitylabs/state-transition-sdk/lib/transaction/MintCommitment';\nimport { SigningService } from '@unicitylabs/state-transition-sdk/lib/sign/SigningService';\nimport { HashAlgorithm } from '@unicitylabs/state-transition-sdk/lib/hash/HashAlgorithm';\nimport { UnmaskedPredicate } from '@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicate';\nimport { DirectAddress } from '@unicitylabs/state-transition-sdk/lib/address/DirectAddress';\nimport { waitInclusionProof } from '@unicitylabs/state-transition-sdk/lib/util/InclusionProofUtils';\nimport type { NametagData } from '../../types/txf';\n\n// =============================================================================\n// Constants\n// =============================================================================\n\n/**\n * Unicity token type for nametags\n * Same as used in Sphere wallet and lottery\n */\nconst UNICITY_TOKEN_TYPE_HEX = 'f8aa13834268d29355ff12183066f0cb902003629bbc5eb9ef0efbe397867509';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface NametagMinterConfig {\n stateTransitionClient: any;\n trustBase: any;\n signingService: SigningService;\n /** Skip trust base verification (dev mode) */\n skipVerification?: boolean;\n /** Enable debug logging */\n debug?: boolean;\n}\n\nexport interface MintNametagResult {\n success: boolean;\n token?: Token<any>;\n nametagData?: NametagData;\n error?: string;\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\nexport class NametagMinter {\n private client: any;\n private trustBase: any;\n private signingService: SigningService;\n private skipVerification: boolean;\n private debug: boolean;\n\n constructor(config: NametagMinterConfig) {\n this.client = config.stateTransitionClient;\n this.trustBase = config.trustBase;\n this.signingService = config.signingService;\n this.skipVerification = config.skipVerification ?? false;\n this.debug = config.debug ?? false;\n }\n\n private log(...args: unknown[]): void {\n if (this.debug) {\n console.log('[NametagMinter]', ...args);\n }\n }\n\n /**\n * Check if a nametag is available (not already minted)\n */\n async isNametagAvailable(nametag: string): Promise<boolean> {\n try {\n const cleanNametag = nametag.replace('@', '').trim();\n const nametagTokenId = await TokenId.fromNameTag(cleanNametag);\n\n const isMinted = await this.client.isMinted(this.trustBase, nametagTokenId);\n return !isMinted;\n } catch (error) {\n this.log('Error checking nametag availability:', error);\n return false;\n }\n }\n\n /**\n * Mint a nametag token on-chain\n *\n * @param nametag - The nametag to mint (e.g., \"alice\" or \"@alice\")\n * @param ownerAddress - The owner's direct address\n * @returns MintNametagResult with token if successful\n */\n async mintNametag(\n nametag: string,\n ownerAddress: DirectAddress\n ): Promise<MintNametagResult> {\n const cleanNametag = nametag.replace('@', '').trim();\n this.log(`Starting mint for nametag: ${cleanNametag}`);\n\n try {\n // 1. Check availability\n const isAvailable = await this.isNametagAvailable(cleanNametag);\n if (!isAvailable) {\n return {\n success: false,\n error: `Nametag \"${cleanNametag}\" is already taken`,\n };\n }\n\n // 2. Create token ID and type\n const nametagTokenId = await TokenId.fromNameTag(cleanNametag);\n const nametagTokenType = new TokenType(\n Buffer.from(UNICITY_TOKEN_TYPE_HEX, 'hex')\n );\n\n // 3. Generate salt\n const salt = new Uint8Array(32);\n crypto.getRandomValues(salt);\n this.log('Generated salt');\n\n // 4. Create mint transaction data\n const mintData = await MintTransactionData.createFromNametag(\n cleanNametag,\n nametagTokenType,\n ownerAddress,\n salt,\n ownerAddress\n );\n this.log('Created MintTransactionData');\n\n // 5. Create commitment\n const commitment = await MintCommitment.create(mintData);\n this.log('Created MintCommitment');\n\n // 6. Submit to aggregator with retries\n const MAX_RETRIES = 3;\n let submitSuccess = false;\n\n for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {\n try {\n this.log(`Submitting commitment (attempt ${attempt}/${MAX_RETRIES})...`);\n const response = await this.client.submitMintCommitment(commitment);\n\n if (response.status === 'SUCCESS' || response.status === 'REQUEST_ID_EXISTS') {\n this.log(`Commitment ${response.status === 'REQUEST_ID_EXISTS' ? 'already exists' : 'submitted successfully'}`);\n submitSuccess = true;\n break;\n } else {\n this.log(`Commitment failed: ${response.status}`);\n if (attempt === MAX_RETRIES) {\n return {\n success: false,\n error: `Failed to submit commitment after ${MAX_RETRIES} attempts: ${response.status}`,\n };\n }\n await new Promise(r => setTimeout(r, 1000 * attempt));\n }\n } catch (error) {\n this.log(`Attempt ${attempt} error:`, error);\n if (attempt === MAX_RETRIES) {\n return {\n success: false,\n error: `Submit failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n await new Promise(r => setTimeout(r, 1000 * attempt));\n }\n }\n\n if (!submitSuccess) {\n return {\n success: false,\n error: 'Failed to submit commitment after retries',\n };\n }\n\n // 7. Wait for inclusion proof\n this.log('Waiting for inclusion proof...');\n const inclusionProof = await waitInclusionProof(this.trustBase, this.client, commitment);\n this.log('Received inclusion proof');\n\n // 8. Create genesis transaction\n const genesisTransaction = commitment.toTransaction(inclusionProof);\n\n // 9. Create token predicate and state\n const nametagPredicate = await UnmaskedPredicate.create(\n nametagTokenId,\n nametagTokenType,\n this.signingService,\n HashAlgorithm.SHA256,\n salt\n );\n\n const tokenState = new TokenState(nametagPredicate, null);\n\n // 10. Create final token\n let token: Token<any>;\n\n if (this.skipVerification) {\n this.log('Creating token WITHOUT verification (dev mode)');\n const tokenJson = {\n version: '2.0',\n state: tokenState.toJSON(),\n genesis: genesisTransaction.toJSON(),\n transactions: [],\n nametags: [],\n };\n token = await Token.fromJSON(tokenJson);\n } else {\n token = await Token.mint(\n this.trustBase,\n tokenState,\n genesisTransaction\n );\n }\n\n this.log(`Nametag minted successfully: ${cleanNametag}`);\n\n // 11. Create NametagData for storage\n const nametagData: NametagData = {\n name: cleanNametag,\n token: token.toJSON(),\n timestamp: Date.now(),\n format: 'txf',\n version: '2.0',\n };\n\n return {\n success: true,\n token,\n nametagData,\n };\n } catch (error) {\n this.log('Minting failed:', error);\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n}\n\n// =============================================================================\n// Factory\n// =============================================================================\n\nexport function createNametagMinter(config: NametagMinterConfig): NametagMinter {\n return new NametagMinter(config);\n}\n","/**\n * SDK2 Constants\n * Default configuration values and storage keys\n */\n\n// =============================================================================\n// Storage Keys\n// =============================================================================\n\n/** Default prefix for all storage keys */\nexport const STORAGE_PREFIX = 'sphere_' as const;\n\n/**\n * Default encryption key for wallet data\n * WARNING: This is a placeholder. In production, use user-provided password.\n * This key is used when no password is provided to encrypt/decrypt mnemonic.\n */\nexport const DEFAULT_ENCRYPTION_KEY = 'sphere-default-key' as const;\n\n/** Storage keys for wallet data */\nexport const STORAGE_KEYS = {\n /** Encrypted BIP39 mnemonic */\n MNEMONIC: `${STORAGE_PREFIX}mnemonic`,\n /** Encrypted master private key */\n MASTER_KEY: `${STORAGE_PREFIX}master_key`,\n /** BIP32 chain code */\n CHAIN_CODE: `${STORAGE_PREFIX}chain_code`,\n /** HD derivation path (full path like m/44'/0'/0'/0/0) */\n DERIVATION_PATH: `${STORAGE_PREFIX}derivation_path`,\n /** Base derivation path (like m/44'/0'/0' without chain/index) */\n BASE_PATH: `${STORAGE_PREFIX}base_path`,\n /** Derivation mode: bip32, wif_hmac, legacy_hmac */\n DERIVATION_MODE: `${STORAGE_PREFIX}derivation_mode`,\n /** Wallet source: mnemonic, file, unknown */\n WALLET_SOURCE: `${STORAGE_PREFIX}wallet_source`,\n /** Wallet existence flag */\n WALLET_EXISTS: `${STORAGE_PREFIX}wallet_exists`,\n /** Registered nametag (legacy - single address) */\n NAMETAG: `${STORAGE_PREFIX}nametag`,\n /** Current active address index */\n CURRENT_ADDRESS_INDEX: `${STORAGE_PREFIX}current_address_index`,\n /** Address nametags map (JSON: { \"0\": \"alice\", \"1\": \"bob\" }) */\n ADDRESS_NAMETAGS: `${STORAGE_PREFIX}address_nametags`,\n /** Token data */\n TOKENS: `${STORAGE_PREFIX}tokens`,\n /** Pending transfers */\n PENDING_TRANSFERS: `${STORAGE_PREFIX}pending_transfers`,\n /** Transfer outbox */\n OUTBOX: `${STORAGE_PREFIX}outbox`,\n /** Conversations */\n CONVERSATIONS: `${STORAGE_PREFIX}conversations`,\n /** Messages */\n MESSAGES: `${STORAGE_PREFIX}messages`,\n /** Transaction history */\n TRANSACTION_HISTORY: `${STORAGE_PREFIX}transaction_history`,\n /** Archived tokens (spent token history) */\n ARCHIVED_TOKENS: `${STORAGE_PREFIX}archived_tokens`,\n /** Tombstones (records of deleted/spent tokens) */\n TOMBSTONES: `${STORAGE_PREFIX}tombstones`,\n /** Forked tokens (alternative histories) */\n FORKED_TOKENS: `${STORAGE_PREFIX}forked_tokens`,\n} as const;\n\n// =============================================================================\n// Nostr Defaults\n// =============================================================================\n\n/** Default Nostr relays */\nexport const DEFAULT_NOSTR_RELAYS = [\n 'wss://relay.unicity.network',\n 'wss://relay.damus.io',\n 'wss://nos.lol',\n 'wss://relay.nostr.band',\n] as const;\n\n/** Nostr event kinds used by SDK - must match @unicitylabs/nostr-js-sdk */\nexport const NOSTR_EVENT_KINDS = {\n /** NIP-04 encrypted direct message */\n DIRECT_MESSAGE: 4,\n /** Token transfer (Unicity custom - 31113) */\n TOKEN_TRANSFER: 31113,\n /** Payment request (Unicity custom - 31115) */\n PAYMENT_REQUEST: 31115,\n /** Payment request response (Unicity custom - 31116) */\n PAYMENT_REQUEST_RESPONSE: 31116,\n /** Nametag binding (NIP-78 app-specific data) */\n NAMETAG_BINDING: 30078,\n /** Public broadcast */\n BROADCAST: 1,\n} as const;\n\n// =============================================================================\n// Aggregator (Oracle) Defaults\n// =============================================================================\n\n/**\n * Default aggregator URL\n * Note: The aggregator is conceptually an oracle - a trusted service that provides\n * verifiable truth about token state through cryptographic inclusion proofs.\n */\nexport const DEFAULT_AGGREGATOR_URL = 'https://aggregator.unicity.network/rpc' as const;\n\n/** Dev aggregator URL */\nexport const DEV_AGGREGATOR_URL = 'https://dev-aggregator.dyndns.org/rpc' as const;\n\n/** Test aggregator URL (Goggregator) */\nexport const TEST_AGGREGATOR_URL = 'https://goggregator-test.unicity.network' as const;\n\n/** Default aggregator request timeout (ms) */\nexport const DEFAULT_AGGREGATOR_TIMEOUT = 30000;\n\n// =============================================================================\n// IPFS Defaults\n// =============================================================================\n\n/** Default IPFS gateways */\nexport const DEFAULT_IPFS_GATEWAYS = [\n 'https://ipfs.unicity.network',\n 'https://dweb.link',\n 'https://ipfs.io',\n] as const;\n\n/** Unicity IPFS bootstrap peers */\nexport const DEFAULT_IPFS_BOOTSTRAP_PEERS = [\n '/dns4/unicity-ipfs2.dyndns.org/tcp/4001/p2p/12D3KooWLNi5NDPPHbrfJakAQqwBqymYTTwMQXQKEWuCrJNDdmfh',\n '/dns4/unicity-ipfs3.dyndns.org/tcp/4001/p2p/12D3KooWQ4aujVE4ShLjdusNZBdffq3TbzrwT2DuWZY9H1Gxhwn6',\n '/dns4/unicity-ipfs4.dyndns.org/tcp/4001/p2p/12D3KooWJ1ByPfUzUrpYvgxKU8NZrR8i6PU1tUgMEbQX9Hh2DEn1',\n '/dns4/unicity-ipfs5.dyndns.org/tcp/4001/p2p/12D3KooWB1MdZZGHN5B8TvWXntbycfe7Cjcz7n6eZ9eykZadvmDv',\n] as const;\n\n// =============================================================================\n// Wallet Defaults\n// =============================================================================\n\n/** Default BIP32 base path (without chain/index) */\nexport const DEFAULT_BASE_PATH = \"m/44'/0'/0'\" as const;\n\n/** Default BIP32 derivation path (full path with chain/index) */\nexport const DEFAULT_DERIVATION_PATH = `${DEFAULT_BASE_PATH}/0/0` as const;\n\n/** Coin types */\nexport const COIN_TYPES = {\n /** ALPHA token (L1 blockchain) */\n ALPHA: 'ALPHA',\n /** Test token */\n TEST: 'TEST',\n} as const;\n\n// =============================================================================\n// L1 (ALPHA Blockchain) Defaults\n// =============================================================================\n\n/** Default Fulcrum electrum server for mainnet */\nexport const DEFAULT_ELECTRUM_URL = 'wss://fulcrum.alpha.unicity.network:50004' as const;\n\n/** Testnet Fulcrum electrum server */\nexport const TEST_ELECTRUM_URL = 'wss://fulcrum.alpha.testnet.unicity.network:50004' as const;\n\n// =============================================================================\n// Network Defaults\n// =============================================================================\n\n/** Testnet Nostr relays */\nexport const TEST_NOSTR_RELAYS = [\n 'wss://nostr-relay.testnet.unicity.network',\n] as const;\n\n/** Network configurations */\nexport const NETWORKS = {\n mainnet: {\n name: 'Mainnet',\n aggregatorUrl: DEFAULT_AGGREGATOR_URL,\n nostrRelays: DEFAULT_NOSTR_RELAYS,\n ipfsGateways: DEFAULT_IPFS_GATEWAYS,\n electrumUrl: DEFAULT_ELECTRUM_URL,\n },\n testnet: {\n name: 'Testnet',\n aggregatorUrl: TEST_AGGREGATOR_URL,\n nostrRelays: TEST_NOSTR_RELAYS,\n ipfsGateways: DEFAULT_IPFS_GATEWAYS,\n electrumUrl: TEST_ELECTRUM_URL,\n },\n dev: {\n name: 'Development',\n aggregatorUrl: DEV_AGGREGATOR_URL,\n nostrRelays: TEST_NOSTR_RELAYS,\n ipfsGateways: DEFAULT_IPFS_GATEWAYS,\n electrumUrl: TEST_ELECTRUM_URL,\n },\n} as const;\n\nexport type NetworkType = keyof typeof NETWORKS;\nexport type NetworkConfig = (typeof NETWORKS)[NetworkType];\n\n// =============================================================================\n// Timeouts & Limits\n// =============================================================================\n\n/** Default timeouts (ms) */\nexport const TIMEOUTS = {\n /** WebSocket connection timeout */\n WEBSOCKET_CONNECT: 10000,\n /** Nostr relay reconnect delay */\n NOSTR_RECONNECT_DELAY: 3000,\n /** Max reconnect attempts */\n MAX_RECONNECT_ATTEMPTS: 5,\n /** Proof polling interval */\n PROOF_POLL_INTERVAL: 1000,\n /** Sync interval */\n SYNC_INTERVAL: 60000,\n} as const;\n\n/** Validation limits */\nexport const LIMITS = {\n /** Min nametag length */\n NAMETAG_MIN_LENGTH: 3,\n /** Max nametag length */\n NAMETAG_MAX_LENGTH: 20,\n /** Max memo length */\n MEMO_MAX_LENGTH: 500,\n /** Max message length */\n MESSAGE_MAX_LENGTH: 10000,\n} as const;\n","/**\n * TXF (Token eXchange Format) Type Definitions\n * Based on TXF Format Specification v2.0\n *\n * These types define the serialization format for tokens,\n * independent of any UI or storage implementation.\n */\n\n// =============================================================================\n// TXF Token Structure (v2.0)\n// =============================================================================\n\n/**\n * Complete token object in TXF format\n */\nexport interface TxfToken {\n version: '2.0';\n genesis: TxfGenesis;\n state: TxfState;\n transactions: TxfTransaction[];\n nametags?: string[];\n _integrity?: TxfIntegrity;\n}\n\n/**\n * Genesis transaction (initial minting)\n */\nexport interface TxfGenesis {\n data: TxfGenesisData;\n inclusionProof: TxfInclusionProof;\n}\n\n/**\n * Genesis data payload\n */\nexport interface TxfGenesisData {\n tokenId: string; // 64-char hex\n tokenType: string; // 64-char hex\n coinData: [string, string][]; // [[coinId, amount], ...]\n tokenData: string; // Optional metadata\n salt: string; // 64-char hex\n recipient: string; // DIRECT://... address\n recipientDataHash: string | null;\n reason: string | null;\n}\n\n/**\n * Current token state\n */\nexport interface TxfState {\n data: string;\n predicate: string; // Hex-encoded CBOR predicate\n}\n\n/**\n * State transition transaction\n */\nexport interface TxfTransaction {\n previousStateHash: string;\n newStateHash?: string;\n predicate: string;\n inclusionProof: TxfInclusionProof | null; // null = uncommitted\n data?: Record<string, unknown>;\n}\n\n/**\n * Sparse Merkle Tree inclusion proof\n */\nexport interface TxfInclusionProof {\n authenticator: TxfAuthenticator;\n merkleTreePath: TxfMerkleTreePath;\n transactionHash: string;\n unicityCertificate: string; // Hex-encoded CBOR\n}\n\n/**\n * Proof authenticator\n */\nexport interface TxfAuthenticator {\n algorithm: string;\n publicKey: string;\n signature: string;\n stateHash: string;\n}\n\n/**\n * Merkle tree path for proof verification\n */\nexport interface TxfMerkleTreePath {\n root: string;\n steps: TxfMerkleStep[];\n}\n\n/**\n * Single step in merkle path\n */\nexport interface TxfMerkleStep {\n data: string;\n path: string;\n}\n\n/**\n * Token integrity metadata\n */\nexport interface TxfIntegrity {\n genesisDataJSONHash: string;\n currentStateHash?: string;\n}\n\n// =============================================================================\n// Storage Format (for IPFS/File storage)\n// =============================================================================\n\n/**\n * Nametag data (one per identity)\n */\nexport interface NametagData {\n name: string;\n token: object;\n timestamp: number;\n format: string;\n version: string;\n}\n\n/**\n * Tombstone entry for tracking spent token states\n */\nexport interface TombstoneEntry {\n tokenId: string;\n stateHash: string;\n timestamp: number;\n}\n\n/**\n * Invalidated nametag entry\n */\nexport interface InvalidatedNametagEntry {\n name: string;\n token: object;\n timestamp: number;\n format: string;\n version: string;\n invalidatedAt: number;\n invalidationReason: string;\n}\n\n/**\n * Outbox entry for pending transfers\n */\nexport interface OutboxEntry {\n id: string;\n status: 'pending' | 'submitted' | 'confirmed' | 'delivered' | 'failed';\n sourceTokenId: string;\n salt: string;\n commitmentJson: string;\n recipientPubkey: string;\n recipientNametag?: string;\n amount: string;\n createdAt: number;\n updatedAt: number;\n error?: string;\n retryCount?: number;\n}\n\n/**\n * Mint outbox entry for pending mints\n */\nexport interface MintOutboxEntry {\n id: string;\n status: 'pending' | 'submitted' | 'confirmed' | 'failed';\n type: 'split' | 'faucet' | 'other';\n salt: string;\n requestIdHex: string;\n mintDataJson: string;\n createdAt: number;\n updatedAt: number;\n error?: string;\n}\n\n/**\n * Storage metadata\n */\nexport interface TxfMeta {\n version: number;\n address: string;\n ipnsName: string;\n formatVersion: '2.0';\n lastCid?: string;\n deviceId?: string;\n}\n\n/**\n * Complete storage data structure\n */\nexport interface TxfStorageData {\n _meta: TxfMeta;\n _nametag?: NametagData;\n _tombstones?: TombstoneEntry[];\n _invalidatedNametags?: InvalidatedNametagEntry[];\n _outbox?: OutboxEntry[];\n _mintOutbox?: MintOutboxEntry[];\n [key: string]: TxfToken | TxfMeta | NametagData | TombstoneEntry[] | InvalidatedNametagEntry[] | OutboxEntry[] | MintOutboxEntry[] | undefined;\n}\n\n// =============================================================================\n// Token Storage Provider Interface\n// =============================================================================\n\n/**\n * Base interface that storage providers must implement\n * to support TXF token storage\n */\nexport interface TxfStorageDataBase {\n _meta: TxfMeta;\n _nametag?: NametagData;\n _tombstones?: TombstoneEntry[];\n _invalidatedNametags?: InvalidatedNametagEntry[];\n _outbox?: OutboxEntry[];\n _mintOutbox?: MintOutboxEntry[];\n [key: string]: unknown;\n}\n\n// =============================================================================\n// Validation Types\n// =============================================================================\n\nexport interface ValidationIssue {\n tokenId: string;\n reason: string;\n recoverable?: boolean;\n}\n\nexport interface TokenValidationResult {\n isValid: boolean;\n reason?: string;\n action?: 'ACCEPT' | 'RETRY_LATER' | 'DISCARD_FORK';\n}\n\n// =============================================================================\n// Key Utilities\n// =============================================================================\n\nconst ARCHIVED_PREFIX = '_archived_';\nconst FORKED_PREFIX = '_forked_';\nconst RESERVED_KEYS = ['_meta', '_nametag', '_tombstones', '_invalidatedNametags', '_outbox', '_mintOutbox', '_sent', '_invalid', '_integrity'];\n\n/**\n * Check if a key is an active token key\n */\nexport function isTokenKey(key: string): boolean {\n return key.startsWith('_') &&\n !key.startsWith(ARCHIVED_PREFIX) &&\n !key.startsWith(FORKED_PREFIX) &&\n !RESERVED_KEYS.includes(key);\n}\n\n/**\n * Check if a key is an archived token key\n */\nexport function isArchivedKey(key: string): boolean {\n return key.startsWith(ARCHIVED_PREFIX);\n}\n\n/**\n * Check if a key is a forked token key\n */\nexport function isForkedKey(key: string): boolean {\n return key.startsWith(FORKED_PREFIX);\n}\n\n/**\n * Extract token ID from storage key\n */\nexport function tokenIdFromKey(key: string): string {\n return key.startsWith('_') ? key.substring(1) : key;\n}\n\n/**\n * Create storage key from token ID\n */\nexport function keyFromTokenId(tokenId: string): string {\n return `_${tokenId}`;\n}\n\n/**\n * Extract token ID from archived key\n */\nexport function tokenIdFromArchivedKey(key: string): string {\n return key.startsWith(ARCHIVED_PREFIX) ? key.substring(ARCHIVED_PREFIX.length) : key;\n}\n\n/**\n * Create archived key from token ID\n */\nexport function archivedKeyFromTokenId(tokenId: string): string {\n return `${ARCHIVED_PREFIX}${tokenId}`;\n}\n\n/**\n * Create forked key from token ID and state hash\n */\nexport function forkedKeyFromTokenIdAndState(tokenId: string, stateHash: string): string {\n return `${FORKED_PREFIX}${tokenId}_${stateHash}`;\n}\n\n/**\n * Parse forked key into tokenId and stateHash\n */\nexport function parseForkedKey(key: string): { tokenId: string; stateHash: string } | null {\n if (!key.startsWith(FORKED_PREFIX)) return null;\n const remainder = key.substring(FORKED_PREFIX.length);\n const underscoreIndex = remainder.indexOf('_');\n if (underscoreIndex === -1 || underscoreIndex < 64) return null;\n return {\n tokenId: remainder.substring(0, underscoreIndex),\n stateHash: remainder.substring(underscoreIndex + 1),\n };\n}\n\n/**\n * Validate 64-character hex token ID\n */\nexport function isValidTokenId(tokenId: string): boolean {\n return /^[0-9a-fA-F]{64}$/.test(tokenId);\n}\n","/**\n * TXF Serializer for SDK2\n * Converts between SDK Token format and TXF storage format\n *\n * Platform-independent implementation that works with SDK types directly.\n */\n\nimport type {\n TxfToken,\n TxfTransaction,\n TxfStorageData,\n TxfMeta,\n NametagData,\n TombstoneEntry,\n OutboxEntry,\n MintOutboxEntry,\n InvalidatedNametagEntry,\n} from '../types/txf';\nimport {\n isTokenKey,\n isArchivedKey,\n isForkedKey,\n tokenIdFromKey,\n tokenIdFromArchivedKey,\n parseForkedKey,\n keyFromTokenId,\n archivedKeyFromTokenId,\n forkedKeyFromTokenIdAndState,\n} from '../types/txf';\nimport type { Token, TokenStatus } from '../types';\n\n// =============================================================================\n// SDK Token Normalization\n// =============================================================================\n\n/**\n * Convert bytes array/object to hex string\n */\nfunction bytesToHex(bytes: number[] | Uint8Array): string {\n const arr = Array.isArray(bytes) ? bytes : Array.from(bytes);\n return arr.map(b => b.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * Normalize a value that may be a hex string, bytes object, or Buffer to hex string\n */\nfunction normalizeToHex(value: unknown): string {\n if (typeof value === 'string') {\n return value;\n }\n if (value && typeof value === 'object') {\n const obj = value as Record<string, unknown>;\n // SDK format: { bytes: [...] }\n if ('bytes' in obj && (Array.isArray(obj.bytes) || obj.bytes instanceof Uint8Array)) {\n return bytesToHex(obj.bytes as number[] | Uint8Array);\n }\n // Buffer.toJSON() format: { type: \"Buffer\", data: [...] }\n if (obj.type === 'Buffer' && Array.isArray(obj.data)) {\n return bytesToHex(obj.data as number[]);\n }\n }\n return String(value);\n}\n\n/**\n * Normalize SDK token JSON to canonical TXF storage format.\n * Converts all bytes objects to hex strings before storage.\n */\nexport function normalizeSdkTokenToStorage(sdkTokenJson: unknown): TxfToken {\n const txf = JSON.parse(JSON.stringify(sdkTokenJson));\n\n // Normalize genesis.data fields\n if (txf.genesis?.data) {\n const data = txf.genesis.data;\n if (data.tokenId !== undefined) {\n data.tokenId = normalizeToHex(data.tokenId);\n }\n if (data.tokenType !== undefined) {\n data.tokenType = normalizeToHex(data.tokenType);\n }\n if (data.salt !== undefined) {\n data.salt = normalizeToHex(data.salt);\n }\n }\n\n // Normalize authenticator fields in genesis inclusion proof\n if (txf.genesis?.inclusionProof?.authenticator) {\n const auth = txf.genesis.inclusionProof.authenticator;\n if (auth.publicKey !== undefined) {\n auth.publicKey = normalizeToHex(auth.publicKey);\n }\n if (auth.signature !== undefined) {\n auth.signature = normalizeToHex(auth.signature);\n }\n }\n\n // Normalize transaction authenticators\n if (Array.isArray(txf.transactions)) {\n for (const tx of txf.transactions) {\n if (tx.inclusionProof?.authenticator) {\n const auth = tx.inclusionProof.authenticator;\n if (auth.publicKey !== undefined) {\n auth.publicKey = normalizeToHex(auth.publicKey);\n }\n if (auth.signature !== undefined) {\n auth.signature = normalizeToHex(auth.signature);\n }\n }\n }\n }\n\n return txf as TxfToken;\n}\n\n// =============================================================================\n// Token → TXF Conversion\n// =============================================================================\n\n/**\n * Extract TXF token structure from Token.sdkData (jsonData)\n */\nexport function tokenToTxf(token: Token): TxfToken | null {\n const jsonData = token.sdkData;\n if (!jsonData) {\n return null;\n }\n\n try {\n const txfData = normalizeSdkTokenToStorage(JSON.parse(jsonData));\n\n if (!txfData.genesis || !txfData.state) {\n return null;\n }\n\n // Ensure required fields\n if (!txfData.version) {\n txfData.version = '2.0';\n }\n if (!txfData.transactions) {\n txfData.transactions = [];\n }\n if (!txfData.nametags) {\n txfData.nametags = [];\n }\n if (!txfData._integrity) {\n txfData._integrity = {\n genesisDataJSONHash: '0000' + '0'.repeat(60),\n };\n }\n\n return txfData;\n } catch {\n return null;\n }\n}\n\n/**\n * Convert token interface to simplified Token for parsing\n */\ninterface TokenLike {\n id: string;\n sdkData?: string;\n}\n\n/**\n * Extract TXF from any object with id and sdkData\n */\nexport function objectToTxf(obj: TokenLike): TxfToken | null {\n if (!obj.sdkData) return null;\n try {\n const txfData = normalizeSdkTokenToStorage(JSON.parse(obj.sdkData));\n if (!txfData.genesis || !txfData.state) return null;\n return txfData;\n } catch {\n return null;\n }\n}\n\n// =============================================================================\n// TXF → Token Conversion\n// =============================================================================\n\n/**\n * Determine token status from TXF data\n */\nfunction determineTokenStatus(txf: TxfToken): TokenStatus {\n if (txf.transactions.length > 0) {\n const lastTx = txf.transactions[txf.transactions.length - 1];\n if (lastTx.inclusionProof === null) {\n return 'pending';\n }\n }\n return 'confirmed';\n}\n\n/**\n * Convert TXF token to Token interface\n */\nexport function txfToToken(tokenId: string, txf: TxfToken): Token {\n const coinData = txf.genesis.data.coinData;\n const totalAmount = coinData.reduce((sum, [, amt]) => {\n return sum + BigInt(amt || '0');\n }, BigInt(0));\n\n // Get coin ID (use first non-zero coin, or first coin)\n let coinId = coinData[0]?.[0] || '';\n for (const [cid, amt] of coinData) {\n if (BigInt(amt || '0') > 0) {\n coinId = cid;\n break;\n }\n }\n\n const tokenType = txf.genesis.data.tokenType;\n const isNft = tokenType === '455ad8720656b08e8dbd5bac1f3c73eeea5431565f6c1c3af742b1aa12d41d89';\n\n const now = Date.now();\n\n return {\n id: tokenId,\n coinId,\n symbol: isNft ? 'NFT' : 'UCT',\n name: isNft ? 'NFT' : 'Token',\n amount: totalAmount.toString(),\n status: determineTokenStatus(txf),\n createdAt: now,\n updatedAt: now,\n sdkData: JSON.stringify(txf),\n };\n}\n\n// =============================================================================\n// Storage Data Building\n// =============================================================================\n\n/**\n * Build TXF storage data from tokens and metadata\n */\nexport async function buildTxfStorageData(\n tokens: Token[],\n meta: Omit<TxfMeta, 'formatVersion'>,\n options?: {\n nametag?: NametagData;\n tombstones?: TombstoneEntry[];\n archivedTokens?: Map<string, TxfToken>;\n forkedTokens?: Map<string, TxfToken>;\n outboxEntries?: OutboxEntry[];\n mintOutboxEntries?: MintOutboxEntry[];\n invalidatedNametags?: InvalidatedNametagEntry[];\n }\n): Promise<TxfStorageData> {\n const storageData: TxfStorageData = {\n _meta: {\n ...meta,\n formatVersion: '2.0',\n },\n };\n\n if (options?.nametag) {\n storageData._nametag = options.nametag;\n }\n\n if (options?.tombstones && options.tombstones.length > 0) {\n storageData._tombstones = options.tombstones;\n }\n\n if (options?.outboxEntries && options.outboxEntries.length > 0) {\n storageData._outbox = options.outboxEntries;\n }\n\n if (options?.mintOutboxEntries && options.mintOutboxEntries.length > 0) {\n storageData._mintOutbox = options.mintOutboxEntries;\n }\n\n if (options?.invalidatedNametags && options.invalidatedNametags.length > 0) {\n storageData._invalidatedNametags = options.invalidatedNametags;\n }\n\n // Add active tokens\n for (const token of tokens) {\n const txf = tokenToTxf(token);\n if (txf) {\n const actualTokenId = txf.genesis.data.tokenId;\n storageData[keyFromTokenId(actualTokenId)] = txf;\n }\n }\n\n // Add archived tokens\n if (options?.archivedTokens && options.archivedTokens.size > 0) {\n for (const [tokenId, txf] of options.archivedTokens) {\n storageData[archivedKeyFromTokenId(tokenId)] = txf;\n }\n }\n\n // Add forked tokens\n if (options?.forkedTokens && options.forkedTokens.size > 0) {\n for (const [key, txf] of options.forkedTokens) {\n const [tokenId, stateHash] = key.split('_');\n if (tokenId && stateHash) {\n storageData[forkedKeyFromTokenIdAndState(tokenId, stateHash)] = txf;\n }\n }\n }\n\n return storageData;\n}\n\n// =============================================================================\n// Storage Data Parsing\n// =============================================================================\n\nexport interface ParsedStorageData {\n tokens: Token[];\n meta: TxfMeta | null;\n nametag: NametagData | null;\n tombstones: TombstoneEntry[];\n archivedTokens: Map<string, TxfToken>;\n forkedTokens: Map<string, TxfToken>;\n outboxEntries: OutboxEntry[];\n mintOutboxEntries: MintOutboxEntry[];\n invalidatedNametags: InvalidatedNametagEntry[];\n validationErrors: string[];\n}\n\n/**\n * Parse TXF storage data\n */\nexport function parseTxfStorageData(data: unknown): ParsedStorageData {\n const result: ParsedStorageData = {\n tokens: [],\n meta: null,\n nametag: null,\n tombstones: [],\n archivedTokens: new Map(),\n forkedTokens: new Map(),\n outboxEntries: [],\n mintOutboxEntries: [],\n invalidatedNametags: [],\n validationErrors: [],\n };\n\n if (!data || typeof data !== 'object') {\n result.validationErrors.push('Storage data is not an object');\n return result;\n }\n\n const storageData = data as Record<string, unknown>;\n\n // Extract metadata\n if (storageData._meta && typeof storageData._meta === 'object') {\n result.meta = storageData._meta as TxfMeta;\n }\n\n // Extract nametag\n if (storageData._nametag && typeof storageData._nametag === 'object') {\n result.nametag = storageData._nametag as NametagData;\n }\n\n // Extract tombstones\n if (storageData._tombstones && Array.isArray(storageData._tombstones)) {\n for (const entry of storageData._tombstones) {\n if (\n typeof entry === 'object' &&\n entry !== null &&\n typeof (entry as TombstoneEntry).tokenId === 'string' &&\n typeof (entry as TombstoneEntry).stateHash === 'string' &&\n typeof (entry as TombstoneEntry).timestamp === 'number'\n ) {\n result.tombstones.push(entry as TombstoneEntry);\n }\n }\n }\n\n // Extract outbox entries\n if (storageData._outbox && Array.isArray(storageData._outbox)) {\n for (const entry of storageData._outbox) {\n if (\n typeof entry === 'object' &&\n entry !== null &&\n typeof (entry as OutboxEntry).id === 'string' &&\n typeof (entry as OutboxEntry).status === 'string'\n ) {\n result.outboxEntries.push(entry as OutboxEntry);\n }\n }\n }\n\n // Extract mint outbox entries\n if (storageData._mintOutbox && Array.isArray(storageData._mintOutbox)) {\n for (const entry of storageData._mintOutbox) {\n if (\n typeof entry === 'object' &&\n entry !== null &&\n typeof (entry as MintOutboxEntry).id === 'string' &&\n typeof (entry as MintOutboxEntry).status === 'string'\n ) {\n result.mintOutboxEntries.push(entry as MintOutboxEntry);\n }\n }\n }\n\n // Extract invalidated nametags\n if (storageData._invalidatedNametags && Array.isArray(storageData._invalidatedNametags)) {\n for (const entry of storageData._invalidatedNametags) {\n if (\n typeof entry === 'object' &&\n entry !== null &&\n typeof (entry as InvalidatedNametagEntry).name === 'string'\n ) {\n result.invalidatedNametags.push(entry as InvalidatedNametagEntry);\n }\n }\n }\n\n // Extract tokens\n for (const key of Object.keys(storageData)) {\n // Active tokens\n if (isTokenKey(key)) {\n const tokenId = tokenIdFromKey(key);\n try {\n const txfToken = storageData[key] as TxfToken;\n if (txfToken?.genesis?.data?.tokenId) {\n const token = txfToToken(tokenId, txfToken);\n result.tokens.push(token);\n }\n } catch (err) {\n result.validationErrors.push(`Token ${tokenId}: ${err}`);\n }\n }\n // Archived tokens\n else if (isArchivedKey(key)) {\n const tokenId = tokenIdFromArchivedKey(key);\n try {\n const txfToken = storageData[key] as TxfToken;\n if (txfToken?.genesis?.data?.tokenId) {\n result.archivedTokens.set(tokenId, txfToken);\n }\n } catch {\n result.validationErrors.push(`Archived token ${tokenId}: invalid structure`);\n }\n }\n // Forked tokens\n else if (isForkedKey(key)) {\n const parsed = parseForkedKey(key);\n if (parsed) {\n try {\n const txfToken = storageData[key] as TxfToken;\n if (txfToken?.genesis?.data?.tokenId) {\n const mapKey = `${parsed.tokenId}_${parsed.stateHash}`;\n result.forkedTokens.set(mapKey, txfToken);\n }\n } catch {\n result.validationErrors.push(`Forked token ${parsed.tokenId}: invalid structure`);\n }\n }\n }\n }\n\n return result;\n}\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\n/**\n * Get token ID from Token object (prefers genesis.data.tokenId)\n */\nexport function getTokenId(token: Token): string {\n if (token.sdkData) {\n try {\n const txf = JSON.parse(token.sdkData);\n if (txf.genesis?.data?.tokenId) {\n return txf.genesis.data.tokenId;\n }\n } catch {\n // Fall through\n }\n }\n return token.id;\n}\n\n/**\n * Get the current state hash from a TXF token\n */\nexport function getCurrentStateHash(txf: TxfToken): string | undefined {\n if (txf.transactions && txf.transactions.length > 0) {\n const lastTx = txf.transactions[txf.transactions.length - 1];\n if (lastTx?.newStateHash) {\n return lastTx.newStateHash;\n }\n return undefined;\n }\n\n if (txf._integrity?.currentStateHash) {\n return txf._integrity.currentStateHash;\n }\n\n return undefined;\n}\n\n/**\n * Check if token has valid TXF data\n */\nexport function hasValidTxfData(token: Token): boolean {\n if (!token.sdkData) return false;\n\n try {\n const txf = JSON.parse(token.sdkData);\n return !!(\n txf.genesis &&\n txf.genesis.data &&\n txf.genesis.data.tokenId &&\n txf.state &&\n txf.genesis.inclusionProof\n );\n } catch {\n return false;\n }\n}\n\n/**\n * Check if token has uncommitted transactions\n */\nexport function hasUncommittedTransactions(token: Token): boolean {\n if (!token.sdkData) return false;\n\n try {\n const txf = JSON.parse(token.sdkData);\n if (!txf.transactions || txf.transactions.length === 0) return false;\n\n return txf.transactions.some(\n (tx: TxfTransaction) => tx.inclusionProof === null\n );\n } catch {\n return false;\n }\n}\n\n/**\n * Check if a TXF token has missing newStateHash on any transaction\n */\nexport function hasMissingNewStateHash(txf: TxfToken): boolean {\n if (!txf.transactions || txf.transactions.length === 0) {\n return false;\n }\n return txf.transactions.some(tx => !tx.newStateHash);\n}\n\n/**\n * Count committed transactions in a token\n */\nexport function countCommittedTransactions(token: Token): number {\n if (!token.sdkData) return 0;\n\n try {\n const txf = JSON.parse(token.sdkData);\n if (!txf.transactions) return 0;\n\n return txf.transactions.filter(\n (tx: TxfTransaction) => tx.inclusionProof !== null\n ).length;\n } catch {\n return 0;\n }\n}\n","/**\n * Payments Module\n * Platform-independent token operations with full wallet repository functionality\n *\n * Includes:\n * - Token CRUD operations\n * - Tombstones for sync\n * - Archived tokens (spent history)\n * - Forked tokens (alternative histories)\n * - Transaction history\n * - Nametag storage\n */\n\nimport type {\n Token,\n TokenBalance,\n TokenStatus,\n TransferRequest,\n TransferResult,\n IncomingTransfer,\n FullIdentity,\n SphereEventType,\n SphereEventMap,\n} from '../../types';\nimport type {\n TxfToken,\n TxfTransaction,\n TombstoneEntry,\n NametagData,\n} from '../../types/txf';\nimport { L1PaymentsModule, type L1PaymentsModuleConfig } from './L1PaymentsModule';\nimport { TokenSplitCalculator } from './TokenSplitCalculator';\nimport { TokenSplitExecutor } from './TokenSplitExecutor';\nimport { NametagMinter, type MintNametagResult } from './NametagMinter';\nimport type { StorageProvider, TokenStorageProvider, TxfStorageDataBase } from '../../storage';\nimport type {\n TransportProvider,\n IncomingTokenTransfer,\n PaymentRequestPayload,\n PaymentRequestResponsePayload,\n IncomingPaymentRequest as TransportPaymentRequest,\n IncomingPaymentRequestResponse as TransportPaymentRequestResponse,\n} from '../../transport';\nimport type { OracleProvider } from '../../oracle';\nimport type {\n PaymentRequest,\n IncomingPaymentRequest,\n OutgoingPaymentRequest,\n PaymentRequestResult,\n PaymentRequestStatus,\n PaymentRequestHandler,\n PaymentRequestResponse,\n PaymentRequestResponseHandler,\n} from '../../types';\nimport { STORAGE_KEYS } from '../../constants';\nimport {\n tokenToTxf,\n getCurrentStateHash,\n buildTxfStorageData,\n parseTxfStorageData,\n} from '../../serialization/txf-serializer';\n\n// SDK imports for token parsing and transfers\nimport { Token as SdkToken } from '@unicitylabs/state-transition-sdk/lib/token/Token';\nimport { TokenId } from '@unicitylabs/state-transition-sdk/lib/token/TokenId';\nimport { CoinId } from '@unicitylabs/state-transition-sdk/lib/token/fungible/CoinId';\nimport { TransferCommitment } from '@unicitylabs/state-transition-sdk/lib/transaction/TransferCommitment';\nimport { TransferTransaction } from '@unicitylabs/state-transition-sdk/lib/transaction/TransferTransaction';\nimport { SigningService } from '@unicitylabs/state-transition-sdk/lib/sign/SigningService';\nimport { ProxyAddress } from '@unicitylabs/state-transition-sdk/lib/address/ProxyAddress';\nimport { AddressScheme } from '@unicitylabs/state-transition-sdk/lib/address/AddressScheme';\nimport { UnmaskedPredicate } from '@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicate';\nimport { TokenState } from '@unicitylabs/state-transition-sdk/lib/token/TokenState';\nimport { HashAlgorithm } from '@unicitylabs/state-transition-sdk/lib/hash/HashAlgorithm';\nimport type { IAddress } from '@unicitylabs/state-transition-sdk/lib/address/IAddress';\nimport type { StateTransitionClient } from '@unicitylabs/state-transition-sdk/lib/StateTransitionClient';\n\n// =============================================================================\n// Transaction History Entry\n// =============================================================================\n\nexport interface TransactionHistoryEntry {\n id: string;\n type: 'SENT' | 'RECEIVED' | 'SPLIT' | 'MINT';\n amount: string;\n coinId: string;\n symbol: string;\n timestamp: number;\n recipientNametag?: string;\n senderPubkey?: string;\n txHash?: string;\n}\n\n// =============================================================================\n// Token Parsing Utilities\n// =============================================================================\n\ninterface ParsedTokenInfo {\n coinId: string;\n symbol: string;\n name: string;\n amount: string;\n tokenId?: string;\n}\n\n/**\n * Parse token info from SDK token data or TXF JSON\n */\nasync function parseTokenInfo(tokenData: unknown): Promise<ParsedTokenInfo> {\n const defaultInfo: ParsedTokenInfo = {\n coinId: 'ALPHA',\n symbol: 'ALPHA',\n name: 'Alpha Token',\n amount: '0',\n };\n\n try {\n // If it's a string, try to parse as JSON\n const data = typeof tokenData === 'string' ? JSON.parse(tokenData) : tokenData;\n\n // Try to create SDK token and extract coin info using SDK methods\n try {\n const sdkToken = await SdkToken.fromJSON(data);\n\n // Try to get token ID\n if (sdkToken.id) {\n defaultInfo.tokenId = sdkToken.id.toString();\n }\n\n // Extract coinId from SDK token's coins structure (lottery-compatible)\n if (sdkToken.coins && sdkToken.coins.coins) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const rawCoins = sdkToken.coins.coins as any[];\n if (rawCoins.length > 0) {\n const firstCoin = rawCoins[0];\n // Format: [[CoinId, amount]] or [CoinId, amount]\n let coinIdObj: unknown;\n let amount: unknown;\n\n if (Array.isArray(firstCoin) && firstCoin.length === 2) {\n [coinIdObj, amount] = firstCoin;\n }\n\n // Extract hex string from CoinId object\n if (coinIdObj instanceof CoinId) {\n const coinIdHex = coinIdObj.toJSON() as string;\n return {\n coinId: coinIdHex,\n symbol: coinIdHex.slice(0, 8),\n name: `Token ${coinIdHex.slice(0, 8)}`,\n amount: String(amount ?? '0'),\n tokenId: defaultInfo.tokenId,\n };\n } else if (coinIdObj && typeof coinIdObj === 'object' && 'bytes' in coinIdObj) {\n // CoinId stored as object with bytes\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const bytes = (coinIdObj as any).bytes;\n const coinIdHex = Buffer.isBuffer(bytes)\n ? bytes.toString('hex')\n : Array.isArray(bytes)\n ? Buffer.from(bytes).toString('hex')\n : String(bytes);\n return {\n coinId: coinIdHex,\n symbol: coinIdHex.slice(0, 8),\n name: `Token ${coinIdHex.slice(0, 8)}`,\n amount: String(amount ?? '0'),\n tokenId: defaultInfo.tokenId,\n };\n }\n }\n }\n\n // Fallback: Extract from JSON representation\n const tokenJson = sdkToken.toJSON() as unknown as Record<string, unknown>;\n const genesisData = tokenJson.genesis as Record<string, unknown> | undefined;\n if (genesisData?.data) {\n const gData = genesisData.data as Record<string, unknown>;\n if (gData.coinData && typeof gData.coinData === 'object') {\n // coinData might be array: [[coinIdHex, amount]]\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const coinData = gData.coinData as any;\n if (Array.isArray(coinData) && coinData.length > 0) {\n const firstEntry = coinData[0];\n if (Array.isArray(firstEntry) && firstEntry.length === 2) {\n const [coinIdHex, amount] = firstEntry;\n const coinIdStr = typeof coinIdHex === 'string' ? coinIdHex : String(coinIdHex);\n return {\n coinId: coinIdStr,\n symbol: coinIdStr.slice(0, 8),\n name: `Token ${coinIdStr.slice(0, 8)}`,\n amount: String(amount),\n tokenId: defaultInfo.tokenId,\n };\n }\n }\n }\n }\n } catch {\n // SDK parsing failed, try manual extraction\n }\n\n // Manual extraction from TXF format - handle array structure\n if (data.genesis?.data) {\n const genesis = data.genesis.data;\n if (genesis.coinData) {\n // coinData can be: [[coinIdHex, amount]] or {coinIdHex: amount}\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const coinData = genesis.coinData as any;\n if (Array.isArray(coinData) && coinData.length > 0) {\n const firstEntry = coinData[0];\n if (Array.isArray(firstEntry) && firstEntry.length === 2) {\n const [coinIdHex, amount] = firstEntry;\n return {\n coinId: String(coinIdHex),\n symbol: String(coinIdHex).slice(0, 8),\n name: `Token ${String(coinIdHex).slice(0, 8)}`,\n amount: String(amount),\n tokenId: genesis.tokenId,\n };\n }\n } else if (typeof coinData === 'object') {\n const coinEntries = Object.entries(coinData);\n if (coinEntries.length > 0) {\n const [coinId, amount] = coinEntries[0] as [string, unknown];\n return {\n coinId,\n symbol: coinId.slice(0, 8),\n name: `Token ${coinId.slice(0, 8)}`,\n amount: String(amount),\n tokenId: genesis.tokenId,\n };\n }\n }\n }\n if (genesis.tokenId) {\n defaultInfo.tokenId = genesis.tokenId;\n }\n }\n\n // Try to extract from state if available\n if (data.state?.coinData) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const coinData = data.state.coinData as any;\n if (Array.isArray(coinData) && coinData.length > 0) {\n const firstEntry = coinData[0];\n if (Array.isArray(firstEntry) && firstEntry.length === 2) {\n const [coinIdHex, amount] = firstEntry;\n return {\n coinId: String(coinIdHex),\n symbol: String(coinIdHex).slice(0, 8),\n name: `Token ${String(coinIdHex).slice(0, 8)}`,\n amount: String(amount),\n tokenId: defaultInfo.tokenId,\n };\n }\n } else if (typeof coinData === 'object') {\n const coinEntries = Object.entries(coinData);\n if (coinEntries.length > 0) {\n const [coinId, amount] = coinEntries[0] as [string, unknown];\n return {\n coinId,\n symbol: coinId.slice(0, 8),\n name: `Token ${coinId.slice(0, 8)}`,\n amount: String(amount),\n tokenId: defaultInfo.tokenId,\n };\n }\n }\n }\n } catch (error) {\n console.warn('[Payments] Failed to parse token info:', error);\n }\n\n return defaultInfo;\n}\n\n// =============================================================================\n// Repository Utility Functions\n// =============================================================================\n\n/**\n * Extract token ID from sdkData/jsonData\n */\nfunction extractTokenIdFromSdkData(sdkData: string | undefined): string | null {\n if (!sdkData) return null;\n try {\n const txf = JSON.parse(sdkData);\n return txf.genesis?.data?.tokenId || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Extract state hash from sdkData/jsonData\n */\nfunction extractStateHashFromSdkData(sdkData: string | undefined): string {\n if (!sdkData) return '';\n try {\n const txf = JSON.parse(sdkData) as TxfToken;\n return getCurrentStateHash(txf) || '';\n } catch {\n return '';\n }\n}\n\n/**\n * Check if two tokens are the same (by genesis tokenId)\n */\nfunction isSameToken(t1: Token, t2: Token): boolean {\n if (t1.id === t2.id) return true;\n\n const id1 = extractTokenIdFromSdkData(t1.sdkData);\n const id2 = extractTokenIdFromSdkData(t2.sdkData);\n\n return !!(id1 && id2 && id1 === id2);\n}\n\n/**\n * Create tombstone from token\n */\nfunction createTombstoneFromToken(token: Token): TombstoneEntry | null {\n const tokenId = extractTokenIdFromSdkData(token.sdkData);\n if (!tokenId) return null;\n\n const stateHash = extractStateHashFromSdkData(token.sdkData);\n\n return {\n tokenId,\n stateHash,\n timestamp: Date.now(),\n };\n}\n\n/**\n * Check if incoming token is an incremental update\n */\nfunction isIncrementalUpdate(existing: TxfToken, incoming: TxfToken): boolean {\n if (existing.genesis?.data?.tokenId !== incoming.genesis?.data?.tokenId) {\n return false;\n }\n\n const existingTxns = existing.transactions || [];\n const incomingTxns = incoming.transactions || [];\n\n if (incomingTxns.length < existingTxns.length) {\n return false;\n }\n\n for (let i = 0; i < existingTxns.length; i++) {\n const existingTx = existingTxns[i];\n const incomingTx = incomingTxns[i];\n\n if (existingTx.previousStateHash !== incomingTx.previousStateHash ||\n existingTx.newStateHash !== incomingTx.newStateHash) {\n return false;\n }\n }\n\n for (let i = existingTxns.length; i < incomingTxns.length; i++) {\n const newTx = incomingTxns[i] as TxfTransaction;\n if (newTx.inclusionProof === null) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Count committed transactions\n */\nfunction countCommittedTxns(txf: TxfToken): number {\n return (txf.transactions || []).filter(\n (tx: TxfTransaction) => tx.inclusionProof !== null\n ).length;\n}\n\n/**\n * Prune tombstones by age and count\n */\nfunction pruneTombstonesByAge(\n tombstones: TombstoneEntry[],\n maxAge: number = 30 * 24 * 60 * 60 * 1000,\n maxCount: number = 100\n): TombstoneEntry[] {\n const now = Date.now();\n let result = tombstones.filter(t => (now - t.timestamp) < maxAge);\n\n if (result.length > maxCount) {\n result = [...result].sort((a, b) => b.timestamp - a.timestamp);\n result = result.slice(0, maxCount);\n }\n\n return result;\n}\n\n/**\n * Prune Map by count\n */\nfunction pruneMapByCount<T>(items: Map<string, T>, maxCount: number): Map<string, T> {\n if (items.size <= maxCount) {\n return new Map(items);\n }\n\n const entries = [...items.entries()];\n const toKeep = entries.slice(entries.length - maxCount);\n return new Map(toKeep);\n}\n\n/**\n * Find best token version from archives\n */\nfunction findBestTokenVersion(\n tokenId: string,\n archivedTokens: Map<string, TxfToken>,\n forkedTokens: Map<string, TxfToken>\n): TxfToken | null {\n const candidates: TxfToken[] = [];\n\n const archived = archivedTokens.get(tokenId);\n if (archived) candidates.push(archived);\n\n for (const [key, forked] of forkedTokens) {\n if (key.startsWith(tokenId + '_')) {\n candidates.push(forked);\n }\n }\n\n if (candidates.length === 0) return null;\n\n candidates.sort((a, b) => countCommittedTxns(b) - countCommittedTxns(a));\n return candidates[0];\n}\n\n// =============================================================================\n// Configuration\n// =============================================================================\n\nexport interface PaymentsModuleConfig {\n /** Auto-sync after operations */\n autoSync?: boolean;\n /** Auto-validate with aggregator */\n autoValidate?: boolean;\n /** Retry failed transfers */\n retryFailed?: boolean;\n /** Max retry attempts */\n maxRetries?: number;\n /** Enable debug logging */\n debug?: boolean;\n /** L1 (ALPHA blockchain) configuration */\n l1?: L1PaymentsModuleConfig;\n}\n\n// =============================================================================\n// Dependencies Interface\n// =============================================================================\n\nexport interface PaymentsModuleDependencies {\n identity: FullIdentity;\n storage: StorageProvider;\n /** @deprecated Use tokenStorageProviders instead */\n tokenStorage?: TokenStorageProvider<TxfStorageDataBase>;\n /** Multiple token storage providers (e.g., IPFS, MongoDB, file) */\n tokenStorageProviders?: Map<string, TokenStorageProvider<TxfStorageDataBase>>;\n transport: TransportProvider;\n oracle: OracleProvider;\n emitEvent: <T extends SphereEventType>(type: T, data: SphereEventMap[T]) => void;\n /** Chain code for BIP32 HD derivation (for L1 multi-address support) */\n chainCode?: string;\n /** Additional L1 addresses to watch */\n l1Addresses?: string[];\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\nexport class PaymentsModule {\n private readonly moduleConfig: Omit<Required<PaymentsModuleConfig>, 'l1'>;\n private deps: PaymentsModuleDependencies | null = null;\n\n /** L1 (ALPHA blockchain) payments sub-module (null if disabled) */\n readonly l1: L1PaymentsModule | null;\n\n // Token State\n private tokens: Map<string, Token> = new Map();\n private pendingTransfers: Map<string, TransferResult> = new Map();\n\n // Repository State (tombstones, archives, forked, history)\n private tombstones: TombstoneEntry[] = [];\n private archivedTokens: Map<string, TxfToken> = new Map();\n private forkedTokens: Map<string, TxfToken> = new Map();\n private transactionHistory: TransactionHistoryEntry[] = [];\n private nametag: NametagData | null = null;\n\n // Payment Requests State (Incoming)\n private paymentRequests: IncomingPaymentRequest[] = [];\n private paymentRequestHandlers: Set<PaymentRequestHandler> = new Set();\n\n // Payment Requests State (Outgoing)\n private outgoingPaymentRequests: Map<string, OutgoingPaymentRequest> = new Map();\n private paymentRequestResponseHandlers: Set<PaymentRequestResponseHandler> = new Set();\n private pendingResponseResolvers: Map<string, {\n resolve: (response: PaymentRequestResponse) => void;\n reject: (error: Error) => void;\n timeout: ReturnType<typeof setTimeout>;\n }> = new Map();\n\n // Subscriptions\n private unsubscribeTransfers: (() => void) | null = null;\n private unsubscribePaymentRequests: (() => void) | null = null;\n private unsubscribePaymentRequestResponses: (() => void) | null = null;\n\n constructor(config?: PaymentsModuleConfig) {\n this.moduleConfig = {\n autoSync: config?.autoSync ?? true,\n autoValidate: config?.autoValidate ?? true,\n retryFailed: config?.retryFailed ?? true,\n maxRetries: config?.maxRetries ?? 3,\n debug: config?.debug ?? false,\n };\n\n // Initialize L1 sub-module only if electrumUrl is provided\n const l1Enabled = config?.l1?.electrumUrl && config.l1.electrumUrl.length > 0;\n this.l1 = l1Enabled ? new L1PaymentsModule(config?.l1) : null;\n }\n\n /** Get module configuration */\n getConfig(): Omit<Required<PaymentsModuleConfig>, 'l1'> {\n return this.moduleConfig;\n }\n\n private log(...args: unknown[]): void {\n if (this.moduleConfig.debug) {\n console.log('[PaymentsModule]', ...args);\n }\n }\n\n // ===========================================================================\n // Lifecycle\n // ===========================================================================\n\n /**\n * Initialize module with dependencies\n */\n initialize(deps: PaymentsModuleDependencies): void {\n this.deps = deps;\n\n // Initialize L1 sub-module with chain code and addresses (if enabled)\n if (this.l1) {\n this.l1.initialize({\n identity: deps.identity,\n chainCode: deps.chainCode,\n addresses: deps.l1Addresses,\n });\n }\n\n // Subscribe to incoming transfers\n this.unsubscribeTransfers = deps.transport.onTokenTransfer((transfer) => {\n this.handleIncomingTransfer(transfer);\n });\n\n // Subscribe to incoming payment requests (if supported)\n if (deps.transport.onPaymentRequest) {\n this.unsubscribePaymentRequests = deps.transport.onPaymentRequest((request) => {\n this.handleIncomingPaymentRequest(request);\n });\n }\n\n // Subscribe to payment request responses (if supported)\n if (deps.transport.onPaymentRequestResponse) {\n this.unsubscribePaymentRequestResponses = deps.transport.onPaymentRequestResponse((response) => {\n this.handlePaymentRequestResponse(response);\n });\n }\n }\n\n /**\n * Load tokens from storage\n */\n async load(): Promise<void> {\n this.ensureInitialized();\n\n // Load from key-value storage\n const data = await this.deps!.storage.get(STORAGE_KEYS.TOKENS);\n if (data) {\n try {\n const parsed = JSON.parse(data);\n\n // Load tokens\n const tokens = parsed.tokens as Token[] || [];\n this.tokens.clear();\n for (const token of tokens) {\n this.tokens.set(token.id, token);\n }\n\n // Load tombstones\n if (Array.isArray(parsed.tombstones)) {\n this.tombstones = parsed.tombstones.filter(\n (t: unknown) =>\n typeof t === 'object' && t !== null &&\n typeof (t as TombstoneEntry).tokenId === 'string' &&\n typeof (t as TombstoneEntry).stateHash === 'string'\n );\n }\n\n // Load archived tokens\n if (parsed.archivedTokens && typeof parsed.archivedTokens === 'object') {\n this.archivedTokens = new Map(Object.entries(parsed.archivedTokens));\n }\n\n // Load forked tokens\n if (parsed.forkedTokens && typeof parsed.forkedTokens === 'object') {\n this.forkedTokens = new Map(Object.entries(parsed.forkedTokens));\n }\n\n // Load nametag\n if (parsed.nametag) {\n this.nametag = parsed.nametag;\n }\n\n this.log(`Loaded ${this.tokens.size} tokens, ${this.tombstones.length} tombstones, ${this.archivedTokens.size} archived`);\n } catch (err) {\n console.error('[Payments] Failed to parse stored data:', err);\n }\n }\n\n // Load tokens from file storage providers (lottery compatibility)\n await this.loadTokensFromFileStorage();\n\n // Load nametag from file storage (lottery compatibility)\n await this.loadNametagFromFileStorage();\n\n // Load transaction history\n const historyData = await this.deps!.storage.get(STORAGE_KEYS.TRANSACTION_HISTORY);\n if (historyData) {\n try {\n this.transactionHistory = JSON.parse(historyData);\n } catch {\n this.transactionHistory = [];\n }\n }\n\n // Load pending transfers\n const pending = await this.deps!.storage.get(STORAGE_KEYS.PENDING_TRANSFERS);\n if (pending) {\n const transfers = JSON.parse(pending) as TransferResult[];\n for (const transfer of transfers) {\n this.pendingTransfers.set(transfer.id, transfer);\n }\n }\n }\n\n /**\n * Cleanup resources\n */\n destroy(): void {\n this.unsubscribeTransfers?.();\n this.unsubscribeTransfers = null;\n this.unsubscribePaymentRequests?.();\n this.unsubscribePaymentRequests = null;\n this.unsubscribePaymentRequestResponses?.();\n this.unsubscribePaymentRequestResponses = null;\n this.paymentRequestHandlers.clear();\n this.paymentRequestResponseHandlers.clear();\n\n // Clear pending response resolvers\n for (const [, resolver] of this.pendingResponseResolvers) {\n clearTimeout(resolver.timeout);\n resolver.reject(new Error('Module destroyed'));\n }\n this.pendingResponseResolvers.clear();\n\n if (this.l1) {\n this.l1.destroy();\n }\n }\n\n // ===========================================================================\n // Public API - Send\n // ===========================================================================\n\n /**\n * Send tokens to recipient\n * Supports automatic token splitting when exact amount is needed\n */\n async send(request: TransferRequest): Promise<TransferResult> {\n this.ensureInitialized();\n\n // Use mutable result for building the transfer\n const result: { -readonly [K in keyof TransferResult]: TransferResult[K] } = {\n id: crypto.randomUUID(),\n status: 'pending',\n tokens: [],\n };\n\n try {\n // Resolve recipient pubkey for Nostr delivery\n const recipientPubkey = await this.resolveRecipient(request.recipient);\n\n // Resolve recipient address for on-chain transfer\n const recipientAddress = await this.resolveRecipientAddress(request.recipient);\n\n // Create signing service\n const signingService = await this.createSigningService();\n\n // Get state transition client and trust base\n const stClient = this.deps!.oracle.getStateTransitionClient?.() as StateTransitionClient | undefined;\n if (!stClient) {\n throw new Error('State transition client not available. Oracle provider must implement getStateTransitionClient()');\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const trustBase = (this.deps!.oracle as any).getTrustBase?.();\n if (!trustBase) {\n throw new Error('Trust base not available. Oracle provider must implement getTrustBase()');\n }\n\n // Calculate optimal split plan\n const calculator = new TokenSplitCalculator();\n const availableTokens = Array.from(this.tokens.values());\n const splitPlan = await calculator.calculateOptimalSplit(\n availableTokens,\n BigInt(request.amount),\n request.coinId\n );\n\n if (!splitPlan) {\n throw new Error('Insufficient balance');\n }\n\n this.log(`Split plan: requiresSplit=${splitPlan.requiresSplit}, directTokens=${splitPlan.tokensToTransferDirectly.length}`);\n\n // Collect all tokens involved\n const tokensToSend: Token[] = splitPlan.tokensToTransferDirectly.map(t => t.uiToken);\n if (splitPlan.tokenToSplit) {\n tokensToSend.push(splitPlan.tokenToSplit.uiToken);\n }\n result.tokens = tokensToSend;\n\n // Mark as transferring\n for (const token of tokensToSend) {\n token.status = 'transferring';\n this.tokens.set(token.id, token);\n }\n\n // Save to outbox for recovery\n await this.saveToOutbox(result, recipientPubkey);\n\n result.status = 'submitted';\n\n const recipientNametag = request.recipient.startsWith('@') ? request.recipient.slice(1) : undefined;\n\n // Handle split if required\n if (splitPlan.requiresSplit && splitPlan.tokenToSplit) {\n this.log('Executing token split...');\n\n const executor = new TokenSplitExecutor({\n stateTransitionClient: stClient,\n trustBase,\n signingService,\n });\n\n const splitResult = await executor.executeSplit(\n splitPlan.tokenToSplit.sdkToken,\n splitPlan.splitAmount!,\n splitPlan.remainderAmount!,\n splitPlan.coinId,\n recipientAddress\n );\n\n // Save change token for sender\n const changeTokenData = splitResult.tokenForSender.toJSON();\n const changeToken: Token = {\n id: crypto.randomUUID(),\n coinId: request.coinId,\n symbol: this.getCoinSymbol(request.coinId),\n name: this.getCoinName(request.coinId),\n amount: splitPlan.remainderAmount!.toString(),\n status: 'confirmed',\n createdAt: Date.now(),\n updatedAt: Date.now(),\n sdkData: JSON.stringify(changeTokenData),\n };\n await this.addToken(changeToken, true); // Skip history for change\n this.log(`Change token saved: ${changeToken.id}, amount: ${changeToken.amount}`);\n\n // Send recipient token via Nostr (Sphere format)\n await this.deps!.transport.sendTokenTransfer(recipientPubkey, {\n sourceToken: JSON.stringify(splitResult.tokenForRecipient.toJSON()),\n transferTx: JSON.stringify(splitResult.recipientTransferTx.toJSON()),\n memo: request.memo,\n } as unknown as import('../../transport').TokenTransferPayload);\n\n // Remove the original token that was split\n await this.removeToken(splitPlan.tokenToSplit.uiToken.id, recipientNametag);\n\n result.txHash = 'split-' + Date.now().toString(16);\n this.log(`Split transfer completed`);\n }\n\n // Transfer direct tokens (no split needed)\n for (const tokenWithAmount of splitPlan.tokensToTransferDirectly) {\n const token = tokenWithAmount.uiToken;\n\n // Create SDK transfer commitment\n const commitment = await this.createSdkCommitment(token, recipientAddress, signingService);\n\n // Submit commitment via SDK\n const response = await stClient.submitTransferCommitment(commitment);\n if (response.status !== 'SUCCESS' && response.status !== 'REQUEST_ID_EXISTS') {\n throw new Error(`Transfer commitment failed: ${response.status}`);\n }\n\n // Wait for inclusion proof using SDK\n if (!this.deps!.oracle.waitForProofSdk) {\n throw new Error('Oracle provider must implement waitForProofSdk()');\n }\n const inclusionProof = await this.deps!.oracle.waitForProofSdk(commitment);\n\n // Create transfer transaction\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const transferTx = commitment.toTransaction(inclusionProof as any);\n\n // Get request ID as hex string for tracking\n const requestIdBytes = commitment.requestId;\n result.txHash = requestIdBytes instanceof Uint8Array\n ? Array.from(requestIdBytes).map(b => b.toString(16).padStart(2, '0')).join('')\n : String(requestIdBytes);\n\n // Send via transport (Nostr) - use Sphere-compatible format\n await this.deps!.transport.sendTokenTransfer(recipientPubkey, {\n sourceToken: JSON.stringify(tokenWithAmount.sdkToken.toJSON()),\n transferTx: JSON.stringify(transferTx.toJSON()),\n memo: request.memo,\n } as unknown as import('../../transport').TokenTransferPayload);\n\n this.log(`Token ${token.id} transferred, txHash: ${result.txHash}`);\n\n // Remove sent token (creates tombstone)\n await this.removeToken(token.id, recipientNametag);\n }\n\n result.status = 'delivered';\n\n // Save state\n await this.save();\n await this.removeFromOutbox(result.id);\n\n result.status = 'completed';\n\n // Add to transaction history\n await this.addToHistory({\n type: 'SENT',\n amount: request.amount,\n coinId: request.coinId,\n symbol: this.getCoinSymbol(request.coinId),\n timestamp: Date.now(),\n recipientNametag,\n });\n\n this.deps!.emitEvent('transfer:confirmed', result);\n return result;\n } catch (error) {\n result.status = 'failed';\n result.error = error instanceof Error ? error.message : String(error);\n\n // Restore tokens\n for (const token of result.tokens) {\n token.status = 'confirmed';\n this.tokens.set(token.id, token);\n }\n\n this.deps!.emitEvent('transfer:failed', result);\n throw error;\n }\n }\n\n /**\n * Get coin symbol from coinId\n */\n private getCoinSymbol(coinId: string): string {\n // Common coin mappings\n const symbols: Record<string, string> = {\n 'UCT': 'UCT',\n // Add more as needed\n };\n return symbols[coinId] || coinId.slice(0, 6).toUpperCase();\n }\n\n /**\n * Get coin name from coinId\n */\n private getCoinName(coinId: string): string {\n const names: Record<string, string> = {\n 'UCT': 'Unicity Token',\n };\n return names[coinId] || coinId;\n }\n\n // ===========================================================================\n // Public API - Payment Requests\n // ===========================================================================\n\n /**\n * Send a payment request to someone\n * @param recipientPubkeyOrNametag - Recipient's pubkey or @nametag\n * @param request - Payment request details\n * @returns Result with event ID\n */\n async sendPaymentRequest(\n recipientPubkeyOrNametag: string,\n request: Omit<PaymentRequest, 'id' | 'createdAt'>\n ): Promise<PaymentRequestResult> {\n this.ensureInitialized();\n\n if (!this.deps!.transport.sendPaymentRequest) {\n return {\n success: false,\n error: 'Transport provider does not support payment requests',\n };\n }\n\n try {\n // Resolve recipient pubkey\n const recipientPubkey = await this.resolveRecipient(recipientPubkeyOrNametag);\n\n // Build payload\n const payload: PaymentRequestPayload = {\n amount: request.amount,\n coinId: request.coinId,\n message: request.message,\n recipientNametag: request.recipientNametag,\n metadata: request.metadata,\n };\n\n // Send via transport\n const eventId = await this.deps!.transport.sendPaymentRequest(recipientPubkey, payload);\n const requestId = crypto.randomUUID();\n\n // Track outgoing request\n const outgoingRequest: OutgoingPaymentRequest = {\n id: requestId,\n eventId,\n recipientPubkey,\n recipientNametag: recipientPubkeyOrNametag.startsWith('@')\n ? recipientPubkeyOrNametag.slice(1)\n : undefined,\n amount: request.amount,\n coinId: request.coinId,\n message: request.message,\n createdAt: Date.now(),\n status: 'pending',\n };\n this.outgoingPaymentRequests.set(requestId, outgoingRequest);\n\n this.log(`Payment request sent: ${eventId}`);\n\n return {\n success: true,\n requestId,\n eventId,\n };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.log(`Failed to send payment request: ${errorMsg}`);\n return {\n success: false,\n error: errorMsg,\n };\n }\n }\n\n /**\n * Subscribe to incoming payment requests\n * @param handler - Handler function for incoming requests\n * @returns Unsubscribe function\n */\n onPaymentRequest(handler: PaymentRequestHandler): () => void {\n this.paymentRequestHandlers.add(handler);\n return () => this.paymentRequestHandlers.delete(handler);\n }\n\n /**\n * Get all payment requests\n * @param filter - Optional status filter\n */\n getPaymentRequests(filter?: { status?: PaymentRequestStatus }): IncomingPaymentRequest[] {\n if (filter?.status) {\n return this.paymentRequests.filter((r) => r.status === filter.status);\n }\n return [...this.paymentRequests];\n }\n\n /**\n * Get pending payment requests count\n */\n getPendingPaymentRequestsCount(): number {\n return this.paymentRequests.filter((r) => r.status === 'pending').length;\n }\n\n /**\n * Accept a payment request (marks it as accepted, user should then call send())\n */\n async acceptPaymentRequest(requestId: string): Promise<void> {\n this.updatePaymentRequestStatus(requestId, 'accepted');\n await this.sendPaymentRequestResponse(requestId, 'accepted');\n }\n\n /**\n * Reject a payment request\n */\n async rejectPaymentRequest(requestId: string): Promise<void> {\n this.updatePaymentRequestStatus(requestId, 'rejected');\n await this.sendPaymentRequestResponse(requestId, 'rejected');\n }\n\n /**\n * Mark a payment request as paid (after successful transfer)\n */\n markPaymentRequestPaid(requestId: string): void {\n this.updatePaymentRequestStatus(requestId, 'paid');\n }\n\n /**\n * Clear processed (non-pending) payment requests\n */\n clearProcessedPaymentRequests(): void {\n this.paymentRequests = this.paymentRequests.filter((r) => r.status === 'pending');\n }\n\n /**\n * Remove a specific payment request\n */\n removePaymentRequest(requestId: string): void {\n this.paymentRequests = this.paymentRequests.filter((r) => r.id !== requestId);\n }\n\n /**\n * Pay a payment request directly\n * Convenience method that accepts, sends, and marks as paid\n */\n async payPaymentRequest(requestId: string, memo?: string): Promise<TransferResult> {\n const request = this.paymentRequests.find((r) => r.id === requestId);\n if (!request) {\n throw new Error(`Payment request not found: ${requestId}`);\n }\n\n if (request.status !== 'pending' && request.status !== 'accepted') {\n throw new Error(`Payment request is not pending or accepted: ${request.status}`);\n }\n\n // Mark as accepted (don't send response yet, wait for payment)\n this.updatePaymentRequestStatus(requestId, 'accepted');\n\n try {\n // Send the payment\n const result = await this.send({\n coinId: request.coinId,\n amount: request.amount,\n recipient: request.senderPubkey,\n memo: memo || request.message,\n });\n\n // Mark as paid and send response with transfer ID\n this.updatePaymentRequestStatus(requestId, 'paid');\n await this.sendPaymentRequestResponse(requestId, 'paid', result.id);\n\n return result;\n } catch (error) {\n // Revert to pending on failure\n this.updatePaymentRequestStatus(requestId, 'pending');\n throw error;\n }\n }\n\n private updatePaymentRequestStatus(requestId: string, status: PaymentRequestStatus): void {\n const request = this.paymentRequests.find((r) => r.id === requestId);\n if (request) {\n request.status = status;\n\n // Emit event\n const eventType = `payment_request:${status}` as const;\n if (eventType === 'payment_request:accepted' ||\n eventType === 'payment_request:rejected' ||\n eventType === 'payment_request:paid') {\n this.deps?.emitEvent(eventType, request);\n }\n }\n }\n\n private handleIncomingPaymentRequest(transportRequest: TransportPaymentRequest): void {\n // Check for duplicates\n if (this.paymentRequests.find((r) => r.id === transportRequest.id)) {\n return;\n }\n\n // Convert transport request to IncomingPaymentRequest\n const request: IncomingPaymentRequest = {\n id: transportRequest.id,\n senderPubkey: transportRequest.senderPubkey,\n amount: transportRequest.request.amount,\n coinId: transportRequest.request.coinId,\n symbol: transportRequest.request.coinId, // Use coinId as symbol for now\n message: transportRequest.request.message,\n recipientNametag: transportRequest.request.recipientNametag,\n requestId: transportRequest.request.requestId,\n timestamp: transportRequest.timestamp,\n status: 'pending',\n metadata: transportRequest.request.metadata,\n };\n\n // Add to list (newest first)\n this.paymentRequests.unshift(request);\n\n // Emit event\n this.deps?.emitEvent('payment_request:incoming', request);\n\n // Notify handlers\n for (const handler of this.paymentRequestHandlers) {\n try {\n handler(request);\n } catch (error) {\n this.log('Payment request handler error:', error);\n }\n }\n\n this.log(`Incoming payment request: ${request.id} for ${request.amount} ${request.symbol}`);\n }\n\n // ===========================================================================\n // Public API - Outgoing Payment Requests\n // ===========================================================================\n\n /**\n * Get outgoing payment requests\n * @param filter - Optional status filter\n */\n getOutgoingPaymentRequests(filter?: { status?: PaymentRequestStatus }): OutgoingPaymentRequest[] {\n const requests = Array.from(this.outgoingPaymentRequests.values());\n if (filter?.status) {\n return requests.filter((r) => r.status === filter.status);\n }\n return requests;\n }\n\n /**\n * Subscribe to payment request responses (for outgoing requests)\n * @param handler - Handler function for incoming responses\n * @returns Unsubscribe function\n */\n onPaymentRequestResponse(handler: PaymentRequestResponseHandler): () => void {\n this.paymentRequestResponseHandlers.add(handler);\n return () => this.paymentRequestResponseHandlers.delete(handler);\n }\n\n /**\n * Wait for a response to a payment request\n * @param requestId - The outgoing request ID to wait for\n * @param timeoutMs - Timeout in milliseconds (default: 60000)\n * @returns Promise that resolves with the response or rejects on timeout\n */\n waitForPaymentResponse(requestId: string, timeoutMs: number = 60000): Promise<PaymentRequestResponse> {\n const outgoing = this.outgoingPaymentRequests.get(requestId);\n if (!outgoing) {\n return Promise.reject(new Error(`Outgoing payment request not found: ${requestId}`));\n }\n\n // If already has a response, return it\n if (outgoing.response) {\n return Promise.resolve(outgoing.response);\n }\n\n // Create a promise that resolves when response arrives or times out\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.pendingResponseResolvers.delete(requestId);\n // Update status to expired\n const request = this.outgoingPaymentRequests.get(requestId);\n if (request && request.status === 'pending') {\n request.status = 'expired';\n }\n reject(new Error(`Payment request response timeout: ${requestId}`));\n }, timeoutMs);\n\n this.pendingResponseResolvers.set(requestId, { resolve, reject, timeout });\n });\n }\n\n /**\n * Cancel waiting for a payment response\n */\n cancelWaitForPaymentResponse(requestId: string): void {\n const resolver = this.pendingResponseResolvers.get(requestId);\n if (resolver) {\n clearTimeout(resolver.timeout);\n resolver.reject(new Error('Cancelled'));\n this.pendingResponseResolvers.delete(requestId);\n }\n }\n\n /**\n * Remove an outgoing payment request\n */\n removeOutgoingPaymentRequest(requestId: string): void {\n this.outgoingPaymentRequests.delete(requestId);\n this.cancelWaitForPaymentResponse(requestId);\n }\n\n /**\n * Clear completed/expired outgoing payment requests\n */\n clearCompletedOutgoingPaymentRequests(): void {\n for (const [id, request] of this.outgoingPaymentRequests) {\n if (request.status === 'paid' || request.status === 'rejected' || request.status === 'expired') {\n this.outgoingPaymentRequests.delete(id);\n }\n }\n }\n\n private handlePaymentRequestResponse(transportResponse: TransportPaymentRequestResponse): void {\n // Find the outgoing request by matching requestId\n let outgoingRequest: OutgoingPaymentRequest | undefined;\n let outgoingRequestId: string | undefined;\n\n for (const [id, request] of this.outgoingPaymentRequests) {\n // Match by eventId or requestId from the response\n if (request.eventId === transportResponse.response.requestId ||\n request.id === transportResponse.response.requestId) {\n outgoingRequest = request;\n outgoingRequestId = id;\n break;\n }\n }\n\n // Convert transport response to PaymentRequestResponse\n const response: PaymentRequestResponse = {\n id: transportResponse.id,\n responderPubkey: transportResponse.responderPubkey,\n requestId: transportResponse.response.requestId,\n responseType: transportResponse.response.responseType,\n message: transportResponse.response.message,\n transferId: transportResponse.response.transferId,\n timestamp: transportResponse.timestamp,\n };\n\n // Update outgoing request if found\n if (outgoingRequest && outgoingRequestId) {\n outgoingRequest.status = response.responseType === 'paid' ? 'paid' :\n response.responseType === 'accepted' ? 'accepted' :\n 'rejected';\n outgoingRequest.response = response;\n\n // Resolve pending promise if any\n const resolver = this.pendingResponseResolvers.get(outgoingRequestId);\n if (resolver) {\n clearTimeout(resolver.timeout);\n resolver.resolve(response);\n this.pendingResponseResolvers.delete(outgoingRequestId);\n }\n }\n\n // Emit event\n this.deps?.emitEvent('payment_request:response', response);\n\n // Notify handlers\n for (const handler of this.paymentRequestResponseHandlers) {\n try {\n handler(response);\n } catch (error) {\n this.log('Payment request response handler error:', error);\n }\n }\n\n this.log(`Received payment request response: ${response.id} type: ${response.responseType}`);\n }\n\n /**\n * Send a response to a payment request (used internally by accept/reject/pay methods)\n */\n private async sendPaymentRequestResponse(\n requestId: string,\n responseType: 'accepted' | 'rejected' | 'paid',\n transferId?: string\n ): Promise<void> {\n const request = this.paymentRequests.find((r) => r.id === requestId);\n if (!request) return;\n\n if (!this.deps?.transport.sendPaymentRequestResponse) {\n this.log('Transport does not support sendPaymentRequestResponse');\n return;\n }\n\n try {\n const payload: PaymentRequestResponsePayload = {\n requestId: request.requestId, // Original request ID from sender\n responseType,\n transferId,\n };\n\n await this.deps.transport.sendPaymentRequestResponse(request.senderPubkey, payload);\n this.log(`Sent payment request response: ${responseType} for ${requestId}`);\n } catch (error) {\n this.log('Failed to send payment request response:', error);\n }\n }\n\n // ===========================================================================\n // Public API - Balance & Tokens\n // ===========================================================================\n\n /**\n * Get balance for coin type\n */\n getBalance(coinId?: string): TokenBalance[] {\n const balances = new Map<string, TokenBalance>();\n\n for (const token of this.tokens.values()) {\n if (token.status !== 'confirmed') continue;\n if (coinId && token.coinId !== coinId) continue;\n\n const key = token.coinId;\n const existing = balances.get(key);\n\n if (existing) {\n (existing as { totalAmount: string }).totalAmount = (\n BigInt(existing.totalAmount) + BigInt(token.amount)\n ).toString();\n (existing as { tokenCount: number }).tokenCount++;\n } else {\n balances.set(key, {\n coinId: token.coinId,\n symbol: token.symbol,\n name: token.name,\n totalAmount: token.amount,\n tokenCount: 1,\n decimals: 8,\n });\n }\n }\n\n return Array.from(balances.values());\n }\n\n /**\n * Get all tokens\n */\n getTokens(filter?: { coinId?: string; status?: TokenStatus }): Token[] {\n let tokens = Array.from(this.tokens.values());\n\n if (filter?.coinId) {\n tokens = tokens.filter((t) => t.coinId === filter.coinId);\n }\n if (filter?.status) {\n tokens = tokens.filter((t) => t.status === filter.status);\n }\n\n return tokens;\n }\n\n /**\n * Get single token\n */\n getToken(id: string): Token | undefined {\n return this.tokens.get(id);\n }\n\n // ===========================================================================\n // Public API - Token Operations\n // ===========================================================================\n\n /**\n * Add a token\n * @returns false if duplicate\n */\n async addToken(token: Token, skipHistory: boolean = false): Promise<boolean> {\n this.ensureInitialized();\n\n // Check for duplicates\n for (const existing of this.tokens.values()) {\n if (isSameToken(existing, token)) {\n this.log(`Duplicate token detected: ${token.id}`);\n return false;\n }\n }\n\n this.tokens.set(token.id, token);\n\n // Archive the token\n await this.archiveToken(token);\n\n // Add to transaction history\n if (!skipHistory && token.coinId && token.amount) {\n await this.addToHistory({\n type: 'RECEIVED',\n amount: token.amount,\n coinId: token.coinId,\n symbol: token.symbol || 'UNK',\n timestamp: token.createdAt || Date.now(),\n });\n }\n\n await this.save();\n\n // Save as individual token file (like lottery pattern)\n await this.saveTokenToFileStorage(token);\n\n this.log(`Added token ${token.id}, total: ${this.tokens.size}`);\n return true;\n }\n\n /**\n * Save token as individual file to token storage providers\n * Similar to lottery's saveReceivedToken() pattern\n */\n private async saveTokenToFileStorage(token: Token): Promise<void> {\n const providers = this.getTokenStorageProviders();\n if (providers.size === 0) return;\n\n // Extract SDK token ID for filename\n const sdkTokenId = extractTokenIdFromSdkData(token.sdkData);\n const tokenIdPrefix = sdkTokenId ? sdkTokenId.slice(0, 16) : token.id.slice(0, 16);\n const filename = `token-${tokenIdPrefix}-${Date.now()}`;\n\n // Token data to save (similar to lottery format)\n const tokenData = {\n token: token.sdkData ? JSON.parse(token.sdkData) : null,\n receivedAt: Date.now(),\n meta: {\n id: token.id,\n coinId: token.coinId,\n symbol: token.symbol,\n amount: token.amount,\n status: token.status,\n },\n };\n\n // Save to all token storage providers\n for (const [providerId, provider] of providers) {\n try {\n if (provider.saveToken) {\n await provider.saveToken(filename, tokenData);\n this.log(`Saved token file ${filename} to ${providerId}`);\n }\n } catch (error) {\n console.warn(`[Payments] Failed to save token to ${providerId}:`, error);\n }\n }\n }\n\n /**\n * Load tokens from file storage providers (lottery compatibility)\n * This loads tokens from file-based storage that may have been saved\n * by other applications using the same storage directory.\n */\n private async loadTokensFromFileStorage(): Promise<void> {\n const providers = this.getTokenStorageProviders();\n if (providers.size === 0) return;\n\n for (const [providerId, provider] of providers) {\n if (!provider.listTokenIds || !provider.getToken) continue;\n\n try {\n const tokenIds = await provider.listTokenIds();\n this.log(`Found ${tokenIds.length} token files in ${providerId}`);\n\n for (const tokenId of tokenIds) {\n try {\n const fileData = await provider.getToken(tokenId);\n if (!fileData || typeof fileData !== 'object') continue;\n\n // Handle lottery format: { token, receivedAt } or { token, receivedAt, meta }\n const data = fileData as Record<string, unknown>;\n const tokenJson = data.token;\n if (!tokenJson) continue;\n\n // Check if already loaded from key-value storage\n let sdkTokenId: string | undefined;\n if (typeof tokenJson === 'object' && tokenJson !== null) {\n const tokenObj = tokenJson as Record<string, unknown>;\n const genesis = tokenObj.genesis as Record<string, unknown> | undefined;\n const genesisData = genesis?.data as Record<string, unknown> | undefined;\n sdkTokenId = genesisData?.tokenId as string | undefined;\n }\n\n if (sdkTokenId) {\n // Check if this token already exists\n let exists = false;\n for (const existing of this.tokens.values()) {\n const existingId = extractTokenIdFromSdkData(existing.sdkData);\n if (existingId === sdkTokenId) {\n exists = true;\n break;\n }\n }\n if (exists) continue;\n }\n\n // Parse token info\n const tokenInfo = await parseTokenInfo(tokenJson);\n\n // Create token entry\n const token: Token = {\n id: tokenInfo.tokenId ?? tokenId,\n coinId: tokenInfo.coinId,\n symbol: tokenInfo.symbol,\n name: tokenInfo.name,\n amount: tokenInfo.amount,\n status: 'confirmed',\n createdAt: (data.receivedAt as number) || Date.now(),\n updatedAt: Date.now(),\n sdkData: typeof tokenJson === 'string'\n ? tokenJson\n : JSON.stringify(tokenJson),\n };\n\n // Add to in-memory storage (skip file save since it's already in file)\n this.tokens.set(token.id, token);\n this.log(`Loaded token from file: ${tokenId}`);\n } catch (tokenError) {\n console.warn(`[Payments] Failed to load token ${tokenId}:`, tokenError);\n }\n }\n } catch (error) {\n console.warn(`[Payments] Failed to load tokens from ${providerId}:`, error);\n }\n }\n\n // Save to key-value storage to sync\n if (this.tokens.size > 0) {\n await this.save();\n }\n }\n\n /**\n * Update an existing token\n */\n async updateToken(token: Token): Promise<void> {\n this.ensureInitialized();\n\n const incomingTokenId = extractTokenIdFromSdkData(token.sdkData);\n let found = false;\n\n // Find by genesis tokenId first\n for (const [id, existing] of this.tokens) {\n const existingTokenId = extractTokenIdFromSdkData(existing.sdkData);\n if ((existingTokenId && incomingTokenId && existingTokenId === incomingTokenId) ||\n existing.id === token.id) {\n this.tokens.delete(id);\n this.tokens.set(token.id, token);\n found = true;\n break;\n }\n }\n\n if (!found) {\n await this.addToken(token, true);\n return;\n }\n\n // Archive the updated token\n await this.archiveToken(token);\n\n await this.save();\n this.log(`Updated token ${token.id}`);\n }\n\n /**\n * Remove a token by ID\n */\n async removeToken(tokenId: string, recipientNametag?: string, skipHistory: boolean = false): Promise<void> {\n this.ensureInitialized();\n\n const token = this.tokens.get(tokenId);\n if (!token) return;\n\n // Archive before removing\n await this.archiveToken(token);\n\n // Create tombstone\n const tombstone = createTombstoneFromToken(token);\n if (tombstone) {\n const alreadyTombstoned = this.tombstones.some(\n t => t.tokenId === tombstone.tokenId && t.stateHash === tombstone.stateHash\n );\n if (!alreadyTombstoned) {\n this.tombstones.push(tombstone);\n this.log(`Created tombstone for ${tombstone.tokenId.slice(0, 8)}...`);\n }\n }\n\n // Remove from active tokens\n this.tokens.delete(tokenId);\n\n // Add to transaction history\n if (!skipHistory && token.coinId && token.amount) {\n await this.addToHistory({\n type: 'SENT',\n amount: token.amount,\n coinId: token.coinId,\n symbol: token.symbol || 'UNK',\n timestamp: Date.now(),\n recipientNametag,\n });\n }\n\n await this.save();\n }\n\n // ===========================================================================\n // Public API - Tombstones\n // ===========================================================================\n\n /**\n * Get all tombstones\n */\n getTombstones(): TombstoneEntry[] {\n return [...this.tombstones];\n }\n\n /**\n * Check if token state is tombstoned\n */\n isStateTombstoned(tokenId: string, stateHash: string): boolean {\n return this.tombstones.some(\n t => t.tokenId === tokenId && t.stateHash === stateHash\n );\n }\n\n /**\n * Merge remote tombstones\n * @returns number of local tokens removed\n */\n async mergeTombstones(remoteTombstones: TombstoneEntry[]): Promise<number> {\n this.ensureInitialized();\n\n let removedCount = 0;\n const tombstoneKeys = new Set(\n remoteTombstones.map(t => `${t.tokenId}:${t.stateHash}`)\n );\n\n // Find tokens to remove\n const tokensToRemove: Token[] = [];\n for (const token of this.tokens.values()) {\n const sdkTokenId = extractTokenIdFromSdkData(token.sdkData);\n const currentStateHash = extractStateHashFromSdkData(token.sdkData);\n\n const key = `${sdkTokenId}:${currentStateHash}`;\n if (tombstoneKeys.has(key)) {\n tokensToRemove.push(token);\n }\n }\n\n for (const token of tokensToRemove) {\n this.tokens.delete(token.id);\n this.log(`Removed tombstoned token ${token.id.slice(0, 8)}...`);\n removedCount++;\n }\n\n // Merge tombstones (union)\n for (const remoteTombstone of remoteTombstones) {\n const alreadyExists = this.tombstones.some(\n t => t.tokenId === remoteTombstone.tokenId && t.stateHash === remoteTombstone.stateHash\n );\n if (!alreadyExists) {\n this.tombstones.push(remoteTombstone);\n }\n }\n\n if (removedCount > 0) {\n await this.save();\n }\n\n return removedCount;\n }\n\n /**\n * Prune old tombstones\n */\n async pruneTombstones(maxAge?: number): Promise<void> {\n const originalCount = this.tombstones.length;\n this.tombstones = pruneTombstonesByAge(this.tombstones, maxAge);\n\n if (this.tombstones.length < originalCount) {\n await this.save();\n this.log(`Pruned tombstones from ${originalCount} to ${this.tombstones.length}`);\n }\n }\n\n // ===========================================================================\n // Public API - Archives\n // ===========================================================================\n\n /**\n * Get archived tokens\n */\n getArchivedTokens(): Map<string, TxfToken> {\n return new Map(this.archivedTokens);\n }\n\n /**\n * Get best archived version of a token\n */\n getBestArchivedVersion(tokenId: string): TxfToken | null {\n return findBestTokenVersion(tokenId, this.archivedTokens, this.forkedTokens);\n }\n\n /**\n * Merge remote archived tokens\n * @returns number of tokens updated/added\n */\n async mergeArchivedTokens(remoteArchived: Map<string, TxfToken>): Promise<number> {\n let mergedCount = 0;\n\n for (const [tokenId, remoteTxf] of remoteArchived) {\n const existingArchive = this.archivedTokens.get(tokenId);\n\n if (!existingArchive) {\n this.archivedTokens.set(tokenId, remoteTxf);\n mergedCount++;\n } else if (isIncrementalUpdate(existingArchive, remoteTxf)) {\n this.archivedTokens.set(tokenId, remoteTxf);\n mergedCount++;\n } else if (!isIncrementalUpdate(remoteTxf, existingArchive)) {\n // It's a fork\n const stateHash = getCurrentStateHash(remoteTxf) || '';\n await this.storeForkedToken(tokenId, stateHash, remoteTxf);\n }\n }\n\n if (mergedCount > 0) {\n await this.save();\n }\n\n return mergedCount;\n }\n\n /**\n * Prune archived tokens\n */\n async pruneArchivedTokens(maxCount: number = 100): Promise<void> {\n if (this.archivedTokens.size <= maxCount) return;\n\n const originalCount = this.archivedTokens.size;\n this.archivedTokens = pruneMapByCount(this.archivedTokens, maxCount);\n\n await this.save();\n this.log(`Pruned archived tokens from ${originalCount} to ${this.archivedTokens.size}`);\n }\n\n // ===========================================================================\n // Public API - Forked Tokens\n // ===========================================================================\n\n /**\n * Get forked tokens\n */\n getForkedTokens(): Map<string, TxfToken> {\n return new Map(this.forkedTokens);\n }\n\n /**\n * Store a forked token\n */\n async storeForkedToken(tokenId: string, stateHash: string, txfToken: TxfToken): Promise<void> {\n const key = `${tokenId}_${stateHash}`;\n if (this.forkedTokens.has(key)) return;\n\n this.forkedTokens.set(key, txfToken);\n this.log(`Stored forked token ${tokenId.slice(0, 8)}... state ${stateHash.slice(0, 12)}...`);\n await this.save();\n }\n\n /**\n * Merge remote forked tokens\n * @returns number of tokens added\n */\n async mergeForkedTokens(remoteForked: Map<string, TxfToken>): Promise<number> {\n let addedCount = 0;\n\n for (const [key, remoteTxf] of remoteForked) {\n if (!this.forkedTokens.has(key)) {\n this.forkedTokens.set(key, remoteTxf);\n addedCount++;\n }\n }\n\n if (addedCount > 0) {\n await this.save();\n }\n\n return addedCount;\n }\n\n /**\n * Prune forked tokens\n */\n async pruneForkedTokens(maxCount: number = 50): Promise<void> {\n if (this.forkedTokens.size <= maxCount) return;\n\n const originalCount = this.forkedTokens.size;\n this.forkedTokens = pruneMapByCount(this.forkedTokens, maxCount);\n\n await this.save();\n this.log(`Pruned forked tokens from ${originalCount} to ${this.forkedTokens.size}`);\n }\n\n // ===========================================================================\n // Public API - Transaction History\n // ===========================================================================\n\n /**\n * Get transaction history\n */\n getHistory(): TransactionHistoryEntry[] {\n return [...this.transactionHistory].sort((a, b) => b.timestamp - a.timestamp);\n }\n\n /**\n * Add to transaction history\n */\n async addToHistory(entry: Omit<TransactionHistoryEntry, 'id'>): Promise<void> {\n this.ensureInitialized();\n\n const historyEntry: TransactionHistoryEntry = {\n id: crypto.randomUUID(),\n ...entry,\n };\n this.transactionHistory.push(historyEntry);\n\n await this.deps!.storage.set(\n STORAGE_KEYS.TRANSACTION_HISTORY,\n JSON.stringify(this.transactionHistory)\n );\n }\n\n // ===========================================================================\n // Public API - Nametag\n // ===========================================================================\n\n /**\n * Set nametag for current identity\n */\n async setNametag(nametag: NametagData): Promise<void> {\n this.ensureInitialized();\n this.nametag = nametag;\n await this.save();\n // Save to file storage for lottery compatibility\n await this.saveNametagToFileStorage(nametag);\n this.log(`Nametag set: ${nametag.name}`);\n }\n\n /**\n * Get nametag\n */\n getNametag(): NametagData | null {\n return this.nametag;\n }\n\n /**\n * Check if has nametag\n */\n hasNametag(): boolean {\n return this.nametag !== null;\n }\n\n /**\n * Clear nametag\n */\n async clearNametag(): Promise<void> {\n this.ensureInitialized();\n this.nametag = null;\n await this.save();\n }\n\n /**\n * Save nametag to file storage for lottery compatibility\n * Creates file: nametag-{name}.json\n */\n private async saveNametagToFileStorage(nametag: NametagData): Promise<void> {\n const providers = this.getTokenStorageProviders();\n if (providers.size === 0) return;\n\n const filename = `nametag-${nametag.name}`;\n\n // Lottery-compatible format\n const fileData = {\n nametag: nametag.name,\n token: nametag.token,\n timestamp: nametag.timestamp || Date.now(),\n };\n\n for (const [providerId, provider] of providers) {\n try {\n if (provider.saveToken) {\n await provider.saveToken(filename, fileData);\n this.log(`Saved nametag file ${filename} to ${providerId}`);\n }\n } catch (error) {\n console.warn(`[Payments] Failed to save nametag to ${providerId}:`, error);\n }\n }\n }\n\n /**\n * Load nametag from file storage (lottery compatibility)\n * Looks for file: nametag-{name}.json\n */\n private async loadNametagFromFileStorage(): Promise<void> {\n if (this.nametag) return; // Already loaded from key-value storage\n\n const providers = this.getTokenStorageProviders();\n if (providers.size === 0) return;\n\n for (const [providerId, provider] of providers) {\n if (!provider.listTokenIds || !provider.getToken) continue;\n\n try {\n const tokenIds = await provider.listTokenIds();\n const nametagFiles = tokenIds.filter(id => id.startsWith('nametag-'));\n\n for (const nametagFile of nametagFiles) {\n try {\n const fileData = await provider.getToken(nametagFile);\n if (!fileData || typeof fileData !== 'object') continue;\n\n const data = fileData as Record<string, unknown>;\n if (!data.token || !data.nametag) continue;\n\n // Convert to NametagData format\n this.nametag = {\n name: data.nametag as string,\n token: data.token as object,\n timestamp: (data.timestamp as number) || Date.now(),\n format: 'lottery',\n version: '1.0',\n };\n\n this.log(`Loaded nametag from file: ${nametagFile}`);\n return; // Found one, stop searching\n } catch (fileError) {\n console.warn(`[Payments] Failed to load nametag file ${nametagFile}:`, fileError);\n }\n }\n } catch (error) {\n console.warn(`[Payments] Failed to search nametag files in ${providerId}:`, error);\n }\n }\n }\n\n /**\n * Mint a nametag token on-chain (like Sphere wallet and lottery)\n * This creates the nametag token required for receiving tokens via PROXY addresses\n *\n * @param nametag - The nametag to mint (e.g., \"alice\" or \"@alice\")\n * @returns MintNametagResult with success status and token if successful\n */\n async mintNametag(nametag: string): Promise<MintNametagResult> {\n this.ensureInitialized();\n\n // Get state transition client and trust base\n const stClient = this.deps!.oracle.getStateTransitionClient?.();\n if (!stClient) {\n return {\n success: false,\n error: 'State transition client not available. Oracle provider must implement getStateTransitionClient()',\n };\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const trustBase = (this.deps!.oracle as any).getTrustBase?.();\n if (!trustBase) {\n return {\n success: false,\n error: 'Trust base not available. Oracle provider must implement getTrustBase()',\n };\n }\n\n try {\n // Create signing service\n const signingService = await this.createSigningService();\n\n // Create owner address using UnmaskedPredicateReference (same pattern as TokenSplitExecutor)\n const { UnmaskedPredicateReference } = await import('@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicateReference');\n const { TokenType } = await import('@unicitylabs/state-transition-sdk/lib/token/TokenType');\n\n // Use a dummy token type for address creation (like Sphere wallet does)\n const UNICITY_TOKEN_TYPE_HEX = 'f8aa13834268d29355ff12183066f0cb902003629bbc5eb9ef0efbe397867509';\n const tokenType = new TokenType(Buffer.from(UNICITY_TOKEN_TYPE_HEX, 'hex'));\n\n const addressRef = await UnmaskedPredicateReference.create(\n tokenType,\n signingService.algorithm,\n signingService.publicKey,\n HashAlgorithm.SHA256\n );\n const ownerAddress = await addressRef.toAddress();\n\n // Create NametagMinter\n const minter = new NametagMinter({\n stateTransitionClient: stClient,\n trustBase,\n signingService,\n debug: this.moduleConfig.debug,\n });\n\n // Mint the nametag\n const result = await minter.mintNametag(nametag, ownerAddress);\n\n if (result.success && result.nametagData) {\n // Save the nametag data\n await this.setNametag(result.nametagData);\n this.log(`Nametag minted and saved: ${result.nametagData.name}`);\n\n // Emit event (use existing nametag:registered event type)\n this.deps!.emitEvent('nametag:registered', {\n nametag: result.nametagData.name,\n addressIndex: 0, // Primary address\n });\n }\n\n return result;\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.log('mintNametag failed:', errorMsg);\n return {\n success: false,\n error: errorMsg,\n };\n }\n }\n\n /**\n * Check if a nametag is available for minting\n * @param nametag - The nametag to check (e.g., \"alice\" or \"@alice\")\n */\n async isNametagAvailable(nametag: string): Promise<boolean> {\n this.ensureInitialized();\n\n const stClient = this.deps!.oracle.getStateTransitionClient?.();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const trustBase = (this.deps!.oracle as any).getTrustBase?.();\n\n if (!stClient || !trustBase) {\n return false;\n }\n\n try {\n const signingService = await this.createSigningService();\n const minter = new NametagMinter({\n stateTransitionClient: stClient,\n trustBase,\n signingService,\n });\n\n return await minter.isNametagAvailable(nametag);\n } catch {\n return false;\n }\n }\n\n // ===========================================================================\n // Public API - Sync & Validate\n // ===========================================================================\n\n /**\n * Sync with all token storage providers (IPFS, MongoDB, etc.)\n * Syncs with each provider and merges results\n */\n async sync(): Promise<{ added: number; removed: number }> {\n this.ensureInitialized();\n\n this.deps!.emitEvent('sync:started', { source: 'payments' });\n\n try {\n // Get all token storage providers\n const providers = this.getTokenStorageProviders();\n\n if (providers.size === 0) {\n // No providers - just save locally\n await this.save();\n this.deps!.emitEvent('sync:completed', {\n source: 'payments',\n count: this.tokens.size,\n });\n return { added: 0, removed: 0 };\n }\n\n // Create local data once\n const localData = await this.createStorageData();\n\n let totalAdded = 0;\n let totalRemoved = 0;\n\n // Sync with each provider\n for (const [providerId, provider] of providers) {\n try {\n const result = await provider.sync(localData);\n\n if (result.success && result.merged) {\n // Apply merged data from each provider\n this.loadFromStorageData(result.merged);\n totalAdded += result.added;\n totalRemoved += result.removed;\n }\n\n this.deps!.emitEvent('sync:provider', {\n providerId,\n success: result.success,\n added: result.added,\n removed: result.removed,\n });\n } catch (providerError) {\n // Log error but continue with other providers\n console.warn(`[PaymentsModule] Sync failed for provider ${providerId}:`, providerError);\n this.deps!.emitEvent('sync:provider', {\n providerId,\n success: false,\n error: providerError instanceof Error ? providerError.message : String(providerError),\n });\n }\n }\n\n this.deps!.emitEvent('sync:completed', {\n source: 'payments',\n count: this.tokens.size,\n });\n\n return { added: totalAdded, removed: totalRemoved };\n } catch (error) {\n this.deps!.emitEvent('sync:error', {\n source: 'payments',\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n /**\n * Get all active token storage providers\n */\n private getTokenStorageProviders(): Map<string, TokenStorageProvider<TxfStorageDataBase>> {\n // Prefer new multi-provider map\n if (this.deps!.tokenStorageProviders && this.deps!.tokenStorageProviders.size > 0) {\n return this.deps!.tokenStorageProviders;\n }\n\n // Fallback to deprecated single provider\n if (this.deps!.tokenStorage) {\n const map = new Map<string, TokenStorageProvider<TxfStorageDataBase>>();\n map.set(this.deps!.tokenStorage.id, this.deps!.tokenStorage);\n return map;\n }\n\n return new Map();\n }\n\n /**\n * Update token storage providers (called when providers are added/removed dynamically)\n */\n updateTokenStorageProviders(providers: Map<string, TokenStorageProvider<TxfStorageDataBase>>): void {\n if (this.deps) {\n this.deps.tokenStorageProviders = providers;\n }\n }\n\n /**\n * Validate tokens with aggregator\n */\n async validate(): Promise<{ valid: Token[]; invalid: Token[] }> {\n this.ensureInitialized();\n\n const valid: Token[] = [];\n const invalid: Token[] = [];\n\n for (const token of this.tokens.values()) {\n const result = await this.deps!.oracle.validateToken(token.sdkData);\n\n if (result.valid && !result.spent) {\n valid.push(token);\n } else {\n token.status = 'invalid';\n invalid.push(token);\n }\n }\n\n if (invalid.length > 0) {\n await this.save();\n }\n\n return { valid, invalid };\n }\n\n /**\n * Get pending transfers\n */\n getPendingTransfers(): TransferResult[] {\n return Array.from(this.pendingTransfers.values());\n }\n\n // ===========================================================================\n // Private: Transfer Operations\n // ===========================================================================\n\n private async resolveRecipient(recipient: string): Promise<string> {\n if (recipient.startsWith('@')) {\n const nametag = recipient.slice(1);\n const pubkey = await this.deps!.transport.resolveNametag?.(nametag);\n if (!pubkey) {\n throw new Error(`Nametag not found: ${nametag}`);\n }\n return pubkey;\n }\n return recipient;\n }\n\n /**\n * Create SDK TransferCommitment for a token transfer\n */\n private async createSdkCommitment(\n token: Token,\n recipientAddress: IAddress,\n signingService: SigningService\n ): Promise<TransferCommitment> {\n // Parse SDK token from stored data\n const tokenData = token.sdkData\n ? (typeof token.sdkData === 'string' ? JSON.parse(token.sdkData) : token.sdkData)\n : token;\n\n const sdkToken = await SdkToken.fromJSON(tokenData);\n\n // Generate random salt\n const salt = crypto.getRandomValues(new Uint8Array(32));\n\n // Create transfer commitment\n const commitment = await TransferCommitment.create(\n sdkToken,\n recipientAddress,\n salt,\n null, // recipientData\n null, // recipientDataHash\n signingService\n );\n\n return commitment;\n }\n\n /**\n * Create SigningService from identity private key\n */\n private async createSigningService(): Promise<SigningService> {\n const privateKeyHex = this.deps!.identity.privateKey;\n const privateKeyBytes = new Uint8Array(\n privateKeyHex.match(/.{1,2}/g)!.map((byte) => parseInt(byte, 16))\n );\n return SigningService.createFromSecret(privateKeyBytes);\n }\n\n /**\n * Resolve recipient to IAddress\n */\n private async resolveRecipientAddress(recipient: string): Promise<IAddress> {\n // If it's a nametag, resolve via TokenId\n if (recipient.startsWith('@')) {\n const nametag = recipient.slice(1);\n const tokenId = await TokenId.fromNameTag(nametag);\n return ProxyAddress.fromTokenId(tokenId);\n }\n\n // If it's a pubkey, create proxy address from it\n const pubkeyBytes = new Uint8Array(\n recipient.match(/.{1,2}/g)!.map((byte) => parseInt(byte, 16))\n );\n const tokenId = new TokenId(pubkeyBytes.slice(0, 32));\n return ProxyAddress.fromTokenId(tokenId);\n }\n\n private async handleIncomingTransfer(transfer: IncomingTokenTransfer): Promise<void> {\n try {\n // Check payload format - Sphere wallet sends { sourceToken, transferTx }\n // SDK format is { token, proof }\n const payload = transfer.payload as unknown as Record<string, unknown>;\n\n let tokenData: unknown;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let finalizedSdkToken: SdkToken<any> | null = null;\n\n if (payload.sourceToken && payload.transferTx) {\n // Sphere wallet format - needs finalization for PROXY addresses\n this.log('Processing Sphere wallet format transfer...');\n\n const sourceTokenInput = typeof payload.sourceToken === 'string'\n ? JSON.parse(payload.sourceToken as string)\n : payload.sourceToken;\n const transferTxInput = typeof payload.transferTx === 'string'\n ? JSON.parse(payload.transferTx as string)\n : payload.transferTx;\n\n if (!sourceTokenInput || !transferTxInput) {\n console.warn('[Payments] Invalid Sphere wallet transfer format');\n return;\n }\n\n const sourceToken = await SdkToken.fromJSON(sourceTokenInput);\n const transferTx = await TransferTransaction.fromJSON(transferTxInput);\n\n // Check if this is a PROXY address transfer (needs finalization)\n const recipientAddress = transferTx.data.recipient;\n const addressScheme = recipientAddress.scheme;\n\n if (addressScheme === AddressScheme.PROXY) {\n // Need to finalize with nametag token\n if (!this.nametag?.token) {\n console.error('[Payments] Cannot finalize PROXY transfer - no nametag token. Token rejected.');\n return; // Reject token - cannot spend without finalization\n }\n {\n try {\n const nametagToken = await SdkToken.fromJSON(this.nametag.token);\n const signingService = await this.createSigningService();\n const transferSalt = transferTx.data.salt;\n\n const recipientPredicate = await UnmaskedPredicate.create(\n sourceToken.id,\n sourceToken.type,\n signingService,\n HashAlgorithm.SHA256,\n transferSalt\n );\n\n const recipientState = new TokenState(recipientPredicate, null);\n\n const stClient = this.deps!.oracle.getStateTransitionClient?.() as StateTransitionClient | undefined;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const trustBase = (this.deps!.oracle as any).getTrustBase?.();\n\n if (!stClient || !trustBase) {\n console.error('[Payments] Cannot finalize - missing state transition client or trust base. Token rejected.');\n return; // Reject token - cannot spend without finalization\n }\n\n finalizedSdkToken = await stClient.finalizeTransaction(\n trustBase,\n sourceToken,\n recipientState,\n transferTx,\n [nametagToken]\n );\n tokenData = finalizedSdkToken.toJSON();\n this.log('Token finalized successfully');\n } catch (finalizeError) {\n console.error('[Payments] Finalization failed:', finalizeError);\n return; // Reject token - cannot spend without finalization\n }\n }\n } else {\n // Direct address - no finalization needed\n tokenData = sourceTokenInput;\n }\n } else if (payload.token) {\n // SDK format\n tokenData = payload.token;\n } else {\n console.warn('[Payments] Unknown transfer payload format');\n return;\n }\n\n // Validate token\n const validation = await this.deps!.oracle.validateToken(tokenData);\n if (!validation.valid) {\n console.warn('[Payments] Received invalid token');\n return;\n }\n\n // Parse token info from SDK data\n const tokenInfo = await parseTokenInfo(tokenData);\n\n // Create token entry\n const token: Token = {\n id: tokenInfo.tokenId ?? crypto.randomUUID(),\n coinId: tokenInfo.coinId,\n symbol: tokenInfo.symbol,\n name: tokenInfo.name,\n amount: tokenInfo.amount,\n status: 'confirmed',\n createdAt: Date.now(),\n updatedAt: Date.now(),\n sdkData: typeof tokenData === 'string'\n ? tokenData\n : JSON.stringify(tokenData),\n };\n\n // Check if tombstoned\n const sdkTokenId = extractTokenIdFromSdkData(token.sdkData);\n const stateHash = extractStateHashFromSdkData(token.sdkData);\n if (sdkTokenId && stateHash && this.isStateTombstoned(sdkTokenId, stateHash)) {\n this.log(`Rejected tombstoned token ${sdkTokenId.slice(0, 8)}...`);\n return;\n }\n\n await this.addToken(token);\n\n const incomingTransfer: IncomingTransfer = {\n id: transfer.id,\n senderPubkey: transfer.senderPubkey,\n tokens: [token],\n memo: payload.memo as string | undefined,\n receivedAt: transfer.timestamp,\n };\n\n this.deps!.emitEvent('transfer:incoming', incomingTransfer);\n this.log(`Incoming transfer processed: ${token.id}, ${token.amount} ${token.symbol}`);\n } catch (error) {\n console.error('[Payments] Failed to process incoming transfer:', error);\n }\n }\n\n // ===========================================================================\n // Private: Archive\n // ===========================================================================\n\n private async archiveToken(token: Token): Promise<void> {\n const txf = tokenToTxf(token);\n if (!txf) return;\n\n const tokenId = txf.genesis?.data?.tokenId;\n if (!tokenId) return;\n\n const existingArchive = this.archivedTokens.get(tokenId);\n\n if (existingArchive) {\n if (isIncrementalUpdate(existingArchive, txf)) {\n this.archivedTokens.set(tokenId, txf);\n this.log(`Updated archived token ${tokenId.slice(0, 8)}...`);\n } else {\n // Fork\n const stateHash = getCurrentStateHash(txf) || '';\n await this.storeForkedToken(tokenId, stateHash, txf);\n this.log(`Archived token ${tokenId.slice(0, 8)}... is a fork`);\n }\n } else {\n this.archivedTokens.set(tokenId, txf);\n this.log(`Archived token ${tokenId.slice(0, 8)}...`);\n }\n }\n\n // ===========================================================================\n // Private: Storage\n // ===========================================================================\n\n private async save(): Promise<void> {\n const tokens = Array.from(this.tokens.values());\n\n const data = {\n tokens,\n tombstones: this.tombstones.length > 0 ? this.tombstones : undefined,\n archivedTokens: this.archivedTokens.size > 0\n ? Object.fromEntries(this.archivedTokens)\n : undefined,\n forkedTokens: this.forkedTokens.size > 0\n ? Object.fromEntries(this.forkedTokens)\n : undefined,\n nametag: this.nametag || undefined,\n };\n\n await this.deps!.storage.set(STORAGE_KEYS.TOKENS, JSON.stringify(data));\n }\n\n private async saveToOutbox(transfer: TransferResult, recipient: string): Promise<void> {\n const outbox = await this.loadOutbox();\n outbox.push({ transfer, recipient, createdAt: Date.now() });\n await this.deps!.storage.set(STORAGE_KEYS.OUTBOX, JSON.stringify(outbox));\n }\n\n private async removeFromOutbox(transferId: string): Promise<void> {\n const outbox = await this.loadOutbox();\n const filtered = outbox.filter((e) => e.transfer.id !== transferId);\n await this.deps!.storage.set(STORAGE_KEYS.OUTBOX, JSON.stringify(filtered));\n }\n\n private async loadOutbox(): Promise<Array<{ transfer: TransferResult; recipient: string; createdAt: number }>> {\n const data = await this.deps!.storage.get(STORAGE_KEYS.OUTBOX);\n return data ? JSON.parse(data) : [];\n }\n\n private async createStorageData(): Promise<TxfStorageDataBase> {\n const tokens = Array.from(this.tokens.values());\n\n return await buildTxfStorageData(\n tokens,\n {\n version: 1,\n address: this.deps!.identity.address,\n ipnsName: this.deps!.identity.ipnsName ?? '',\n },\n {\n nametag: this.nametag || undefined,\n tombstones: this.tombstones,\n archivedTokens: this.archivedTokens,\n forkedTokens: this.forkedTokens,\n }\n ) as unknown as TxfStorageDataBase;\n }\n\n private loadFromStorageData(data: TxfStorageDataBase): void {\n const parsed = parseTxfStorageData(data);\n\n // Load tokens\n this.tokens.clear();\n for (const token of parsed.tokens) {\n this.tokens.set(token.id, token);\n }\n\n // Load other data\n this.tombstones = parsed.tombstones;\n this.archivedTokens = parsed.archivedTokens;\n this.forkedTokens = parsed.forkedTokens;\n this.nametag = parsed.nametag;\n }\n\n // ===========================================================================\n // Private: Helpers\n // ===========================================================================\n\n private ensureInitialized(): void {\n if (!this.deps) {\n throw new Error('PaymentsModule not initialized');\n }\n }\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\nexport function createPaymentsModule(config?: PaymentsModuleConfig): PaymentsModule {\n return new PaymentsModule(config);\n}\n","/**\n * Communications Module\n * Platform-independent messaging operations\n */\n\nimport type {\n DirectMessage,\n BroadcastMessage,\n FullIdentity,\n SphereEventType,\n SphereEventMap,\n} from '../../types';\nimport type { StorageProvider } from '../../storage';\nimport type { TransportProvider, IncomingMessage, IncomingBroadcast } from '../../transport';\n\n// =============================================================================\n// Configuration\n// =============================================================================\n\nexport interface CommunicationsModuleConfig {\n /** Auto-save messages */\n autoSave?: boolean;\n /** Max messages in memory */\n maxMessages?: number;\n /** Enable read receipts */\n readReceipts?: boolean;\n}\n\n// =============================================================================\n// Dependencies Interface\n// =============================================================================\n\nexport interface CommunicationsModuleDependencies {\n identity: FullIdentity;\n storage: StorageProvider;\n transport: TransportProvider;\n emitEvent: <T extends SphereEventType>(type: T, data: SphereEventMap[T]) => void;\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\nexport class CommunicationsModule {\n private config: Required<CommunicationsModuleConfig>;\n private deps: CommunicationsModuleDependencies | null = null;\n\n // State\n private messages: Map<string, DirectMessage> = new Map();\n private broadcasts: Map<string, BroadcastMessage> = new Map();\n\n // Subscriptions\n private unsubscribeMessages: (() => void) | null = null;\n private broadcastSubscriptions: Map<string, () => void> = new Map();\n\n // Handlers\n private dmHandlers: Set<(message: DirectMessage) => void> = new Set();\n private broadcastHandlers: Set<(message: BroadcastMessage) => void> = new Set();\n\n constructor(config?: CommunicationsModuleConfig) {\n this.config = {\n autoSave: config?.autoSave ?? true,\n maxMessages: config?.maxMessages ?? 1000,\n readReceipts: config?.readReceipts ?? true,\n };\n }\n\n // ===========================================================================\n // Lifecycle\n // ===========================================================================\n\n /**\n * Initialize module with dependencies\n */\n initialize(deps: CommunicationsModuleDependencies): void {\n this.deps = deps;\n\n // Subscribe to incoming messages\n this.unsubscribeMessages = deps.transport.onMessage((msg) => {\n this.handleIncomingMessage(msg);\n });\n }\n\n /**\n * Load messages from storage\n */\n async load(): Promise<void> {\n this.ensureInitialized();\n\n const data = await this.deps!.storage.get('direct_messages');\n if (data) {\n const messages = JSON.parse(data) as DirectMessage[];\n this.messages.clear();\n for (const msg of messages) {\n this.messages.set(msg.id, msg);\n }\n }\n }\n\n /**\n * Cleanup resources\n */\n destroy(): void {\n this.unsubscribeMessages?.();\n this.unsubscribeMessages = null;\n\n for (const unsub of this.broadcastSubscriptions.values()) {\n unsub();\n }\n this.broadcastSubscriptions.clear();\n }\n\n // ===========================================================================\n // Public API - Direct Messages\n // ===========================================================================\n\n /**\n * Send direct message\n */\n async sendDM(recipient: string, content: string): Promise<DirectMessage> {\n this.ensureInitialized();\n\n // Resolve recipient\n const recipientPubkey = await this.resolveRecipient(recipient);\n\n // Send via transport\n const eventId = await this.deps!.transport.sendMessage(recipientPubkey, content);\n\n // Create message record\n const message: DirectMessage = {\n id: eventId,\n senderPubkey: this.deps!.identity.publicKey,\n senderNametag: this.deps!.identity.nametag,\n recipientPubkey,\n content,\n timestamp: Date.now(),\n isRead: true,\n };\n\n // Save\n this.messages.set(message.id, message);\n if (this.config.autoSave) {\n await this.save();\n }\n\n return message;\n }\n\n /**\n * Get conversation with peer\n */\n getConversation(peerPubkey: string): DirectMessage[] {\n return Array.from(this.messages.values())\n .filter(\n (m) => m.senderPubkey === peerPubkey || m.recipientPubkey === peerPubkey\n )\n .sort((a, b) => a.timestamp - b.timestamp);\n }\n\n /**\n * Get all conversations grouped by peer\n */\n getConversations(): Map<string, DirectMessage[]> {\n const conversations = new Map<string, DirectMessage[]>();\n\n for (const message of this.messages.values()) {\n const peer =\n message.senderPubkey === this.deps?.identity.publicKey\n ? message.recipientPubkey\n : message.senderPubkey;\n\n if (!conversations.has(peer)) {\n conversations.set(peer, []);\n }\n conversations.get(peer)!.push(message);\n }\n\n // Sort each conversation\n for (const msgs of conversations.values()) {\n msgs.sort((a, b) => a.timestamp - b.timestamp);\n }\n\n return conversations;\n }\n\n /**\n * Mark messages as read\n */\n async markAsRead(messageIds: string[]): Promise<void> {\n for (const id of messageIds) {\n const msg = this.messages.get(id);\n if (msg) {\n msg.isRead = true;\n }\n }\n\n if (this.config.autoSave) {\n await this.save();\n }\n }\n\n /**\n * Get unread count\n */\n getUnreadCount(peerPubkey?: string): number {\n let messages = Array.from(this.messages.values()).filter(\n (m) => !m.isRead && m.senderPubkey !== this.deps?.identity.publicKey\n );\n\n if (peerPubkey) {\n messages = messages.filter((m) => m.senderPubkey === peerPubkey);\n }\n\n return messages.length;\n }\n\n /**\n * Subscribe to incoming DMs\n */\n onDirectMessage(handler: (message: DirectMessage) => void): () => void {\n this.dmHandlers.add(handler);\n return () => this.dmHandlers.delete(handler);\n }\n\n // ===========================================================================\n // Public API - Broadcasts\n // ===========================================================================\n\n /**\n * Publish broadcast message\n */\n async broadcast(content: string, tags?: string[]): Promise<BroadcastMessage> {\n this.ensureInitialized();\n\n const eventId = await this.deps!.transport.publishBroadcast?.(content, tags);\n\n const message: BroadcastMessage = {\n id: eventId ?? crypto.randomUUID(),\n authorPubkey: this.deps!.identity.publicKey,\n authorNametag: this.deps!.identity.nametag,\n content,\n timestamp: Date.now(),\n tags,\n };\n\n this.broadcasts.set(message.id, message);\n return message;\n }\n\n /**\n * Subscribe to broadcasts with tags\n */\n subscribeToBroadcasts(tags: string[]): () => void {\n this.ensureInitialized();\n\n const key = tags.sort().join(':');\n if (this.broadcastSubscriptions.has(key)) {\n return () => {};\n }\n\n const unsub = this.deps!.transport.subscribeToBroadcast?.(tags, (broadcast) => {\n this.handleIncomingBroadcast(broadcast);\n });\n\n if (unsub) {\n this.broadcastSubscriptions.set(key, unsub);\n }\n\n return () => {\n const sub = this.broadcastSubscriptions.get(key);\n if (sub) {\n sub();\n this.broadcastSubscriptions.delete(key);\n }\n };\n }\n\n /**\n * Get broadcasts\n */\n getBroadcasts(limit?: number): BroadcastMessage[] {\n const messages = Array.from(this.broadcasts.values())\n .sort((a, b) => b.timestamp - a.timestamp);\n\n return limit ? messages.slice(0, limit) : messages;\n }\n\n /**\n * Subscribe to incoming broadcasts\n */\n onBroadcast(handler: (message: BroadcastMessage) => void): () => void {\n this.broadcastHandlers.add(handler);\n return () => this.broadcastHandlers.delete(handler);\n }\n\n // ===========================================================================\n // Private: Message Handling\n // ===========================================================================\n\n private handleIncomingMessage(msg: IncomingMessage): void {\n // Skip own messages\n if (msg.senderPubkey === this.deps?.identity.publicKey) return;\n\n const message: DirectMessage = {\n id: msg.id,\n senderPubkey: msg.senderPubkey,\n recipientPubkey: this.deps!.identity.publicKey,\n content: msg.content,\n timestamp: msg.timestamp,\n isRead: false,\n };\n\n this.messages.set(message.id, message);\n\n // Emit event\n this.deps!.emitEvent('message:dm', message);\n\n // Notify handlers\n for (const handler of this.dmHandlers) {\n try {\n handler(message);\n } catch (error) {\n console.error('[Communications] Handler error:', error);\n }\n }\n\n // Auto-save\n if (this.config.autoSave) {\n this.save();\n }\n\n // Prune if needed\n this.pruneIfNeeded();\n }\n\n private handleIncomingBroadcast(incoming: IncomingBroadcast): void {\n const message: BroadcastMessage = {\n id: incoming.id,\n authorPubkey: incoming.authorPubkey,\n content: incoming.content,\n timestamp: incoming.timestamp,\n tags: incoming.tags,\n };\n\n this.broadcasts.set(message.id, message);\n\n // Emit event\n this.deps!.emitEvent('message:broadcast', message);\n\n // Notify handlers\n for (const handler of this.broadcastHandlers) {\n try {\n handler(message);\n } catch (error) {\n console.error('[Communications] Handler error:', error);\n }\n }\n }\n\n // ===========================================================================\n // Private: Storage\n // ===========================================================================\n\n private async save(): Promise<void> {\n const messages = Array.from(this.messages.values());\n await this.deps!.storage.set('direct_messages', JSON.stringify(messages));\n }\n\n private pruneIfNeeded(): void {\n if (this.messages.size <= this.config.maxMessages) return;\n\n const sorted = Array.from(this.messages.entries())\n .sort(([, a], [, b]) => a.timestamp - b.timestamp);\n\n const toRemove = sorted.slice(0, sorted.length - this.config.maxMessages);\n for (const [id] of toRemove) {\n this.messages.delete(id);\n }\n }\n\n // ===========================================================================\n // Private: Helpers\n // ===========================================================================\n\n private async resolveRecipient(recipient: string): Promise<string> {\n if (recipient.startsWith('@')) {\n const pubkey = await this.deps!.transport.resolveNametag?.(recipient.slice(1));\n if (!pubkey) {\n throw new Error(`Nametag not found: ${recipient}`);\n }\n return pubkey;\n }\n return recipient;\n }\n\n private ensureInitialized(): void {\n if (!this.deps) {\n throw new Error('CommunicationsModule not initialized');\n }\n }\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\nexport function createCommunicationsModule(\n config?: CommunicationsModuleConfig\n): CommunicationsModule {\n return new CommunicationsModule(config);\n}\n","/**\n * Encryption utilities for SDK2\n *\n * Provides AES-256 encryption for sensitive wallet data.\n * Uses crypto-js for cross-platform compatibility.\n */\n\nimport CryptoJS from 'crypto-js';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface EncryptedData {\n /** Encrypted ciphertext (base64) */\n ciphertext: string;\n /** Initialization vector (hex) */\n iv: string;\n /** Salt used for key derivation (hex) */\n salt: string;\n /** Algorithm identifier */\n algorithm: 'aes-256-cbc';\n /** Key derivation function */\n kdf: 'pbkdf2';\n /** Number of PBKDF2 iterations */\n iterations: number;\n}\n\nexport interface EncryptionOptions {\n /** Number of PBKDF2 iterations (default: 100000) */\n iterations?: number;\n}\n\n// =============================================================================\n// Constants\n// =============================================================================\n\n/** Default number of PBKDF2 iterations */\nconst DEFAULT_ITERATIONS = 100000;\n\n/** AES key size in bits */\nconst KEY_SIZE = 256;\n\n/** Salt size in bytes */\nconst SALT_SIZE = 16;\n\n/** IV size in bytes */\nconst IV_SIZE = 16;\n\n// =============================================================================\n// Key Derivation\n// =============================================================================\n\n/**\n * Derive encryption key from password using PBKDF2\n * @param password - User password\n * @param salt - Salt as WordArray\n * @param iterations - Number of iterations\n */\nfunction deriveKey(\n password: string,\n salt: CryptoJS.lib.WordArray,\n iterations: number\n): CryptoJS.lib.WordArray {\n return CryptoJS.PBKDF2(password, salt, {\n keySize: KEY_SIZE / 32, // WordArray uses 32-bit words\n iterations,\n hasher: CryptoJS.algo.SHA256,\n });\n}\n\n// =============================================================================\n// Encryption Functions\n// =============================================================================\n\n/**\n * Encrypt data with AES-256-CBC\n * @param plaintext - Data to encrypt (string or object)\n * @param password - Encryption password\n * @param options - Encryption options\n */\nexport function encrypt(\n plaintext: string | object,\n password: string,\n options: EncryptionOptions = {}\n): EncryptedData {\n const iterations = options.iterations ?? DEFAULT_ITERATIONS;\n\n // Convert object to JSON string if needed\n const data = typeof plaintext === 'string' ? plaintext : JSON.stringify(plaintext);\n\n // Generate random salt and IV\n const salt = CryptoJS.lib.WordArray.random(SALT_SIZE);\n const iv = CryptoJS.lib.WordArray.random(IV_SIZE);\n\n // Derive key from password\n const key = deriveKey(password, salt, iterations);\n\n // Encrypt with AES-256-CBC\n const encrypted = CryptoJS.AES.encrypt(data, key, {\n iv,\n mode: CryptoJS.mode.CBC,\n padding: CryptoJS.pad.Pkcs7,\n });\n\n return {\n ciphertext: encrypted.ciphertext.toString(CryptoJS.enc.Base64),\n iv: iv.toString(CryptoJS.enc.Hex),\n salt: salt.toString(CryptoJS.enc.Hex),\n algorithm: 'aes-256-cbc',\n kdf: 'pbkdf2',\n iterations,\n };\n}\n\n/**\n * Decrypt AES-256-CBC encrypted data\n * @param encryptedData - Encrypted data object\n * @param password - Decryption password\n */\nexport function decrypt(encryptedData: EncryptedData, password: string): string {\n // Parse salt and IV\n const salt = CryptoJS.enc.Hex.parse(encryptedData.salt);\n const iv = CryptoJS.enc.Hex.parse(encryptedData.iv);\n\n // Derive key from password\n const key = deriveKey(password, salt, encryptedData.iterations);\n\n // Parse ciphertext\n const ciphertext = CryptoJS.enc.Base64.parse(encryptedData.ciphertext);\n\n // Create cipher params\n const cipherParams = CryptoJS.lib.CipherParams.create({\n ciphertext,\n });\n\n // Decrypt\n const decrypted = CryptoJS.AES.decrypt(cipherParams, key, {\n iv,\n mode: CryptoJS.mode.CBC,\n padding: CryptoJS.pad.Pkcs7,\n });\n\n const result = decrypted.toString(CryptoJS.enc.Utf8);\n\n if (!result) {\n throw new Error('Decryption failed: invalid password or corrupted data');\n }\n\n return result;\n}\n\n/**\n * Decrypt and parse JSON data\n * @param encryptedData - Encrypted data object\n * @param password - Decryption password\n */\nexport function decryptJson<T = unknown>(encryptedData: EncryptedData, password: string): T {\n const decrypted = decrypt(encryptedData, password);\n try {\n return JSON.parse(decrypted) as T;\n } catch {\n throw new Error('Decryption failed: invalid JSON data');\n }\n}\n\n// =============================================================================\n// Simple Encryption (Password-based, for localStorage)\n// =============================================================================\n\n/**\n * Simple encryption using CryptoJS built-in password-based encryption\n * Suitable for localStorage where we don't need full EncryptedData metadata\n * @param plaintext - Data to encrypt\n * @param password - Encryption password\n */\nexport function encryptSimple(plaintext: string, password: string): string {\n return CryptoJS.AES.encrypt(plaintext, password).toString();\n}\n\n/**\n * Simple decryption\n * @param ciphertext - Encrypted string\n * @param password - Decryption password\n */\nexport function decryptSimple(ciphertext: string, password: string): string {\n const decrypted = CryptoJS.AES.decrypt(ciphertext, password);\n const result = decrypted.toString(CryptoJS.enc.Utf8);\n\n if (!result) {\n throw new Error('Decryption failed: invalid password or corrupted data');\n }\n\n return result;\n}\n\n// =============================================================================\n// Mnemonic Encryption (Compatible with existing wallet format)\n// =============================================================================\n\n/**\n * Encrypt mnemonic phrase for storage\n * Uses simple AES encryption compatible with existing wallet format\n * @param mnemonic - BIP39 mnemonic phrase\n * @param password - Encryption password\n */\nexport function encryptMnemonic(mnemonic: string, password: string): string {\n return encryptSimple(mnemonic, password);\n}\n\n/**\n * Decrypt mnemonic phrase from storage\n * @param encryptedMnemonic - Encrypted mnemonic string\n * @param password - Decryption password\n */\nexport function decryptMnemonic(encryptedMnemonic: string, password: string): string {\n return decryptSimple(encryptedMnemonic, password);\n}\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\n/**\n * Check if data looks like an EncryptedData object\n */\nexport function isEncryptedData(data: unknown): data is EncryptedData {\n if (typeof data !== 'object' || data === null) {\n return false;\n }\n const obj = data as Record<string, unknown>;\n return (\n typeof obj.ciphertext === 'string' &&\n typeof obj.iv === 'string' &&\n typeof obj.salt === 'string' &&\n obj.algorithm === 'aes-256-cbc' &&\n obj.kdf === 'pbkdf2' &&\n typeof obj.iterations === 'number'\n );\n}\n\n/**\n * Serialize EncryptedData to string for storage\n */\nexport function serializeEncrypted(data: EncryptedData): string {\n return JSON.stringify(data);\n}\n\n/**\n * Deserialize EncryptedData from string\n */\nexport function deserializeEncrypted(serialized: string): EncryptedData {\n const parsed = JSON.parse(serialized);\n if (!isEncryptedData(parsed)) {\n throw new Error('Invalid encrypted data format');\n }\n return parsed;\n}\n\n/**\n * Generate a random password/key as hex string\n * @param bytes - Number of random bytes (default: 32)\n */\nexport function generateRandomKey(bytes: number = 32): string {\n return CryptoJS.lib.WordArray.random(bytes).toString(CryptoJS.enc.Hex);\n}\n","/**\n * Wallet Text Format Parsing\n *\n * Parses text-based wallet backup files (UNICITY WALLET DETAILS format)\n */\n\nimport CryptoJS from 'crypto-js';\nimport type { LegacyFileParseResult, LegacyFileParsedData } from './types';\nimport { extractFromText } from '../core/utils';\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst WALLET_HEADER = 'UNICITY WALLET DETAILS';\n\n// Legacy webwallet encryption parameters (for backwards compatibility)\nconst LEGACY_SALT = 'alpha_wallet_salt';\nconst LEGACY_ITERATIONS = 100000;\n\n// =============================================================================\n// Encryption/Decryption\n// =============================================================================\n\n/**\n * Derive encryption key using original webwallet parameters\n */\nfunction deriveLegacyKey(password: string): string {\n return CryptoJS.PBKDF2(password, LEGACY_SALT, {\n keySize: 256 / 32,\n iterations: LEGACY_ITERATIONS,\n hasher: CryptoJS.algo.SHA1,\n }).toString();\n}\n\n/**\n * Decrypt master key from text format\n */\nexport function decryptTextFormatKey(encryptedKey: string, password: string): string | null {\n try {\n const key = deriveLegacyKey(password);\n const decrypted = CryptoJS.AES.decrypt(encryptedKey, key);\n const result = decrypted.toString(CryptoJS.enc.Utf8);\n return result || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Encrypt master key for text format export\n */\nexport function encryptForTextFormat(masterPrivateKey: string, password: string): string {\n const key = deriveLegacyKey(password);\n return CryptoJS.AES.encrypt(masterPrivateKey, key).toString();\n}\n\n// =============================================================================\n// Export Types\n// =============================================================================\n\nexport interface WalletTextExportParams {\n masterPrivateKey: string;\n masterPrivateKeyWIF?: string;\n chainCode?: string;\n descriptorPath?: string;\n isBIP32: boolean;\n addresses: Array<{\n index: number;\n address: string;\n path?: string;\n isChange?: boolean;\n }>;\n}\n\nexport interface WalletTextExportOptions {\n password?: string;\n}\n\n// =============================================================================\n// Serialization Functions\n// =============================================================================\n\n/**\n * Format addresses for text export\n */\nfunction formatAddresses(\n addresses: WalletTextExportParams['addresses'],\n isBIP32: boolean\n): string {\n return addresses\n .map((addr, index) => {\n const path = addr.path || (isBIP32\n ? `m/84'/1'/0'/${addr.isChange ? 1 : 0}/${addr.index}`\n : `m/44'/0'/${addr.index}'`);\n return `Address ${index + 1}: ${addr.address} (Path: ${path})`;\n })\n .join('\\n');\n}\n\n/**\n * Serialize wallet to text format (unencrypted)\n */\nexport function serializeWalletToText(params: WalletTextExportParams): string {\n const {\n masterPrivateKey,\n masterPrivateKeyWIF,\n chainCode,\n descriptorPath,\n isBIP32,\n addresses,\n } = params;\n\n const addressesText = formatAddresses(addresses, isBIP32);\n\n let masterKeySection: string;\n\n if (isBIP32 && chainCode) {\n masterKeySection = `MASTER PRIVATE KEY (keep secret!):\n${masterPrivateKey}\n${masterPrivateKeyWIF ? `\\nMASTER PRIVATE KEY IN WIF FORMAT (for importprivkey command):\\n${masterPrivateKeyWIF}\\n` : ''}\nMASTER CHAIN CODE (for BIP32 HD wallet compatibility):\n${chainCode}\n\nDESCRIPTOR PATH: ${descriptorPath || \"84'/1'/0'\"}\n\nWALLET TYPE: BIP32 hierarchical deterministic wallet\n\nENCRYPTION STATUS: Not encrypted\nThis key is in plaintext and not protected. Anyone with this file can access your wallet.`;\n } else {\n masterKeySection = `MASTER PRIVATE KEY (keep secret!):\n${masterPrivateKey}\n${masterPrivateKeyWIF ? `\\nMASTER PRIVATE KEY IN WIF FORMAT (for importprivkey command):\\n${masterPrivateKeyWIF}\\n` : ''}\nWALLET TYPE: Standard wallet (HMAC-based)\n\nENCRYPTION STATUS: Not encrypted\nThis key is in plaintext and not protected. Anyone with this file can access your wallet.`;\n }\n\n return `${WALLET_HEADER}\n===========================\n\n${masterKeySection}\n\nYOUR ADDRESSES:\n${addressesText}\n\nGenerated on: ${new Date().toLocaleString()}\n\nWARNING: Keep your master private key safe and secure.\nAnyone with your master private key can access all your funds.`;\n}\n\n/**\n * Serialize wallet to text format (encrypted)\n */\nexport function serializeEncryptedWalletToText(params: {\n encryptedMasterKey: string;\n chainCode?: string;\n descriptorPath?: string;\n isBIP32: boolean;\n addresses: WalletTextExportParams['addresses'];\n}): string {\n const { encryptedMasterKey, chainCode, descriptorPath, isBIP32, addresses } = params;\n\n const addressesText = formatAddresses(addresses, isBIP32);\n\n let encryptedContent = `ENCRYPTED MASTER KEY (password protected):\n${encryptedMasterKey}`;\n\n if (isBIP32 && chainCode) {\n encryptedContent += `\n\nMASTER CHAIN CODE (for BIP32 HD wallet compatibility):\n${chainCode}\n\nDESCRIPTOR PATH: ${descriptorPath || \"84'/1'/0'\"}\n\nWALLET TYPE: BIP32 hierarchical deterministic wallet`;\n } else {\n encryptedContent += `\n\nWALLET TYPE: Standard wallet (HMAC-based)`;\n }\n\n return `${WALLET_HEADER}\n===========================\n\n${encryptedContent}\n\nENCRYPTION STATUS: Encrypted with password\nTo use this key, you will need the password you set in the wallet.\n\nYOUR ADDRESSES:\n${addressesText}\n\nGenerated on: ${new Date().toLocaleString()}\n\nWARNING: Keep your master private key safe and secure.\nAnyone with your master private key can access all your funds.`;\n}\n\n// =============================================================================\n// Detection\n// =============================================================================\n\n/**\n * Check if content is wallet text format\n */\nexport function isWalletTextFormat(content: string): boolean {\n return (\n content.includes(WALLET_HEADER) &&\n (content.includes('MASTER PRIVATE KEY') || content.includes('ENCRYPTED MASTER KEY'))\n );\n}\n\n/**\n * Check if text wallet is encrypted\n */\nexport function isTextWalletEncrypted(content: string): boolean {\n return content.includes('ENCRYPTED MASTER KEY');\n}\n\n// =============================================================================\n// Parse Functions\n// =============================================================================\n\n/**\n * Parse wallet from text format (unencrypted)\n */\nexport function parseWalletText(content: string): LegacyFileParseResult {\n try {\n const isEncrypted = isTextWalletEncrypted(content);\n\n if (isEncrypted) {\n // Extract encrypted key - caller needs to decrypt\n const encryptedKey = extractFromText(\n content,\n /ENCRYPTED MASTER KEY \\(password protected\\):\\s*([^\\n]+)/\n );\n\n if (!encryptedKey) {\n return {\n success: false,\n error: 'Could not find encrypted master key in backup file',\n };\n }\n\n // Return with needsPassword flag\n return {\n success: false,\n needsPassword: true,\n error: 'Password required for encrypted wallet',\n };\n }\n\n // Extract unencrypted master key\n const masterKey = extractFromText(\n content,\n /MASTER PRIVATE KEY \\(keep secret!\\):\\s*([^\\n]+)/\n );\n\n if (!masterKey) {\n return {\n success: false,\n error: 'Could not find master private key in backup file',\n };\n }\n\n // Extract chain code\n const chainCode = extractFromText(\n content,\n /MASTER CHAIN CODE \\(for (?:BIP32 HD|Alpha) wallet compatibility\\):\\s*([^\\n]+)/\n );\n\n // Extract descriptor path\n const descriptorPath = extractFromText(content, /DESCRIPTOR PATH:\\s*([^\\n]+)/);\n\n // Determine derivation mode\n const isBIP32 =\n content.includes('WALLET TYPE: BIP32 hierarchical deterministic wallet') ||\n content.includes('WALLET TYPE: Alpha descriptor wallet') ||\n !!chainCode;\n\n const data: LegacyFileParsedData = {\n masterKey,\n chainCode: chainCode ?? undefined,\n descriptorPath: descriptorPath ?? undefined,\n derivationMode: isBIP32 ? 'bip32' : 'wif_hmac',\n };\n\n return {\n success: true,\n data,\n };\n } catch (e) {\n return {\n success: false,\n error: `Failed to parse wallet text: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n\n/**\n * Parse and decrypt wallet from text format\n */\nexport function parseAndDecryptWalletText(\n content: string,\n password: string\n): LegacyFileParseResult {\n try {\n const isEncrypted = isTextWalletEncrypted(content);\n\n if (!isEncrypted) {\n // Not encrypted, parse directly\n return parseWalletText(content);\n }\n\n // Extract encrypted key\n const encryptedKey = extractFromText(\n content,\n /ENCRYPTED MASTER KEY \\(password protected\\):\\s*([^\\n]+)/\n );\n\n if (!encryptedKey) {\n return {\n success: false,\n error: 'Could not find encrypted master key in backup file',\n };\n }\n\n // Decrypt\n const masterKey = decryptTextFormatKey(encryptedKey, password);\n\n if (!masterKey) {\n return {\n success: false,\n error: 'Failed to decrypt - incorrect password?',\n };\n }\n\n // Extract chain code (not encrypted)\n const chainCode = extractFromText(\n content,\n /MASTER CHAIN CODE \\(for (?:BIP32 HD|Alpha) wallet compatibility\\):\\s*([^\\n]+)/\n );\n\n // Extract descriptor path\n const descriptorPath = extractFromText(content, /DESCRIPTOR PATH:\\s*([^\\n]+)/);\n\n // Determine derivation mode\n const isBIP32 =\n content.includes('WALLET TYPE: BIP32 hierarchical deterministic wallet') ||\n content.includes('WALLET TYPE: Alpha descriptor wallet') ||\n !!chainCode;\n\n const data: LegacyFileParsedData = {\n masterKey,\n chainCode: chainCode ?? undefined,\n descriptorPath: descriptorPath ?? undefined,\n derivationMode: isBIP32 ? 'bip32' : 'wif_hmac',\n };\n\n return {\n success: true,\n data,\n };\n } catch (e) {\n return {\n success: false,\n error: `Failed to parse/decrypt wallet text: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n","/**\n * SDK Utility Functions\n * Pure utility functions for the wallet SDK\n */\n\n// =============================================================================\n// Constants\n// =============================================================================\n\n/** secp256k1 curve order */\nconst SECP256K1_ORDER = BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141');\n\n/** Base58 alphabet */\nconst BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';\n\n// =============================================================================\n// Private Key Validation\n// =============================================================================\n\n/**\n * Validate if a hex string is a valid secp256k1 private key\n * Must be 0 < key < n (curve order)\n */\nexport function isValidPrivateKey(hex: string): boolean {\n try {\n if (!/^[0-9a-fA-F]{64}$/.test(hex)) {\n return false;\n }\n const key = BigInt('0x' + hex);\n return key > 0n && key < SECP256K1_ORDER;\n } catch {\n return false;\n }\n}\n\n// =============================================================================\n// Base58 Encoding/Decoding\n// =============================================================================\n\n/**\n * Base58 encode hex string\n *\n * @example\n * ```ts\n * base58Encode('00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31')\n * // '1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs'\n * ```\n */\nexport function base58Encode(hex: string): string {\n let num = BigInt('0x' + hex);\n let encoded = '';\n\n while (num > 0n) {\n const remainder = Number(num % 58n);\n num = num / 58n;\n encoded = BASE58_ALPHABET[remainder] + encoded;\n }\n\n // Add leading 1s for leading 0s in hex\n for (let i = 0; i < hex.length && hex.substring(i, i + 2) === '00'; i += 2) {\n encoded = '1' + encoded;\n }\n\n return encoded;\n}\n\n/**\n * Base58 decode string to Uint8Array\n *\n * @example\n * ```ts\n * base58Decode('1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs')\n * // Uint8Array [0, 245, 74, ...]\n * ```\n */\nexport function base58Decode(str: string): Uint8Array {\n const ALPHABET_MAP: Record<string, number> = {};\n for (let i = 0; i < BASE58_ALPHABET.length; i++) {\n ALPHABET_MAP[BASE58_ALPHABET[i]] = i;\n }\n\n // Count leading zeros (represented as '1' in base58)\n let zeros = 0;\n for (let i = 0; i < str.length && str[i] === '1'; i++) {\n zeros++;\n }\n\n // Decode from base58 to number\n let num = BigInt(0);\n for (let i = 0; i < str.length; i++) {\n const char = str[i];\n if (!(char in ALPHABET_MAP)) {\n throw new Error('Invalid base58 character: ' + char);\n }\n num = num * BigInt(58) + BigInt(ALPHABET_MAP[char]);\n }\n\n // Convert to bytes\n const bytes: number[] = [];\n while (num > 0) {\n bytes.unshift(Number(num % BigInt(256)));\n num = num / BigInt(256);\n }\n\n // Add leading zeros\n for (let i = 0; i < zeros; i++) {\n bytes.unshift(0);\n }\n\n return new Uint8Array(bytes);\n}\n\n// =============================================================================\n// Binary Pattern Search\n// =============================================================================\n\n/**\n * Find pattern in Uint8Array\n *\n * @param data - Data to search in\n * @param pattern - Pattern to find\n * @param startIndex - Start index for search\n * @returns Index of pattern or -1 if not found\n */\nexport function findPattern(\n data: Uint8Array,\n pattern: Uint8Array,\n startIndex: number = 0\n): number {\n for (let i = startIndex; i <= data.length - pattern.length; i++) {\n let found = true;\n for (let j = 0; j < pattern.length; j++) {\n if (data[i + j] !== pattern[j]) {\n found = false;\n break;\n }\n }\n if (found) return i;\n }\n return -1;\n}\n\n// =============================================================================\n// Text Parsing\n// =============================================================================\n\n/**\n * Extract value from text using regex pattern\n *\n * @param text - Text to search\n * @param pattern - Regex pattern with capture group\n * @returns Captured value or null\n */\nexport function extractFromText(text: string, pattern: RegExp): string | null {\n const match = text.match(pattern);\n return match?.[1]?.trim() ?? null;\n}\n\n// =============================================================================\n// Delay/Sleep\n// =============================================================================\n\n/**\n * Sleep for specified milliseconds\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n// =============================================================================\n// Random\n// =============================================================================\n\n/**\n * Generate random hex string of specified byte length\n */\nexport function randomHex(byteLength: number): string {\n const bytes = new Uint8Array(byteLength);\n if (typeof globalThis.crypto !== 'undefined') {\n globalThis.crypto.getRandomValues(bytes);\n } else {\n // Fallback for Node.js without global crypto\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const nodeCrypto = require('crypto');\n const buf = nodeCrypto.randomBytes(byteLength);\n bytes.set(buf);\n }\n return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * Generate random UUID v4\n */\nexport function randomUUID(): string {\n if (typeof globalThis.crypto !== 'undefined' && globalThis.crypto.randomUUID) {\n return globalThis.crypto.randomUUID();\n }\n // Fallback\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const nodeCrypto = require('crypto');\n return nodeCrypto.randomUUID();\n}\n","/**\n * Wallet.dat Parsing\n *\n * Parses Bitcoin Core wallet.dat files (SQLite format)\n * Extracts keys, chain codes, and descriptors\n */\n\nimport CryptoJS from 'crypto-js';\nimport type { LegacyFileParseResult, LegacyFileParsedData, DecryptionProgressCallback } from './types';\nimport { findPattern, base58Decode, isValidPrivateKey } from '../core/utils';\nimport { bytesToHex } from '../core/crypto';\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\nfunction uint8ArrayToWordArray(u8arr: Uint8Array): CryptoJS.lib.WordArray {\n const hex = bytesToHex(u8arr);\n return CryptoJS.enc.Hex.parse(hex);\n}\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface CMasterKeyData {\n encryptedKey: Uint8Array;\n salt: Uint8Array;\n derivationMethod: number;\n iterations: number;\n position: number;\n}\n\nexport interface WalletDatInfo {\n isSQLite: boolean;\n isEncrypted: boolean;\n isDescriptorWallet: boolean;\n hasHDChain: boolean;\n descriptorKeys: string[];\n legacyKeys: string[];\n chainCode: string | null;\n descriptorPath: string | null;\n cmasterKeys: CMasterKeyData[];\n descriptorId: Uint8Array | null;\n xpubString: string | null;\n}\n\n// =============================================================================\n// Detection Functions\n// =============================================================================\n\n/**\n * Check if data is a valid SQLite database\n */\nexport function isSQLiteDatabase(data: Uint8Array): boolean {\n if (data.length < 16) return false;\n const header = new TextDecoder().decode(data.slice(0, 16));\n return header.startsWith('SQLite format 3');\n}\n\n/**\n * Check if wallet.dat is encrypted\n */\nexport function isWalletDatEncrypted(data: Uint8Array): boolean {\n const mkeyPattern = new TextEncoder().encode('mkey');\n return findPattern(data, mkeyPattern, 0) !== -1;\n}\n\n// =============================================================================\n// CMasterKey Detection\n// =============================================================================\n\nfunction findAllCMasterKeys(data: Uint8Array): CMasterKeyData[] {\n const results: CMasterKeyData[] = [];\n\n for (let pos = 0; pos < data.length - 70; pos++) {\n if (data[pos] === 0x30) {\n const saltLenPos = pos + 1 + 48;\n if (saltLenPos < data.length && data[saltLenPos] === 0x08) {\n const iterPos = saltLenPos + 1 + 8 + 4;\n if (iterPos + 4 <= data.length) {\n const iterations = data[iterPos] | (data[iterPos + 1] << 8) |\n (data[iterPos + 2] << 16) | (data[iterPos + 3] << 24);\n if (iterations >= 1000 && iterations <= 10000000) {\n const encryptedKey = data.slice(pos + 1, pos + 1 + 48);\n const salt = data.slice(saltLenPos + 1, saltLenPos + 1 + 8);\n const derivationMethod = data[saltLenPos + 1 + 8] | (data[saltLenPos + 1 + 8 + 1] << 8) |\n (data[saltLenPos + 1 + 8 + 2] << 16) | (data[saltLenPos + 1 + 8 + 3] << 24);\n\n results.push({ encryptedKey, salt, derivationMethod, iterations, position: pos });\n }\n }\n }\n }\n }\n\n return results;\n}\n\n// =============================================================================\n// Descriptor Extraction\n// =============================================================================\n\nfunction findWpkhDescriptor(data: Uint8Array): {\n descriptorId: Uint8Array | null;\n xpubString: string | null;\n descriptorPath: string | null;\n} {\n const descriptorPattern = new TextEncoder().encode('walletdescriptor');\n let descriptorIndex = 0;\n\n while ((descriptorIndex = findPattern(data, descriptorPattern, descriptorIndex)) !== -1) {\n let scanPos = descriptorIndex + descriptorPattern.length + 32;\n\n const descLen = data[scanPos];\n scanPos++;\n\n const descBytes = data.slice(scanPos, scanPos + Math.min(descLen, 200));\n let descStr = '';\n for (let i = 0; i < descBytes.length && descBytes[i] >= 32 && descBytes[i] <= 126; i++) {\n descStr += String.fromCharCode(descBytes[i]);\n }\n\n if (descStr.startsWith('wpkh(xpub') && descStr.includes('/0/*)')) {\n const xpubMatch = descStr.match(/xpub[1-9A-HJ-NP-Za-km-z]{100,}/);\n if (xpubMatch) {\n const descIdStart = descriptorIndex + descriptorPattern.length;\n const descriptorId = data.slice(descIdStart, descIdStart + 32);\n const pathMatch = descStr.match(/\\[[\\da-f]+\\/(\\d+'\\/\\d+'\\/\\d+')\\]/);\n const descriptorPath = pathMatch ? pathMatch[1] : \"84'/1'/0'\";\n\n return {\n descriptorId,\n xpubString: xpubMatch[0],\n descriptorPath,\n };\n }\n }\n\n descriptorIndex++;\n }\n\n return { descriptorId: null, xpubString: null, descriptorPath: null };\n}\n\nfunction extractChainCodeFromXpub(xpubString: string): string {\n const decoded = base58Decode(xpubString);\n return bytesToHex(decoded.slice(13, 45));\n}\n\nfunction findMasterChainCode(data: Uint8Array): string | null {\n const xpubPattern = new TextEncoder().encode('xpub');\n const base58Chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';\n let searchPos = 0;\n\n while (searchPos < data.length) {\n const xpubIndex = findPattern(data, xpubPattern, searchPos);\n if (xpubIndex === -1) break;\n\n let xpubStr = 'xpub';\n let pos = xpubIndex + 4;\n\n while (pos < data.length && xpubStr.length < 120) {\n const char = String.fromCharCode(data[pos]);\n if (base58Chars.includes(char)) {\n xpubStr += char;\n pos++;\n } else {\n break;\n }\n }\n\n if (xpubStr.length > 100) {\n try {\n const decoded = base58Decode(xpubStr);\n const depth = decoded[4];\n if (depth === 0) {\n return bytesToHex(decoded.slice(13, 45));\n }\n } catch {\n // Invalid xpub, continue\n }\n }\n\n searchPos = xpubIndex + 4;\n }\n\n return null;\n}\n\n// =============================================================================\n// Key Extraction (Unencrypted)\n// =============================================================================\n\nfunction extractDescriptorKeys(data: Uint8Array): string[] {\n const keys: string[] = [];\n const descriptorKeyPattern = new TextEncoder().encode('walletdescriptorkey');\n\n let index = 0;\n while ((index = findPattern(data, descriptorKeyPattern, index)) !== -1) {\n for (let checkPos = index + descriptorKeyPattern.length;\n checkPos < Math.min(index + descriptorKeyPattern.length + 200, data.length - 40);\n checkPos++) {\n if (data[checkPos] === 0xd3 &&\n data[checkPos + 1] === 0x02 &&\n data[checkPos + 2] === 0x01 &&\n data[checkPos + 3] === 0x01 &&\n data[checkPos + 4] === 0x04 &&\n data[checkPos + 5] === 0x20) {\n const privKey = data.slice(checkPos + 6, checkPos + 38);\n const privKeyHex = bytesToHex(privKey);\n\n if (isValidPrivateKey(privKeyHex)) {\n keys.push(privKeyHex);\n break;\n }\n }\n }\n index++;\n }\n\n return keys;\n}\n\nfunction extractLegacyKeys(data: Uint8Array): string[] {\n const keys: string[] = [];\n const keyPattern = new TextEncoder().encode('key');\n\n let index = 0;\n while ((index = findPattern(data, keyPattern, index)) !== -1) {\n const searchPattern = new Uint8Array([0x04, 0x20]);\n for (let i = index; i < Math.min(index + 200, data.length - 34); i++) {\n if (data[i] === searchPattern[0] && data[i + 1] === searchPattern[1]) {\n const privKey = data.slice(i + 2, i + 34);\n const privKeyHex = bytesToHex(privKey);\n\n if (isValidPrivateKey(privKeyHex)) {\n keys.push(privKeyHex);\n break;\n }\n }\n }\n index++;\n }\n\n return keys;\n}\n\n// =============================================================================\n// Encrypted Key Lookup\n// =============================================================================\n\nfunction findEncryptedKeyForDescriptor(\n data: Uint8Array,\n descriptorId: Uint8Array\n): { pubkey: Uint8Array; encryptedKey: Uint8Array } | null {\n const ckeyPattern = new TextEncoder().encode('walletdescriptorckey');\n let ckeyIndex = findPattern(data, ckeyPattern, 0);\n\n while (ckeyIndex !== -1) {\n const recordDescId = data.slice(ckeyIndex + ckeyPattern.length, ckeyIndex + ckeyPattern.length + 32);\n\n if (Array.from(recordDescId).every((b, i) => b === descriptorId[i])) {\n let keyPos = ckeyIndex + ckeyPattern.length + 32;\n const pubkeyLen = data[keyPos];\n keyPos++;\n const pubkey = data.slice(keyPos, keyPos + pubkeyLen);\n\n for (let searchPos = keyPos + pubkeyLen;\n searchPos < Math.min(keyPos + pubkeyLen + 100, data.length - 50);\n searchPos++) {\n const valueLen = data[searchPos];\n if (valueLen >= 32 && valueLen <= 64) {\n const encryptedKey = data.slice(searchPos + 1, searchPos + 1 + valueLen);\n return { pubkey, encryptedKey };\n }\n }\n }\n\n ckeyIndex = findPattern(data, ckeyPattern, ckeyIndex + 1);\n }\n\n return null;\n}\n\n// =============================================================================\n// Decryption Functions\n// =============================================================================\n\n/**\n * Decrypt master key from CMasterKey structure\n */\nexport async function decryptCMasterKey(\n cmk: CMasterKeyData,\n password: string,\n onProgress?: DecryptionProgressCallback\n): Promise<string> {\n const { encryptedKey, salt, iterations } = cmk;\n\n const passwordHex = bytesToHex(new TextEncoder().encode(password));\n const saltHex = bytesToHex(salt);\n const inputHex = passwordHex + saltHex;\n\n let hash = CryptoJS.SHA512(CryptoJS.enc.Hex.parse(inputHex));\n\n const BATCH_SIZE = 1000;\n for (let i = 0; i < iterations - 1; i++) {\n hash = CryptoJS.SHA512(hash);\n if (onProgress && i % BATCH_SIZE === 0) {\n await onProgress(i, iterations);\n }\n }\n\n const derivedKey = CryptoJS.lib.WordArray.create(hash.words.slice(0, 8));\n const derivedIv = CryptoJS.lib.WordArray.create(hash.words.slice(8, 12));\n\n const encryptedWords = uint8ArrayToWordArray(encryptedKey);\n\n const decrypted = CryptoJS.AES.decrypt(\n { ciphertext: encryptedWords } as CryptoJS.lib.CipherParams,\n derivedKey,\n { iv: derivedIv, padding: CryptoJS.pad.Pkcs7, mode: CryptoJS.mode.CBC }\n );\n\n const result = CryptoJS.enc.Hex.stringify(decrypted);\n\n if (!result || result.length !== 64) {\n throw new Error('Master key decryption failed - incorrect password');\n }\n\n return result;\n}\n\n/**\n * Decrypt private key using decrypted master key\n */\nexport function decryptPrivateKey(\n encryptedKey: Uint8Array,\n pubkey: Uint8Array,\n masterKeyHex: string\n): string {\n const pubkeyWords = uint8ArrayToWordArray(pubkey);\n const pubkeyHashWords = CryptoJS.SHA256(CryptoJS.SHA256(pubkeyWords));\n const ivWords = CryptoJS.lib.WordArray.create(pubkeyHashWords.words.slice(0, 4));\n\n const masterKeyWords = CryptoJS.enc.Hex.parse(masterKeyHex);\n const encryptedWords = uint8ArrayToWordArray(encryptedKey);\n\n const decrypted = CryptoJS.AES.decrypt(\n { ciphertext: encryptedWords } as CryptoJS.lib.CipherParams,\n masterKeyWords,\n { iv: ivWords, padding: CryptoJS.pad.Pkcs7, mode: CryptoJS.mode.CBC }\n );\n\n return CryptoJS.enc.Hex.stringify(decrypted);\n}\n\n// =============================================================================\n// Main Parse Function\n// =============================================================================\n\n/**\n * Parse wallet.dat file\n * For encrypted wallets, returns info for decryption\n */\nexport function parseWalletDat(data: Uint8Array): LegacyFileParseResult {\n if (!isSQLiteDatabase(data)) {\n return {\n success: false,\n error: 'Invalid wallet.dat file - not an SQLite database',\n };\n }\n\n const isEncrypted = isWalletDatEncrypted(data);\n const cmasterKeys = isEncrypted ? findAllCMasterKeys(data) : [];\n const descriptorKeys = isEncrypted ? [] : extractDescriptorKeys(data);\n const legacyKeys = isEncrypted ? [] : extractLegacyKeys(data);\n\n // descriptorId is used in parseAndDecryptWalletDat for encrypted wallets\n const { descriptorId: _descriptorId, xpubString, descriptorPath } = findWpkhDescriptor(data);\n void _descriptorId; // Suppress unused warning\n\n let chainCode: string | null = null;\n if (xpubString) {\n try {\n chainCode = extractChainCodeFromXpub(xpubString);\n } catch {\n chainCode = findMasterChainCode(data);\n }\n } else {\n chainCode = findMasterChainCode(data);\n }\n\n // For unencrypted wallets\n if (!isEncrypted) {\n let masterKey: string | null = null;\n\n if (descriptorKeys.length > 0) {\n masterKey = descriptorKeys[0];\n } else if (legacyKeys.length > 0) {\n masterKey = legacyKeys[0];\n }\n\n if (masterKey) {\n const parsedData: LegacyFileParsedData = {\n masterKey,\n chainCode: chainCode ?? undefined,\n descriptorPath: descriptorPath ?? \"84'/1'/0'\",\n derivationMode: chainCode ? 'bip32' : 'wif_hmac',\n };\n\n return {\n success: true,\n data: parsedData,\n };\n }\n\n return {\n success: false,\n error: 'No valid private keys found in wallet.dat file',\n };\n }\n\n // For encrypted wallets\n if (cmasterKeys.length === 0) {\n return {\n success: false,\n error: 'Encrypted wallet but no CMasterKey structures found',\n };\n }\n\n // Return encryption info for decryption\n const firstCmk = cmasterKeys[0];\n return {\n success: false,\n needsPassword: true,\n encryptionInfo: {\n iterations: firstCmk.iterations,\n salt: firstCmk.salt,\n encryptedKey: firstCmk.encryptedKey,\n },\n error: 'Password required for encrypted wallet',\n };\n}\n\n/**\n * Parse and decrypt wallet.dat file\n */\nexport async function parseAndDecryptWalletDat(\n data: Uint8Array,\n password: string,\n onProgress?: DecryptionProgressCallback\n): Promise<LegacyFileParseResult> {\n if (!isSQLiteDatabase(data)) {\n return {\n success: false,\n error: 'Invalid wallet.dat file - not an SQLite database',\n };\n }\n\n const isEncrypted = isWalletDatEncrypted(data);\n\n if (!isEncrypted) {\n // Not encrypted, parse directly\n return parseWalletDat(data);\n }\n\n const cmasterKeys = findAllCMasterKeys(data);\n if (cmasterKeys.length === 0) {\n return {\n success: false,\n error: 'Encrypted wallet but no CMasterKey structures found',\n };\n }\n\n // Try to decrypt each CMasterKey\n let masterKeyHex: string | null = null;\n for (const cmk of cmasterKeys) {\n try {\n masterKeyHex = await decryptCMasterKey(cmk, password, onProgress);\n if (masterKeyHex && masterKeyHex.length === 64) {\n break;\n }\n } catch {\n continue;\n }\n }\n\n if (!masterKeyHex || masterKeyHex.length !== 64) {\n return {\n success: false,\n error: 'Master key decryption failed - incorrect password',\n };\n }\n\n // Find descriptor info\n const { descriptorId, xpubString, descriptorPath } = findWpkhDescriptor(data);\n\n let chainCode: string | null = null;\n if (xpubString) {\n try {\n chainCode = extractChainCodeFromXpub(xpubString);\n } catch {\n chainCode = findMasterChainCode(data);\n }\n } else {\n chainCode = findMasterChainCode(data);\n }\n\n // Find and decrypt BIP32 master private key\n if (!descriptorId) {\n return {\n success: false,\n error: 'Could not find native SegWit receive descriptor',\n };\n }\n\n const encryptedKeyData = findEncryptedKeyForDescriptor(data, descriptorId);\n if (!encryptedKeyData) {\n return {\n success: false,\n error: 'Could not find encrypted private key for descriptor',\n };\n }\n\n const bip32MasterKey = decryptPrivateKey(\n encryptedKeyData.encryptedKey,\n encryptedKeyData.pubkey,\n masterKeyHex\n );\n\n if (!bip32MasterKey || bip32MasterKey.length !== 64) {\n return {\n success: false,\n error: 'Could not decrypt BIP32 master private key',\n };\n }\n\n const parsedData: LegacyFileParsedData = {\n masterKey: bip32MasterKey,\n chainCode: chainCode ?? undefined,\n descriptorPath: descriptorPath ?? \"84'/1'/0'\",\n derivationMode: 'bip32',\n };\n\n return {\n success: true,\n data: parsedData,\n };\n}\n","/**\n * Sphere - Main SDK Entry Point\n *\n * Handles wallet existence checking, creation, and loading.\n *\n * @example\n * ```ts\n * import { Sphere } from '@unicitylabs/sphere-sdk';\n * import { createLocalStorageProvider, createNostrTransportProvider, createUnicityAggregatorProvider } from '@unicitylabs/sphere-sdk/impl/browser';\n *\n * const storage = createLocalStorageProvider();\n * const transport = createNostrTransportProvider();\n * const oracle = createUnicityAggregatorProvider({ url: '/rpc' });\n *\n * // Option 1: Unified init (recommended)\n * const { sphere, created, generatedMnemonic } = await Sphere.init({\n * storage,\n * transport,\n * oracle,\n * mnemonic: 'your twelve words...', // optional - will load if wallet exists\n * autoGenerate: true, // generate new mnemonic if needed\n * });\n *\n * if (created && generatedMnemonic) {\n * console.log('Save this mnemonic:', generatedMnemonic);\n * }\n *\n * // Option 2: Manual create/load\n * if (await Sphere.exists(storage)) {\n * const sphere = await Sphere.load({ storage, transport, oracle });\n * } else {\n * const sphere = await Sphere.create({ mnemonic, storage, transport, oracle });\n * }\n *\n * // Use the wallet\n * await sphere.payments.send({ coinId: 'ALPHA', amount: '1000', recipient: '@alice' });\n * ```\n */\n\nimport type {\n Identity,\n FullIdentity,\n SphereEventType,\n SphereEventMap,\n SphereEventHandler,\n DerivationMode,\n WalletSource,\n WalletInfo,\n WalletJSON,\n WalletJSONExportOptions,\n} from '../types';\nimport type { StorageProvider, TokenStorageProvider, TxfStorageDataBase } from '../storage';\nimport type { TransportProvider } from '../transport';\nimport type { OracleProvider } from '../oracle';\nimport { PaymentsModule, createPaymentsModule } from '../modules/payments';\nimport { CommunicationsModule, createCommunicationsModule } from '../modules/communications';\nimport { STORAGE_KEYS, DEFAULT_DERIVATION_PATH, DEFAULT_BASE_PATH, LIMITS, DEFAULT_ENCRYPTION_KEY, type NetworkType } from '../constants';\nimport {\n generateMnemonic as generateBip39Mnemonic,\n validateMnemonic as validateBip39Mnemonic,\n identityFromMnemonicSync,\n deriveKeyAtPath,\n deriveAddressInfo,\n getPublicKey,\n hash160,\n sha256,\n type MasterKey,\n type AddressInfo,\n} from './crypto';\nimport { encryptSimple, decryptSimple } from './encryption';\nimport {\n parseWalletText,\n parseAndDecryptWalletText,\n isWalletTextFormat,\n isTextWalletEncrypted,\n serializeWalletToText,\n serializeEncryptedWalletToText,\n encryptForTextFormat,\n} from '../serialization/wallet-text';\nimport {\n parseWalletDat,\n parseAndDecryptWalletDat,\n isSQLiteDatabase,\n isWalletDatEncrypted,\n} from '../serialization/wallet-dat';\nimport { SigningService } from '@unicitylabs/state-transition-sdk/lib/sign/SigningService';\nimport { TokenType } from '@unicitylabs/state-transition-sdk/lib/token/TokenType';\nimport { HashAlgorithm } from '@unicitylabs/state-transition-sdk/lib/hash/HashAlgorithm';\nimport { UnmaskedPredicateReference } from '@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicateReference';\nimport type {\n LegacyFileType,\n DecryptionProgressCallback,\n} from '../serialization/types';\n\n// =============================================================================\n// Options Types\n// =============================================================================\n\n/** Options for creating a new wallet */\nexport interface SphereCreateOptions {\n /** BIP39 mnemonic (12 or 24 words) */\n mnemonic: string;\n /** Custom derivation path (default: m/44'/0'/0') */\n derivationPath?: string;\n /** Optional nametag to register for this wallet (e.g., 'alice' for @alice). Token is auto-minted. */\n nametag?: string;\n /** Storage provider instance */\n storage: StorageProvider;\n /** Optional token storage provider (for IPFS sync) */\n tokenStorage?: TokenStorageProvider<TxfStorageDataBase>;\n /** Transport provider instance */\n transport: TransportProvider;\n /** Oracle provider instance */\n oracle: OracleProvider;\n /** L1 (ALPHA blockchain) configuration */\n l1?: L1Config;\n /**\n * Network type (mainnet, testnet, dev) - informational only.\n * Actual network configuration comes from provider URLs.\n * Use createBrowserProviders({ network: 'testnet' }) to set up testnet providers.\n */\n network?: NetworkType;\n}\n\n/** Options for loading existing wallet */\nexport interface SphereLoadOptions {\n /** Storage provider instance */\n storage: StorageProvider;\n /** Optional token storage provider (for IPFS sync) */\n tokenStorage?: TokenStorageProvider<TxfStorageDataBase>;\n /** Transport provider instance */\n transport: TransportProvider;\n /** Oracle provider instance */\n oracle: OracleProvider;\n /** L1 (ALPHA blockchain) configuration */\n l1?: L1Config;\n /**\n * Network type (mainnet, testnet, dev) - informational only.\n * Actual network configuration comes from provider URLs.\n * Use createBrowserProviders({ network: 'testnet' }) to set up testnet providers.\n */\n network?: NetworkType;\n}\n\n/** Options for importing a wallet */\nexport interface SphereImportOptions {\n /** BIP39 mnemonic to import */\n mnemonic?: string;\n /** Or master private key (hex) */\n masterKey?: string;\n /** Chain code for BIP32 (optional) */\n chainCode?: string;\n /** Custom derivation path */\n derivationPath?: string;\n /** Base path for BIP32 derivation (e.g., \"m/84'/1'/0'\" from wallet.dat) */\n basePath?: string;\n /** Derivation mode: bip32, wif_hmac, legacy_hmac */\n derivationMode?: DerivationMode;\n /** Optional nametag to register for this wallet (e.g., 'alice' for @alice). Token is auto-minted. */\n nametag?: string;\n /** Storage provider instance */\n storage: StorageProvider;\n /** Optional token storage provider */\n tokenStorage?: TokenStorageProvider<TxfStorageDataBase>;\n /** Transport provider instance */\n transport: TransportProvider;\n /** Oracle provider instance */\n oracle: OracleProvider;\n /** L1 (ALPHA blockchain) configuration */\n l1?: L1Config;\n}\n\n/** L1 (ALPHA blockchain) configuration */\nexport interface L1Config {\n /** Fulcrum WebSocket URL (default: wss://fulcrum.alpha.unicity.network:50004) */\n electrumUrl?: string;\n /** Default fee rate in sat/byte (default: 10) */\n defaultFeeRate?: number;\n /** Enable vesting classification (default: true) */\n enableVesting?: boolean;\n}\n\n/** Options for unified init (auto-create or load) */\nexport interface SphereInitOptions {\n /** Storage provider instance */\n storage: StorageProvider;\n /** Transport provider instance */\n transport: TransportProvider;\n /** Oracle provider instance */\n oracle: OracleProvider;\n /** Optional token storage provider (for IPFS sync) */\n tokenStorage?: TokenStorageProvider<TxfStorageDataBase>;\n /** BIP39 mnemonic - if wallet doesn't exist, use this to create */\n mnemonic?: string;\n /** Auto-generate mnemonic if wallet doesn't exist and no mnemonic provided */\n autoGenerate?: boolean;\n /** Custom derivation path (default: m/44'/0'/0') */\n derivationPath?: string;\n /** Optional nametag to register (only on create). Token is auto-minted. */\n nametag?: string;\n /** L1 (ALPHA blockchain) configuration */\n l1?: L1Config;\n /**\n * Network type (mainnet, testnet, dev) - informational only.\n * Actual network configuration comes from provider URLs.\n * Use createBrowserProviders({ network: 'testnet' }) to set up testnet providers.\n */\n network?: NetworkType;\n}\n\n/** Result of init operation */\nexport interface SphereInitResult {\n /** The initialized Sphere instance */\n sphere: Sphere;\n /** Whether wallet was newly created */\n created: boolean;\n /** Generated mnemonic (only if autoGenerate was used) */\n generatedMnemonic?: string;\n}\n\n// =============================================================================\n// L3 Predicate Address Derivation\n// =============================================================================\n\n/** Token type for Unicity network (used for L3 predicate address derivation) */\nconst UNICITY_TOKEN_TYPE_HEX = 'f8aa13834268d29355ff12183066f0cb902003629bbc5eb9ef0efbe397867509';\n\n/**\n * Derive L3 predicate address (DIRECT://...) from private key\n * Uses UnmaskedPredicateReference for stable wallet address\n */\nasync function deriveL3PredicateAddress(privateKey: string): Promise<string> {\n const secret = Buffer.from(privateKey, 'hex');\n const signingService = await SigningService.createFromSecret(secret);\n\n const tokenTypeBytes = Buffer.from(UNICITY_TOKEN_TYPE_HEX, 'hex');\n const tokenType = new TokenType(tokenTypeBytes);\n\n const predicateRef = UnmaskedPredicateReference.create(\n tokenType,\n signingService.algorithm,\n signingService.publicKey,\n HashAlgorithm.SHA256\n );\n\n return (await (await predicateRef).toAddress()).toString();\n}\n\n// =============================================================================\n// Mutable Identity (internal use only)\n// =============================================================================\n\n/** Mutable version of FullIdentity for internal state management */\ntype MutableFullIdentity = {\n -readonly [K in keyof FullIdentity]: FullIdentity[K];\n};\n\n// =============================================================================\n// Sphere Class\n// =============================================================================\n\nexport class Sphere {\n // Singleton\n private static instance: Sphere | null = null;\n\n // State\n private _initialized = false;\n private _identity: MutableFullIdentity | null = null;\n private _masterKey: MasterKey | null = null;\n private _mnemonic: string | null = null;\n private _source: WalletSource = 'unknown';\n private _derivationMode: DerivationMode = 'bip32';\n private _basePath: string = DEFAULT_BASE_PATH;\n private _currentAddressIndex: number = 0;\n private _addressNametags: Map<number, string> = new Map();\n\n // Providers\n private _storage: StorageProvider;\n private _tokenStorageProviders: Map<string, TokenStorageProvider<TxfStorageDataBase>> = new Map();\n private _transport: TransportProvider;\n private _oracle: OracleProvider;\n\n // Modules\n private _payments: PaymentsModule;\n private _communications: CommunicationsModule;\n\n // Events\n private eventHandlers: Map<SphereEventType, Set<SphereEventHandler<SphereEventType>>> = new Map();\n\n // ===========================================================================\n // Constructor (private)\n // ===========================================================================\n\n private constructor(\n storage: StorageProvider,\n transport: TransportProvider,\n oracle: OracleProvider,\n tokenStorage?: TokenStorageProvider<TxfStorageDataBase>,\n l1Config?: L1Config\n ) {\n this._storage = storage;\n this._transport = transport;\n this._oracle = oracle;\n\n // Initialize token storage providers map\n if (tokenStorage) {\n this._tokenStorageProviders.set(tokenStorage.id, tokenStorage);\n }\n\n this._payments = createPaymentsModule({ l1: l1Config });\n this._communications = createCommunicationsModule();\n }\n\n // ===========================================================================\n // Static Methods - Wallet Management\n // ===========================================================================\n\n /**\n * Check if wallet exists in storage\n */\n static async exists(storage: StorageProvider): Promise<boolean> {\n try {\n const exists = await storage.get(STORAGE_KEYS.WALLET_EXISTS);\n if (exists === 'true') {\n // Double check - verify we have actual data\n const mnemonic = await storage.get(STORAGE_KEYS.MNEMONIC);\n const masterKey = await storage.get(STORAGE_KEYS.MASTER_KEY);\n return !!(mnemonic || masterKey);\n }\n return false;\n } catch {\n return false;\n }\n }\n\n /**\n * Initialize wallet - auto-loads existing or creates new\n *\n * @example\n * ```ts\n * // Load existing or create with provided mnemonic\n * const { sphere, created } = await Sphere.init({\n * storage,\n * transport,\n * oracle,\n * mnemonic: 'your twelve words...',\n * });\n *\n * // Load existing or auto-generate new mnemonic\n * const { sphere, created, generatedMnemonic } = await Sphere.init({\n * storage,\n * transport,\n * oracle,\n * autoGenerate: true,\n * });\n * if (generatedMnemonic) {\n * console.log('Save this mnemonic:', generatedMnemonic);\n * }\n * ```\n */\n static async init(options: SphereInitOptions): Promise<SphereInitResult> {\n const walletExists = await Sphere.exists(options.storage);\n\n if (walletExists) {\n // Load existing wallet\n const sphere = await Sphere.load({\n storage: options.storage,\n transport: options.transport,\n oracle: options.oracle,\n tokenStorage: options.tokenStorage,\n l1: options.l1,\n });\n return { sphere, created: false };\n }\n\n // Need to create new wallet\n let mnemonic = options.mnemonic;\n let generatedMnemonic: string | undefined;\n\n if (!mnemonic) {\n if (options.autoGenerate) {\n // Auto-generate mnemonic\n mnemonic = Sphere.generateMnemonic();\n generatedMnemonic = mnemonic;\n } else {\n throw new Error(\n 'No wallet exists and no mnemonic provided. ' +\n 'Provide a mnemonic or set autoGenerate: true.'\n );\n }\n }\n\n const sphere = await Sphere.create({\n mnemonic,\n storage: options.storage,\n transport: options.transport,\n oracle: options.oracle,\n tokenStorage: options.tokenStorage,\n derivationPath: options.derivationPath,\n nametag: options.nametag,\n l1: options.l1,\n });\n\n return { sphere, created: true, generatedMnemonic };\n }\n\n /**\n * Create new wallet with mnemonic\n */\n static async create(options: SphereCreateOptions): Promise<Sphere> {\n // Validate mnemonic\n if (!options.mnemonic || !Sphere.validateMnemonic(options.mnemonic)) {\n throw new Error('Invalid mnemonic');\n }\n\n // Check if wallet already exists\n if (await Sphere.exists(options.storage)) {\n throw new Error('Wallet already exists. Use Sphere.load() or Sphere.clear() first.');\n }\n\n const sphere = new Sphere(\n options.storage,\n options.transport,\n options.oracle,\n options.tokenStorage,\n options.l1\n );\n\n // Store encrypted mnemonic\n await sphere.storeMnemonic(options.mnemonic, options.derivationPath);\n\n // Initialize identity from mnemonic\n await sphere.initializeIdentityFromMnemonic(options.mnemonic, options.derivationPath);\n\n // Initialize everything\n await sphere.initializeProviders();\n await sphere.initializeModules();\n\n // Mark wallet as created only after successful initialization\n // This prevents \"Wallet already exists\" errors if init fails partway through\n await sphere.finalizeWalletCreation();\n\n sphere._initialized = true;\n Sphere.instance = sphere;\n\n // Register nametag if provided (includes on-chain token minting)\n if (options.nametag) {\n await sphere.registerNametag(options.nametag);\n }\n\n return sphere;\n }\n\n /**\n * Load existing wallet from storage\n */\n static async load(options: SphereLoadOptions): Promise<Sphere> {\n // Check if wallet exists\n if (!(await Sphere.exists(options.storage))) {\n throw new Error('No wallet found. Use Sphere.create() to create a new wallet.');\n }\n\n const sphere = new Sphere(\n options.storage,\n options.transport,\n options.oracle,\n options.tokenStorage,\n options.l1\n );\n\n // Load identity from storage\n await sphere.loadIdentityFromStorage();\n\n // Initialize everything\n await sphere.initializeProviders();\n await sphere.initializeModules();\n\n // Sync nametag with Nostr (re-register if missing)\n await sphere.syncNametagWithNostr();\n\n // Mint nametag token if nametag exists but token is missing\n // Required for receiving tokens via @nametag (PROXY address finalization)\n if (sphere._identity?.nametag && !sphere._payments.hasNametag()) {\n console.log(`[Sphere] Minting missing nametag token for @${sphere._identity.nametag}...`);\n const result = await sphere.mintNametag(sphere._identity.nametag);\n if (!result.success) {\n console.warn(`[Sphere] Failed to mint nametag token: ${result.error}`);\n } else {\n console.log(`[Sphere] Nametag token minted successfully`);\n }\n }\n\n sphere._initialized = true;\n Sphere.instance = sphere;\n\n return sphere;\n }\n\n /**\n * Import wallet from mnemonic or master key\n */\n static async import(options: SphereImportOptions): Promise<Sphere> {\n if (!options.mnemonic && !options.masterKey) {\n throw new Error('Either mnemonic or masterKey is required');\n }\n\n // Clear existing wallet if any\n await Sphere.clear(options.storage);\n\n const sphere = new Sphere(\n options.storage,\n options.transport,\n options.oracle,\n options.tokenStorage,\n options.l1\n );\n\n if (options.mnemonic) {\n // Validate and store mnemonic\n if (!Sphere.validateMnemonic(options.mnemonic)) {\n throw new Error('Invalid mnemonic');\n }\n await sphere.storeMnemonic(options.mnemonic, options.derivationPath, options.basePath);\n await sphere.initializeIdentityFromMnemonic(options.mnemonic, options.derivationPath);\n } else if (options.masterKey) {\n // Store master key directly\n await sphere.storeMasterKey(\n options.masterKey,\n options.chainCode,\n options.derivationPath,\n options.basePath,\n options.derivationMode\n );\n await sphere.initializeIdentityFromMasterKey(\n options.masterKey,\n options.chainCode,\n options.derivationPath\n );\n }\n\n // Initialize everything\n await sphere.initializeProviders();\n await sphere.initializeModules();\n\n // Mark wallet as created only after successful initialization\n await sphere.finalizeWalletCreation();\n\n sphere._initialized = true;\n Sphere.instance = sphere;\n\n // Register nametag if provided\n if (options.nametag) {\n await sphere.registerNametag(options.nametag);\n }\n\n return sphere;\n }\n\n /**\n * Clear wallet data from storage\n */\n static async clear(storage: StorageProvider): Promise<void> {\n // Clear all wallet data\n await storage.remove(STORAGE_KEYS.MNEMONIC);\n await storage.remove(STORAGE_KEYS.MASTER_KEY);\n await storage.remove(STORAGE_KEYS.CHAIN_CODE);\n await storage.remove(STORAGE_KEYS.DERIVATION_PATH);\n await storage.remove(STORAGE_KEYS.BASE_PATH);\n await storage.remove(STORAGE_KEYS.DERIVATION_MODE);\n await storage.remove(STORAGE_KEYS.WALLET_SOURCE);\n await storage.remove(STORAGE_KEYS.WALLET_EXISTS);\n await storage.remove(STORAGE_KEYS.NAMETAG);\n await storage.remove(STORAGE_KEYS.TOKENS);\n await storage.remove(STORAGE_KEYS.PENDING_TRANSFERS);\n await storage.remove(STORAGE_KEYS.OUTBOX);\n\n if (Sphere.instance) {\n await Sphere.instance.destroy();\n }\n }\n\n /**\n * Get current instance\n */\n static getInstance(): Sphere | null {\n return Sphere.instance;\n }\n\n /**\n * Check if initialized\n */\n static isInitialized(): boolean {\n return Sphere.instance?._initialized ?? false;\n }\n\n /**\n * Validate mnemonic using BIP39\n */\n static validateMnemonic(mnemonic: string): boolean {\n return validateBip39Mnemonic(mnemonic);\n }\n\n /**\n * Generate new BIP39 mnemonic\n * @param strength - 128 for 12 words, 256 for 24 words\n */\n static generateMnemonic(strength: 128 | 256 = 128): string {\n return generateBip39Mnemonic(strength);\n }\n\n // ===========================================================================\n // Public Properties - Modules\n // ===========================================================================\n\n /** Payments module (L3 + L1) */\n get payments(): PaymentsModule {\n this.ensureReady();\n return this._payments;\n }\n\n /** Communications module */\n get communications(): CommunicationsModule {\n this.ensureReady();\n return this._communications;\n }\n\n // ===========================================================================\n // Public Properties - State\n // ===========================================================================\n\n /** Current identity (public info only) */\n get identity(): Identity | null {\n if (!this._identity) return null;\n return {\n publicKey: this._identity.publicKey,\n address: this._identity.address,\n predicateAddress: this._identity.predicateAddress,\n ipnsName: this._identity.ipnsName,\n nametag: this._identity.nametag,\n };\n }\n\n /** Is ready */\n get isReady(): boolean {\n return this._initialized;\n }\n\n // ===========================================================================\n // Public Methods - Providers Access\n // ===========================================================================\n\n getStorage(): StorageProvider {\n return this._storage;\n }\n\n /**\n * Get first token storage provider (for backward compatibility)\n * @deprecated Use getTokenStorageProviders() for multiple providers\n */\n getTokenStorage(): TokenStorageProvider<TxfStorageDataBase> | undefined {\n const providers = Array.from(this._tokenStorageProviders.values());\n return providers.length > 0 ? providers[0] : undefined;\n }\n\n /**\n * Get all token storage providers\n */\n getTokenStorageProviders(): Map<string, TokenStorageProvider<TxfStorageDataBase>> {\n return new Map(this._tokenStorageProviders);\n }\n\n /**\n * Add a token storage provider dynamically (e.g., from UI)\n * Provider will be initialized and connected automatically\n */\n async addTokenStorageProvider(provider: TokenStorageProvider<TxfStorageDataBase>): Promise<void> {\n if (this._tokenStorageProviders.has(provider.id)) {\n throw new Error(`Token storage provider '${provider.id}' already exists`);\n }\n\n // Set identity if wallet is initialized\n if (this._identity) {\n provider.setIdentity(this._identity);\n await provider.initialize();\n }\n\n this._tokenStorageProviders.set(provider.id, provider);\n\n // Update payments module with new providers\n if (this._initialized) {\n this._payments.updateTokenStorageProviders(this._tokenStorageProviders);\n }\n }\n\n /**\n * Remove a token storage provider dynamically\n */\n async removeTokenStorageProvider(providerId: string): Promise<boolean> {\n const provider = this._tokenStorageProviders.get(providerId);\n if (!provider) {\n return false;\n }\n\n // Shutdown provider gracefully\n await provider.shutdown();\n\n this._tokenStorageProviders.delete(providerId);\n\n // Update payments module\n if (this._initialized) {\n this._payments.updateTokenStorageProviders(this._tokenStorageProviders);\n }\n\n return true;\n }\n\n /**\n * Check if a token storage provider is registered\n */\n hasTokenStorageProvider(providerId: string): boolean {\n return this._tokenStorageProviders.has(providerId);\n }\n\n getTransport(): TransportProvider {\n return this._transport;\n }\n\n getAggregator(): OracleProvider {\n return this._oracle;\n }\n\n /**\n * Check if wallet has BIP32 master key for HD derivation\n */\n hasMasterKey(): boolean {\n return this._masterKey !== null;\n }\n\n // ===========================================================================\n // Public Methods - Multi-Address Derivation\n // ===========================================================================\n\n /**\n * Get the base derivation path used by this wallet (e.g., \"m/44'/0'/0'\")\n */\n getBasePath(): string {\n return this._basePath;\n }\n\n /**\n * Get the default address path (first external address)\n * Returns path like \"m/44'/0'/0'/0/0\"\n */\n getDefaultAddressPath(): string {\n return `${this._basePath}/0/0`;\n }\n\n /**\n * Get current derivation mode\n */\n getDerivationMode(): DerivationMode {\n return this._derivationMode;\n }\n\n /**\n * Get the mnemonic phrase (for backup purposes)\n * Returns null if wallet was imported from file (masterKey only)\n */\n getMnemonic(): string | null {\n return this._mnemonic;\n }\n\n /**\n * Get wallet info for backup/export purposes\n */\n getWalletInfo(): WalletInfo {\n let address0: string | null = null;\n try {\n if (this._masterKey) {\n address0 = this.deriveAddress(0).address;\n } else if (this._identity) {\n address0 = this._identity.address;\n }\n } catch {\n // Ignore errors\n }\n\n return {\n source: this._source,\n hasMnemonic: this._mnemonic !== null,\n hasChainCode: this._masterKey?.chainCode !== undefined,\n derivationMode: this._derivationMode,\n basePath: this._basePath,\n address0,\n };\n }\n\n /**\n * Export wallet to JSON format for backup\n *\n * @example\n * ```ts\n * // Export with mnemonic (if available)\n * const json = sphere.exportToJSON();\n *\n * // Export with encryption\n * const encrypted = sphere.exportToJSON({ password: 'secret' });\n *\n * // Export multiple addresses\n * const multi = sphere.exportToJSON({ addressCount: 5 });\n * ```\n */\n exportToJSON(options: WalletJSONExportOptions = {}): WalletJSON {\n this.ensureReady();\n\n if (!this._masterKey && !this._identity) {\n throw new Error('Wallet not initialized');\n }\n\n // Build addresses array\n const addressCount = options.addressCount || 1;\n const addresses: Array<{\n address: string;\n publicKey: string;\n path: string;\n index: number;\n }> = [];\n\n for (let i = 0; i < addressCount; i++) {\n try {\n const addr = this.deriveAddress(i, false);\n addresses.push({\n address: addr.address,\n publicKey: addr.publicKey,\n path: addr.path,\n index: addr.index,\n });\n } catch {\n // Stop if we can't derive more addresses (e.g., no masterKey)\n if (i === 0 && this._identity) {\n addresses.push({\n address: this._identity.address,\n publicKey: this._identity.publicKey,\n path: this.getDefaultAddressPath(),\n index: 0,\n });\n }\n break;\n }\n }\n\n // Build wallet data\n let masterPrivateKey: string | undefined;\n let chainCode: string | undefined;\n\n if (this._masterKey) {\n masterPrivateKey = this._masterKey.privateKey;\n chainCode = this._masterKey.chainCode;\n }\n\n // Prepare mnemonic (optionally encrypt)\n let mnemonic: string | undefined;\n let encrypted = false;\n\n if (this._mnemonic && options.includeMnemonic !== false) {\n if (options.password) {\n mnemonic = encryptSimple(this._mnemonic, options.password);\n encrypted = true;\n } else {\n mnemonic = this._mnemonic;\n }\n }\n\n // Encrypt master key if password provided\n if (masterPrivateKey && options.password) {\n masterPrivateKey = encryptSimple(masterPrivateKey, options.password);\n encrypted = true;\n }\n\n return {\n version: '1.0',\n type: 'sphere-wallet',\n createdAt: new Date().toISOString(),\n wallet: {\n masterPrivateKey,\n chainCode,\n addresses,\n isBIP32: this._derivationMode === 'bip32',\n descriptorPath: this._basePath.replace(/^m\\//, ''),\n },\n mnemonic,\n encrypted,\n source: this._source,\n derivationMode: this._derivationMode,\n };\n }\n\n /**\n * Export wallet to text format for backup\n *\n * @example\n * ```ts\n * // Export unencrypted\n * const text = sphere.exportToTxt();\n *\n * // Export with encryption\n * const encrypted = sphere.exportToTxt({ password: 'secret' });\n *\n * // Export multiple addresses\n * const multi = sphere.exportToTxt({ addressCount: 5 });\n * ```\n */\n exportToTxt(options: { password?: string; addressCount?: number } = {}): string {\n this.ensureReady();\n\n if (!this._masterKey && !this._identity) {\n throw new Error('Wallet not initialized');\n }\n\n // Build addresses array\n const addressCount = options.addressCount || 1;\n const addresses: Array<{\n index: number;\n address: string;\n path: string;\n isChange: boolean;\n }> = [];\n\n for (let i = 0; i < addressCount; i++) {\n try {\n const addr = this.deriveAddress(i, false);\n addresses.push({\n address: addr.address,\n path: addr.path,\n index: addr.index,\n isChange: false,\n });\n } catch {\n // Stop if we can't derive more addresses\n if (i === 0 && this._identity) {\n addresses.push({\n address: this._identity.address,\n path: this.getDefaultAddressPath(),\n index: 0,\n isChange: false,\n });\n }\n break;\n }\n }\n\n const masterPrivateKey = this._masterKey?.privateKey || '';\n const chainCode = this._masterKey?.chainCode;\n const isBIP32 = this._derivationMode === 'bip32';\n const descriptorPath = this._basePath.replace(/^m\\//, '');\n\n // If password provided, encrypt\n if (options.password) {\n const encryptedMasterKey = encryptForTextFormat(masterPrivateKey, options.password);\n return serializeEncryptedWalletToText({\n encryptedMasterKey,\n chainCode,\n descriptorPath,\n isBIP32,\n addresses,\n });\n }\n\n // Unencrypted export\n return serializeWalletToText({\n masterPrivateKey,\n chainCode,\n descriptorPath,\n isBIP32,\n addresses,\n });\n }\n\n /**\n * Import wallet from JSON backup\n *\n * @returns Object with success status and optionally recovered mnemonic\n *\n * @example\n * ```ts\n * const json = '{\"version\":\"1.0\",...}';\n * const { success, mnemonic } = await Sphere.importFromJSON({\n * jsonContent: json,\n * password: 'secret', // if encrypted\n * storage, transport, oracle,\n * });\n * ```\n */\n static async importFromJSON(options: {\n jsonContent: string;\n password?: string;\n storage: StorageProvider;\n transport: TransportProvider;\n oracle: OracleProvider;\n tokenStorage?: TokenStorageProvider<TxfStorageDataBase>;\n }): Promise<{ success: boolean; mnemonic?: string; error?: string }> {\n try {\n const data = JSON.parse(options.jsonContent) as WalletJSON;\n\n if (data.version !== '1.0' || data.type !== 'sphere-wallet') {\n return { success: false, error: 'Invalid wallet format' };\n }\n\n // Decrypt if needed\n let mnemonic = data.mnemonic;\n let masterKey = data.wallet.masterPrivateKey;\n\n if (data.encrypted && options.password) {\n if (mnemonic) {\n const decrypted = decryptSimple(mnemonic, options.password);\n if (!decrypted) {\n return { success: false, error: 'Failed to decrypt mnemonic - wrong password?' };\n }\n mnemonic = decrypted;\n }\n if (masterKey) {\n const decrypted = decryptSimple(masterKey, options.password);\n if (!decrypted) {\n return { success: false, error: 'Failed to decrypt master key - wrong password?' };\n }\n masterKey = decrypted;\n }\n } else if (data.encrypted && !options.password) {\n return { success: false, error: 'Password required for encrypted wallet' };\n }\n\n // Determine base path\n const basePath = data.wallet.descriptorPath\n ? `m/${data.wallet.descriptorPath}`\n : DEFAULT_BASE_PATH;\n\n // Import using mnemonic if available (preferred)\n if (mnemonic) {\n await Sphere.import({\n mnemonic,\n basePath,\n storage: options.storage,\n transport: options.transport,\n oracle: options.oracle,\n tokenStorage: options.tokenStorage,\n });\n return { success: true, mnemonic };\n }\n\n // Otherwise import using master key\n if (masterKey) {\n await Sphere.import({\n masterKey,\n chainCode: data.wallet.chainCode,\n basePath,\n derivationMode: data.derivationMode || (data.wallet.isBIP32 ? 'bip32' : 'wif_hmac'),\n storage: options.storage,\n transport: options.transport,\n oracle: options.oracle,\n tokenStorage: options.tokenStorage,\n });\n return { success: true };\n }\n\n return { success: false, error: 'No mnemonic or master key in wallet data' };\n } catch (e) {\n return {\n success: false,\n error: e instanceof Error ? e.message : 'Failed to parse wallet JSON',\n };\n }\n }\n\n /**\n * Import wallet from legacy file (.dat, .txt, or mnemonic text)\n *\n * Supports:\n * - Bitcoin Core wallet.dat files (SQLite format, encrypted or unencrypted)\n * - Text backup files (UNICITY WALLET DETAILS format)\n * - Plain mnemonic text (12 or 24 words)\n *\n * @returns Object with success status, created Sphere instance, and optionally recovered mnemonic\n *\n * @example\n * ```ts\n * // Import from .dat file\n * const fileBuffer = await file.arrayBuffer();\n * const result = await Sphere.importFromLegacyFile({\n * fileContent: new Uint8Array(fileBuffer),\n * fileName: 'wallet.dat',\n * password: 'wallet-password', // if encrypted\n * storage, transport, oracle,\n * });\n *\n * // Import from .txt file\n * const textContent = await file.text();\n * const result = await Sphere.importFromLegacyFile({\n * fileContent: textContent,\n * fileName: 'backup.txt',\n * storage, transport, oracle,\n * });\n * ```\n */\n static async importFromLegacyFile(options: {\n /** File content - Uint8Array for .dat, string for .txt */\n fileContent: string | Uint8Array;\n /** File name (used for type detection) */\n fileName: string;\n /** Password for encrypted files */\n password?: string;\n /** Progress callback for long decryption operations */\n onDecryptProgress?: DecryptionProgressCallback;\n /** Storage provider instance */\n storage: StorageProvider;\n /** Transport provider instance */\n transport: TransportProvider;\n /** Oracle provider instance */\n oracle: OracleProvider;\n /** Optional token storage provider */\n tokenStorage?: TokenStorageProvider<TxfStorageDataBase>;\n /** Optional nametag to register */\n nametag?: string;\n }): Promise<{\n success: boolean;\n sphere?: Sphere;\n mnemonic?: string;\n needsPassword?: boolean;\n error?: string;\n }> {\n const { fileContent, fileName, password, onDecryptProgress } = options;\n\n // Detect file type\n const fileType = Sphere.detectLegacyFileType(fileName, fileContent);\n\n if (fileType === 'unknown') {\n return { success: false, error: 'Unknown file format' };\n }\n\n // Handle mnemonic text\n if (fileType === 'mnemonic') {\n const mnemonic = (fileContent as string).trim().toLowerCase().split(/\\s+/).join(' ');\n if (!Sphere.validateMnemonic(mnemonic)) {\n return { success: false, error: 'Invalid mnemonic phrase' };\n }\n\n const sphere = await Sphere.import({\n mnemonic,\n storage: options.storage,\n transport: options.transport,\n oracle: options.oracle,\n tokenStorage: options.tokenStorage,\n nametag: options.nametag,\n });\n\n return { success: true, sphere, mnemonic };\n }\n\n // Handle .dat file\n if (fileType === 'dat') {\n const data = fileContent instanceof Uint8Array\n ? fileContent\n : new TextEncoder().encode(fileContent);\n\n let parseResult;\n\n if (password) {\n parseResult = await parseAndDecryptWalletDat(data, password, onDecryptProgress);\n } else {\n parseResult = parseWalletDat(data);\n }\n\n if (parseResult.needsPassword && !password) {\n return { success: false, needsPassword: true, error: 'Password required for encrypted wallet' };\n }\n\n if (!parseResult.success || !parseResult.data) {\n return { success: false, error: parseResult.error };\n }\n\n const { masterKey, chainCode, descriptorPath, derivationMode } = parseResult.data;\n\n // Build base path from descriptor path\n const basePath = descriptorPath ? `m/${descriptorPath}` : DEFAULT_BASE_PATH;\n\n const sphere = await Sphere.import({\n masterKey,\n chainCode,\n basePath,\n derivationMode: derivationMode || (chainCode ? 'bip32' : 'wif_hmac'),\n storage: options.storage,\n transport: options.transport,\n oracle: options.oracle,\n tokenStorage: options.tokenStorage,\n nametag: options.nametag,\n });\n\n return { success: true, sphere };\n }\n\n // Handle .txt file\n if (fileType === 'txt') {\n const content = typeof fileContent === 'string'\n ? fileContent\n : new TextDecoder().decode(fileContent);\n\n let parseResult;\n\n if (password) {\n parseResult = parseAndDecryptWalletText(content, password);\n } else if (isTextWalletEncrypted(content)) {\n return { success: false, needsPassword: true, error: 'Password required for encrypted wallet' };\n } else {\n parseResult = parseWalletText(content);\n }\n\n if (parseResult.needsPassword && !password) {\n return { success: false, needsPassword: true, error: 'Password required for encrypted wallet' };\n }\n\n if (!parseResult.success || !parseResult.data) {\n return { success: false, error: parseResult.error };\n }\n\n const { masterKey, chainCode, descriptorPath, derivationMode } = parseResult.data;\n\n const basePath = descriptorPath ? `m/${descriptorPath}` : DEFAULT_BASE_PATH;\n\n const sphere = await Sphere.import({\n masterKey,\n chainCode,\n basePath,\n derivationMode: derivationMode || (chainCode ? 'bip32' : 'wif_hmac'),\n storage: options.storage,\n transport: options.transport,\n oracle: options.oracle,\n tokenStorage: options.tokenStorage,\n nametag: options.nametag,\n });\n\n return { success: true, sphere };\n }\n\n // Handle JSON (redirect to importFromJSON)\n if (fileType === 'json') {\n const content = typeof fileContent === 'string'\n ? fileContent\n : new TextDecoder().decode(fileContent);\n\n const result = await Sphere.importFromJSON({\n jsonContent: content,\n password,\n storage: options.storage,\n transport: options.transport,\n oracle: options.oracle,\n tokenStorage: options.tokenStorage,\n });\n\n if (result.success) {\n const sphere = Sphere.getInstance();\n return { success: true, sphere: sphere!, mnemonic: result.mnemonic };\n }\n\n return result;\n }\n\n return { success: false, error: 'Unsupported file type' };\n }\n\n /**\n * Detect legacy file type from filename and content\n */\n static detectLegacyFileType(fileName: string, content: string | Uint8Array): LegacyFileType {\n // .dat files are binary\n if (fileName.endsWith('.dat')) {\n return 'dat';\n }\n\n // Check content for type detection\n const textContent = typeof content === 'string'\n ? content\n : (content.length < 1000 ? new TextDecoder().decode(content) : '');\n\n // Check for JSON\n if (fileName.endsWith('.json')) {\n return 'json';\n }\n\n try {\n const trimmed = textContent.trim();\n if (trimmed.startsWith('{') || trimmed.startsWith('[')) {\n JSON.parse(trimmed);\n return 'json';\n }\n } catch {\n // Not JSON\n }\n\n // Check for mnemonic (12 or 24 words)\n const words = textContent.trim().split(/\\s+/);\n if (\n (words.length === 12 || words.length === 24) &&\n words.every((w) => /^[a-z]+$/.test(w.toLowerCase()))\n ) {\n return 'mnemonic';\n }\n\n // Check for text wallet format\n if (isWalletTextFormat(textContent)) {\n return 'txt';\n }\n\n // Check for SQLite (binary .dat)\n if (content instanceof Uint8Array && isSQLiteDatabase(content)) {\n return 'dat';\n }\n\n return 'unknown';\n }\n\n /**\n * Check if a legacy file is encrypted\n */\n static isLegacyFileEncrypted(fileName: string, content: string | Uint8Array): boolean {\n const fileType = Sphere.detectLegacyFileType(fileName, content);\n\n if (fileType === 'dat' && content instanceof Uint8Array) {\n return isWalletDatEncrypted(content);\n }\n\n if (fileType === 'txt') {\n const textContent = typeof content === 'string'\n ? content\n : new TextDecoder().decode(content);\n return isTextWalletEncrypted(textContent);\n }\n\n if (fileType === 'json') {\n try {\n const textContent = typeof content === 'string'\n ? content\n : new TextDecoder().decode(content);\n const data = JSON.parse(textContent);\n return !!data.encrypted;\n } catch {\n return false;\n }\n }\n\n return false;\n }\n\n /**\n * Get the current active address index\n *\n * @example\n * ```ts\n * const currentIndex = sphere.getCurrentAddressIndex();\n * console.log(currentIndex); // 0\n *\n * await sphere.switchToAddress(2);\n * console.log(sphere.getCurrentAddressIndex()); // 2\n * ```\n */\n getCurrentAddressIndex(): number {\n return this._currentAddressIndex;\n }\n\n /**\n * Get nametag for a specific address index\n *\n * @param index - Address index (default: current address)\n * @returns Nametag or undefined if not registered\n */\n getNametagForAddress(index?: number): string | undefined {\n const addressIndex = index ?? this._currentAddressIndex;\n return this._addressNametags.get(addressIndex);\n }\n\n /**\n * Get all registered address nametags\n *\n * @returns Map of address index to nametag\n */\n getAllAddressNametags(): Map<number, string> {\n return new Map(this._addressNametags);\n }\n\n /**\n * Switch to a different address by index\n * This changes the active identity to the derived address at the specified index.\n *\n * @param index - Address index to switch to (0, 1, 2, ...)\n *\n * @example\n * ```ts\n * // Switch to second address\n * await sphere.switchToAddress(1);\n * console.log(sphere.identity?.address); // alpha1... (address at index 1)\n *\n * // Register nametag for this address\n * await sphere.registerNametag('bob');\n *\n * // Switch back to first address\n * await sphere.switchToAddress(0);\n * ```\n */\n async switchToAddress(index: number): Promise<void> {\n this.ensureReady();\n\n if (!this._masterKey) {\n throw new Error('HD derivation requires master key with chain code. Cannot switch addresses.');\n }\n\n if (index < 0) {\n throw new Error('Address index must be non-negative');\n }\n\n // Derive the address at the given index\n const addressInfo = this.deriveAddress(index, false);\n\n // Generate IPNS name from public key hash\n const ipnsHash = sha256(addressInfo.publicKey, 'hex').slice(0, 40);\n\n // Derive L3 predicate address (DIRECT://...)\n const predicateAddress = await deriveL3PredicateAddress(addressInfo.privateKey);\n\n // Get nametag for this address (if registered)\n const nametag = this._addressNametags.get(index);\n\n // Update identity\n this._identity = {\n privateKey: addressInfo.privateKey,\n publicKey: addressInfo.publicKey,\n address: addressInfo.address,\n predicateAddress,\n ipnsName: '12D3KooW' + ipnsHash,\n nametag,\n };\n\n // Update current index\n this._currentAddressIndex = index;\n\n // Persist current index\n await this._storage.set(STORAGE_KEYS.CURRENT_ADDRESS_INDEX, index.toString());\n\n // Re-initialize providers with new identity\n this._storage.setIdentity(this._identity);\n this._transport.setIdentity(this._identity);\n\n // Update token storage providers\n for (const provider of this._tokenStorageProviders.values()) {\n provider.setIdentity(this._identity);\n }\n\n // Re-initialize modules with new identity\n await this.reinitializeModulesForNewAddress();\n\n this.emitEvent('identity:changed', {\n address: this._identity.address,\n predicateAddress: this._identity.predicateAddress,\n publicKey: this._identity.publicKey,\n nametag: this._identity.nametag,\n addressIndex: index,\n });\n\n console.log(`[Sphere] Switched to address ${index}:`, this._identity.address);\n }\n\n /**\n * Re-initialize modules after address switch\n */\n private async reinitializeModulesForNewAddress(): Promise<void> {\n const emitEvent = this.emitEvent.bind(this);\n\n this._payments.initialize({\n identity: this._identity!,\n storage: this._storage,\n tokenStorageProviders: this._tokenStorageProviders,\n transport: this._transport,\n oracle: this._oracle,\n emitEvent,\n chainCode: this._masterKey?.chainCode,\n });\n\n this._communications.initialize({\n identity: this._identity!,\n storage: this._storage,\n transport: this._transport,\n emitEvent,\n });\n\n await this._payments.load();\n await this._communications.load();\n }\n\n /**\n * Derive address at a specific index\n *\n * @param index - Address index (0, 1, 2, ...)\n * @param isChange - Whether this is a change address (default: false)\n * @returns Address info with privateKey, publicKey, address, path, index\n *\n * @example\n * ```ts\n * // Derive first receiving address\n * const addr0 = sphere.deriveAddress(0);\n * console.log(addr0.address); // alpha1...\n *\n * // Derive second receiving address\n * const addr1 = sphere.deriveAddress(1);\n *\n * // Derive change address\n * const change = sphere.deriveAddress(0, true);\n * ```\n */\n deriveAddress(index: number, isChange: boolean = false): AddressInfo {\n this.ensureReady();\n\n if (!this._masterKey) {\n throw new Error('HD derivation requires master key with chain code');\n }\n\n const info = deriveAddressInfo(\n this._masterKey,\n this._basePath,\n index,\n isChange\n );\n\n // Convert hash160 to proper address format\n return {\n ...info,\n address: 'alpha1' + info.address.slice(0, 38),\n };\n }\n\n /**\n * Derive address at a full BIP32 path\n *\n * @param path - Full BIP32 path like \"m/44'/0'/0'/0/5\"\n * @returns Address info\n *\n * @example\n * ```ts\n * const addr = sphere.deriveAddressAtPath(\"m/44'/0'/0'/0/5\");\n * ```\n */\n deriveAddressAtPath(path: string): AddressInfo {\n this.ensureReady();\n\n if (!this._masterKey) {\n throw new Error('HD derivation requires master key with chain code');\n }\n\n // Parse path to extract index\n const match = path.match(/\\/(\\d+)$/);\n const index = match ? parseInt(match[1], 10) : 0;\n\n const derived = deriveKeyAtPath(\n this._masterKey.privateKey,\n this._masterKey.chainCode,\n path\n );\n\n const publicKey = getPublicKey(derived.privateKey);\n const addressHash = hash160(publicKey);\n\n return {\n privateKey: derived.privateKey,\n publicKey,\n address: 'alpha1' + addressHash.slice(0, 38),\n path,\n index,\n };\n }\n\n /**\n * Derive multiple addresses starting from index 0\n *\n * @param count - Number of addresses to derive\n * @param includeChange - Include change addresses (default: false)\n * @returns Array of address info\n *\n * @example\n * ```ts\n * // Get first 5 receiving addresses\n * const addresses = sphere.deriveAddresses(5);\n *\n * // Get 5 receiving + 5 change addresses\n * const allAddresses = sphere.deriveAddresses(5, true);\n * ```\n */\n deriveAddresses(count: number, includeChange: boolean = false): AddressInfo[] {\n const addresses: AddressInfo[] = [];\n\n for (let i = 0; i < count; i++) {\n addresses.push(this.deriveAddress(i, false));\n }\n\n if (includeChange) {\n for (let i = 0; i < count; i++) {\n addresses.push(this.deriveAddress(i, true));\n }\n }\n\n return addresses;\n }\n\n // ===========================================================================\n // Public Methods - Status\n // ===========================================================================\n\n getStatus(): {\n storage: { connected: boolean };\n transport: { connected: boolean };\n oracle: { connected: boolean };\n } {\n return {\n storage: { connected: this._storage.isConnected() },\n transport: { connected: this._transport.isConnected() },\n oracle: { connected: this._oracle.isConnected() },\n };\n }\n\n async reconnect(): Promise<void> {\n await this._transport.disconnect();\n await this._transport.connect();\n\n this.emitEvent('connection:changed', {\n provider: 'transport',\n connected: true,\n });\n }\n\n // ===========================================================================\n // Public Methods - Events\n // ===========================================================================\n\n on<T extends SphereEventType>(type: T, handler: SphereEventHandler<T>): () => void {\n if (!this.eventHandlers.has(type)) {\n this.eventHandlers.set(type, new Set());\n }\n this.eventHandlers.get(type)!.add(handler as SphereEventHandler<SphereEventType>);\n\n return () => {\n this.eventHandlers.get(type)?.delete(handler as SphereEventHandler<SphereEventType>);\n };\n }\n\n off<T extends SphereEventType>(type: T, handler: SphereEventHandler<T>): void {\n this.eventHandlers.get(type)?.delete(handler as SphereEventHandler<SphereEventType>);\n }\n\n // ===========================================================================\n // Public Methods - Sync\n // ===========================================================================\n\n async sync(): Promise<void> {\n this.ensureReady();\n await this._payments.sync();\n }\n\n // ===========================================================================\n // Public Methods - Nametag\n // ===========================================================================\n\n /**\n * Get current nametag (if registered)\n */\n getNametag(): string | undefined {\n return this._identity?.nametag;\n }\n\n /**\n * Check if nametag is registered\n */\n hasNametag(): boolean {\n return !!this._identity?.nametag;\n }\n\n /**\n * Register a nametag for the current active address\n * Each address can have its own independent nametag\n *\n * @example\n * ```ts\n * // Register nametag for first address (index 0)\n * await sphere.registerNametag('alice');\n *\n * // Switch to second address and register different nametag\n * await sphere.switchToAddress(1);\n * await sphere.registerNametag('bob');\n *\n * // Now:\n * // - Address 0 has nametag @alice\n * // - Address 1 has nametag @bob\n * ```\n */\n async registerNametag(nametag: string): Promise<void> {\n this.ensureReady();\n\n // Validate nametag format\n const cleanNametag = nametag.startsWith('@') ? nametag.slice(1) : nametag;\n if (!this.validateNametag(cleanNametag)) {\n throw new Error('Invalid nametag format. Use alphanumeric characters, 3-20 chars.');\n }\n\n // Check if current address already has a nametag\n if (this._identity?.nametag) {\n throw new Error(`Nametag already registered for address ${this._currentAddressIndex}: @${this._identity.nametag}`);\n }\n\n // Register with transport provider (Nostr)\n if (this._transport.registerNametag) {\n const success = await this._transport.registerNametag(cleanNametag, this._identity!.publicKey);\n if (!success) {\n throw new Error('Failed to register nametag. It may already be taken.');\n }\n }\n\n // Update identity\n this._identity!.nametag = cleanNametag;\n\n // Store in address nametags map\n this._addressNametags.set(this._currentAddressIndex, cleanNametag);\n\n // Persist to storage (both legacy and new format)\n await this._storage.set(STORAGE_KEYS.NAMETAG, cleanNametag);\n await this.persistAddressNametags();\n\n // Mint nametag token on-chain if not already minted\n // Required for receiving tokens via @nametag (PROXY address finalization)\n if (!this._payments.hasNametag()) {\n console.log(`[Sphere] Minting nametag token for @${cleanNametag}...`);\n const result = await this.mintNametag(cleanNametag);\n if (!result.success) {\n console.warn(`[Sphere] Failed to mint nametag token: ${result.error}`);\n // Don't throw - nametag is registered on Nostr, token can be minted later\n } else {\n console.log(`[Sphere] Nametag token minted successfully`);\n }\n }\n\n this.emitEvent('nametag:registered', {\n nametag: cleanNametag,\n addressIndex: this._currentAddressIndex,\n });\n console.log(`[Sphere] Nametag registered for address ${this._currentAddressIndex}:`, cleanNametag);\n }\n\n /**\n * Persist address nametags to storage\n */\n private async persistAddressNametags(): Promise<void> {\n const nametagsObj: Record<string, string> = {};\n this._addressNametags.forEach((nametag, index) => {\n nametagsObj[index.toString()] = nametag;\n });\n await this._storage.set(STORAGE_KEYS.ADDRESS_NAMETAGS, JSON.stringify(nametagsObj));\n }\n\n /**\n * Mint a nametag token on-chain (like Sphere wallet and lottery)\n * This creates the nametag token required for receiving tokens via PROXY addresses (@nametag)\n *\n * @param nametag - The nametag to mint (e.g., \"alice\" or \"@alice\")\n * @returns MintNametagResult with success status and token if successful\n *\n * @example\n * ```typescript\n * // Mint nametag token for receiving via @alice\n * const result = await sphere.mintNametag('alice');\n * if (result.success) {\n * console.log('Nametag minted:', result.nametagData?.name);\n * } else {\n * console.error('Mint failed:', result.error);\n * }\n * ```\n */\n async mintNametag(nametag: string): Promise<import('../modules/payments').MintNametagResult> {\n this.ensureReady();\n return this._payments.mintNametag(nametag);\n }\n\n /**\n * Check if a nametag is available for minting\n * @param nametag - The nametag to check (e.g., \"alice\" or \"@alice\")\n * @returns true if available, false if taken or error\n */\n async isNametagAvailable(nametag: string): Promise<boolean> {\n this.ensureReady();\n return this._payments.isNametagAvailable(nametag);\n }\n\n /**\n * Load address nametags from storage\n */\n private async loadAddressNametags(): Promise<void> {\n try {\n const saved = await this._storage.get(STORAGE_KEYS.ADDRESS_NAMETAGS);\n if (saved) {\n const nametagsObj = JSON.parse(saved) as Record<string, string>;\n this._addressNametags.clear();\n for (const [indexStr, nametag] of Object.entries(nametagsObj)) {\n this._addressNametags.set(parseInt(indexStr, 10), nametag);\n }\n }\n } catch {\n // Ignore parse errors - start fresh\n }\n }\n\n /**\n * Sync nametag with Nostr on wallet load\n * If local nametag exists but not registered on Nostr, re-register it\n */\n private async syncNametagWithNostr(): Promise<void> {\n const nametag = this._identity?.nametag;\n if (!nametag) {\n return; // No nametag to sync\n }\n\n if (!this._transport.resolveNametag || !this._transport.registerNametag) {\n return; // Transport doesn't support nametag operations\n }\n\n try {\n // Register nametag (will check if already registered and re-publish if needed)\n const success = await this._transport.registerNametag(nametag, this._identity!.publicKey);\n if (success) {\n console.log(`[Sphere] Nametag @${nametag} synced with Nostr`);\n } else {\n console.warn(`[Sphere] Nametag @${nametag} is taken by another pubkey`);\n }\n } catch (error) {\n // Don't fail wallet load on nametag sync errors\n console.warn(`[Sphere] Nametag sync failed:`, error);\n }\n }\n\n /**\n * Validate nametag format\n */\n private validateNametag(nametag: string): boolean {\n // Alphanumeric characters, underscores and hyphens allowed\n const pattern = new RegExp(\n `^[a-zA-Z0-9_-]{${LIMITS.NAMETAG_MIN_LENGTH},${LIMITS.NAMETAG_MAX_LENGTH}}$`\n );\n return pattern.test(nametag);\n }\n\n // ===========================================================================\n // Public Methods - Lifecycle\n // ===========================================================================\n\n async destroy(): Promise<void> {\n this._payments.destroy();\n this._communications.destroy();\n\n await this._transport.disconnect();\n await this._storage.disconnect();\n await this._oracle.disconnect();\n\n this._initialized = false;\n this._identity = null;\n this.eventHandlers.clear();\n\n if (Sphere.instance === this) {\n Sphere.instance = null;\n }\n }\n\n // ===========================================================================\n // Private: Storage\n // ===========================================================================\n\n private async storeMnemonic(mnemonic: string, derivationPath?: string, basePath?: string): Promise<void> {\n // TODO: Encrypt with user password/PIN\n const encrypted = this.encrypt(mnemonic);\n await this._storage.set(STORAGE_KEYS.MNEMONIC, encrypted);\n\n // Store mnemonic in memory for getMnemonic()\n this._mnemonic = mnemonic;\n this._source = 'mnemonic';\n this._derivationMode = 'bip32';\n\n if (derivationPath) {\n await this._storage.set(STORAGE_KEYS.DERIVATION_PATH, derivationPath);\n }\n\n const effectiveBasePath = basePath ?? DEFAULT_BASE_PATH;\n this._basePath = effectiveBasePath;\n await this._storage.set(STORAGE_KEYS.BASE_PATH, effectiveBasePath);\n await this._storage.set(STORAGE_KEYS.DERIVATION_MODE, this._derivationMode);\n await this._storage.set(STORAGE_KEYS.WALLET_SOURCE, this._source);\n // Note: WALLET_EXISTS is set in finalizeWalletCreation() after successful initialization\n }\n\n private async storeMasterKey(\n masterKey: string,\n chainCode?: string,\n derivationPath?: string,\n basePath?: string,\n derivationMode?: DerivationMode\n ): Promise<void> {\n const encrypted = this.encrypt(masterKey);\n await this._storage.set(STORAGE_KEYS.MASTER_KEY, encrypted);\n\n // Set source and derivation mode\n this._source = 'file';\n this._mnemonic = null;\n\n // Determine derivation mode from chain code if not specified\n if (derivationMode) {\n this._derivationMode = derivationMode;\n } else {\n this._derivationMode = chainCode ? 'bip32' : 'wif_hmac';\n }\n\n if (chainCode) {\n await this._storage.set(STORAGE_KEYS.CHAIN_CODE, chainCode);\n }\n\n if (derivationPath) {\n await this._storage.set(STORAGE_KEYS.DERIVATION_PATH, derivationPath);\n }\n\n const effectiveBasePath = basePath ?? DEFAULT_BASE_PATH;\n this._basePath = effectiveBasePath;\n await this._storage.set(STORAGE_KEYS.BASE_PATH, effectiveBasePath);\n await this._storage.set(STORAGE_KEYS.DERIVATION_MODE, this._derivationMode);\n await this._storage.set(STORAGE_KEYS.WALLET_SOURCE, this._source);\n // Note: WALLET_EXISTS is set in finalizeWalletCreation() after successful initialization\n }\n\n /**\n * Mark wallet as fully created (after successful initialization)\n * This is called at the end of create()/import() to ensure wallet is only\n * marked as existing after all initialization steps succeed.\n */\n private async finalizeWalletCreation(): Promise<void> {\n await this._storage.set(STORAGE_KEYS.WALLET_EXISTS, 'true');\n }\n\n // ===========================================================================\n // Private: Identity Initialization\n // ===========================================================================\n\n private async loadIdentityFromStorage(): Promise<void> {\n const encryptedMnemonic = await this._storage.get(STORAGE_KEYS.MNEMONIC);\n const encryptedMasterKey = await this._storage.get(STORAGE_KEYS.MASTER_KEY);\n const chainCode = await this._storage.get(STORAGE_KEYS.CHAIN_CODE);\n const derivationPath = await this._storage.get(STORAGE_KEYS.DERIVATION_PATH);\n const savedNametag = await this._storage.get(STORAGE_KEYS.NAMETAG);\n const savedBasePath = await this._storage.get(STORAGE_KEYS.BASE_PATH);\n const savedDerivationMode = await this._storage.get(STORAGE_KEYS.DERIVATION_MODE);\n const savedSource = await this._storage.get(STORAGE_KEYS.WALLET_SOURCE);\n const savedAddressIndex = await this._storage.get(STORAGE_KEYS.CURRENT_ADDRESS_INDEX);\n\n // Restore wallet metadata\n this._basePath = savedBasePath ?? DEFAULT_BASE_PATH;\n this._derivationMode = (savedDerivationMode as DerivationMode) ?? 'bip32';\n this._source = (savedSource as WalletSource) ?? 'unknown';\n this._currentAddressIndex = savedAddressIndex ? parseInt(savedAddressIndex, 10) : 0;\n\n // Load address nametags\n await this.loadAddressNametags();\n\n if (encryptedMnemonic) {\n const mnemonic = this.decrypt(encryptedMnemonic);\n if (!mnemonic) {\n throw new Error('Failed to decrypt mnemonic');\n }\n this._mnemonic = mnemonic;\n this._source = 'mnemonic';\n await this.initializeIdentityFromMnemonic(mnemonic, derivationPath ?? undefined);\n } else if (encryptedMasterKey) {\n const masterKey = this.decrypt(encryptedMasterKey);\n if (!masterKey) {\n throw new Error('Failed to decrypt master key');\n }\n this._mnemonic = null;\n if (this._source === 'unknown') {\n this._source = 'file';\n }\n await this.initializeIdentityFromMasterKey(\n masterKey,\n chainCode ?? undefined,\n derivationPath ?? undefined\n );\n } else {\n throw new Error('No wallet data found in storage');\n }\n\n // If we have a saved address index > 0 and master key, switch to that address\n if (this._currentAddressIndex > 0 && this._masterKey) {\n // Re-derive identity for the saved address index\n const addressInfo = this.deriveAddress(this._currentAddressIndex, false);\n const ipnsHash = sha256(addressInfo.publicKey, 'hex').slice(0, 40);\n const predicateAddress = await deriveL3PredicateAddress(addressInfo.privateKey);\n const nametag = this._addressNametags.get(this._currentAddressIndex);\n\n this._identity = {\n privateKey: addressInfo.privateKey,\n publicKey: addressInfo.publicKey,\n address: addressInfo.address,\n predicateAddress,\n ipnsName: '12D3KooW' + ipnsHash,\n nametag,\n };\n console.log(`[Sphere] Restored to address ${this._currentAddressIndex}:`, this._identity.address);\n } else {\n // Restore saved nametag for address 0 (legacy support)\n if (savedNametag && this._identity) {\n this._identity.nametag = savedNametag;\n // Also add to address nametags map if not already there\n if (!this._addressNametags.has(0)) {\n this._addressNametags.set(0, savedNametag);\n }\n console.log('[Sphere] Restored nametag:', savedNametag);\n } else if (this._identity) {\n // Check if we have a nametag in the map for address 0\n const nametag = this._addressNametags.get(0);\n if (nametag) {\n this._identity.nametag = nametag;\n console.log('[Sphere] Restored nametag from map:', nametag);\n }\n }\n }\n }\n\n private async initializeIdentityFromMnemonic(\n mnemonic: string,\n derivationPath?: string\n ): Promise<void> {\n const path = derivationPath ?? DEFAULT_DERIVATION_PATH;\n\n // Generate master key from mnemonic using BIP39/BIP32\n const masterKey = identityFromMnemonicSync(mnemonic);\n\n // Derive key at path (e.g., m/44'/0'/0'/0/0)\n const derivedKey = deriveKeyAtPath(\n masterKey.privateKey,\n masterKey.chainCode,\n `${path}/0/0`\n );\n\n // Get public key from derived private key\n const publicKey = getPublicKey(derivedKey.privateKey);\n\n // Generate address hash (platform implementations will do bech32 encoding)\n const addressHash = hash160(publicKey);\n\n // Generate IPNS name from public key hash\n const ipnsHash = sha256(publicKey, 'hex').slice(0, 40);\n\n // Derive L3 predicate address (DIRECT://...)\n const predicateAddress = await deriveL3PredicateAddress(derivedKey.privateKey);\n\n this._identity = {\n privateKey: derivedKey.privateKey,\n publicKey,\n address: 'alpha1' + addressHash.slice(0, 38),\n predicateAddress,\n ipnsName: '12D3KooW' + ipnsHash,\n };\n\n // Store master key info for future derivations\n this._masterKey = masterKey;\n\n console.log('[Sphere] Identity initialized from mnemonic, path:', path);\n }\n\n private async initializeIdentityFromMasterKey(\n masterKey: string,\n chainCode?: string,\n derivationPath?: string\n ): Promise<void> {\n const path = derivationPath ?? DEFAULT_DERIVATION_PATH;\n\n let privateKey: string;\n\n if (chainCode) {\n // Full BIP32 derivation with chain code\n const derivedKey = deriveKeyAtPath(masterKey, chainCode, `${path}/0/0`);\n privateKey = derivedKey.privateKey;\n\n this._masterKey = {\n privateKey: masterKey,\n chainCode,\n };\n } else {\n // Direct master key usage (legacy wallets)\n privateKey = masterKey;\n this._masterKey = null;\n }\n\n const publicKey = getPublicKey(privateKey);\n const addressHash = hash160(publicKey);\n const ipnsHash = sha256(publicKey, 'hex').slice(0, 40);\n\n // Derive L3 predicate address (DIRECT://...)\n const predicateAddress = await deriveL3PredicateAddress(privateKey);\n\n this._identity = {\n privateKey,\n publicKey,\n address: 'alpha1' + addressHash.slice(0, 38),\n predicateAddress,\n ipnsName: '12D3KooW' + ipnsHash,\n };\n\n console.log('[Sphere] Identity initialized from master key, path:', path, 'chainCode:', !!chainCode);\n }\n\n // ===========================================================================\n // Private: Provider & Module Initialization\n // ===========================================================================\n\n private async initializeProviders(): Promise<void> {\n // Set identity on providers\n this._storage.setIdentity(this._identity!);\n this._transport.setIdentity(this._identity!);\n\n // Set identity on all token storage providers\n for (const provider of this._tokenStorageProviders.values()) {\n provider.setIdentity(this._identity!);\n }\n\n // Connect providers\n await this._storage.connect();\n await this._transport.connect();\n await this._oracle.initialize();\n\n // Initialize all token storage providers\n for (const provider of this._tokenStorageProviders.values()) {\n await provider.initialize();\n }\n }\n\n private async initializeModules(): Promise<void> {\n const emitEvent = this.emitEvent.bind(this);\n\n this._payments.initialize({\n identity: this._identity!,\n storage: this._storage,\n tokenStorageProviders: this._tokenStorageProviders,\n transport: this._transport,\n oracle: this._oracle,\n emitEvent,\n // Pass chain code for L1 HD derivation\n chainCode: this._masterKey?.chainCode,\n });\n\n this._communications.initialize({\n identity: this._identity!,\n storage: this._storage,\n transport: this._transport,\n emitEvent,\n });\n\n await this._payments.load();\n await this._communications.load();\n }\n\n // ===========================================================================\n // Private: Helpers\n // ===========================================================================\n\n private ensureReady(): void {\n if (!this._initialized) {\n throw new Error('Sphere not initialized');\n }\n }\n\n private emitEvent<T extends SphereEventType>(type: T, data: SphereEventMap[T]): void {\n const handlers = this.eventHandlers.get(type);\n if (!handlers) return;\n\n for (const handler of handlers) {\n try {\n (handler as SphereEventHandler<T>)(data);\n } catch (error) {\n console.error('[Sphere] Event handler error:', error);\n }\n }\n }\n\n // ===========================================================================\n // Private: Encryption\n // ===========================================================================\n\n private encrypt(data: string): string {\n // Use AES-256 encryption with default key\n // TODO: Add password parameter to create/load for user-provided encryption\n return encryptSimple(data, DEFAULT_ENCRYPTION_KEY);\n }\n\n private decrypt(encrypted: string): string | null {\n try {\n return decryptSimple(encrypted, DEFAULT_ENCRYPTION_KEY);\n } catch {\n return null;\n }\n }\n}\n\n// =============================================================================\n// Convenience Exports\n// =============================================================================\n\nexport const createSphere = Sphere.create.bind(Sphere);\nexport const loadSphere = Sphere.load.bind(Sphere);\nexport const importSphere = Sphere.import.bind(Sphere);\nexport const initSphere = Sphere.init.bind(Sphere);\nexport const getSphere = Sphere.getInstance.bind(Sphere);\nexport const sphereExists = Sphere.exists.bind(Sphere);\n","/**\n * Currency Utilities\n * Conversion between human-readable amounts and smallest units (bigint)\n */\n\n// =============================================================================\n// Constants\n// =============================================================================\n\n/** Default token decimals (18 for most tokens) */\nexport const DEFAULT_TOKEN_DECIMALS = 18;\n\n// =============================================================================\n// Conversion Functions\n// =============================================================================\n\n/**\n * Convert human-readable amount to smallest unit (bigint)\n *\n * @example\n * ```ts\n * toSmallestUnit('1.5', 18) // 1500000000000000000n\n * toSmallestUnit('100', 6) // 100000000n\n * ```\n */\nexport function toSmallestUnit(amount: number | string, decimals: number = DEFAULT_TOKEN_DECIMALS): bigint {\n if (!amount) return 0n;\n\n try {\n const str = amount.toString();\n const [integer, fraction = ''] = str.split('.');\n\n // Pad fraction to exact decimal places, truncate if longer\n const paddedFraction = fraction.padEnd(decimals, '0').slice(0, decimals);\n\n return BigInt(integer + paddedFraction);\n } catch {\n return 0n;\n }\n}\n\n/**\n * Convert smallest unit (bigint) to human-readable string\n *\n * @example\n * ```ts\n * toHumanReadable(1500000000000000000n, 18) // '1.5'\n * toHumanReadable(100000000n, 6) // '100'\n * ```\n */\nexport function toHumanReadable(amount: bigint | string, decimals: number = DEFAULT_TOKEN_DECIMALS): string {\n const str = amount.toString().padStart(decimals + 1, '0');\n const integer = str.slice(0, -decimals) || '0';\n const fraction = str.slice(-decimals).replace(/0+$/, '');\n\n return fraction ? `${integer}.${fraction}` : integer;\n}\n\n/**\n * Format amount for display with optional symbol\n *\n * @example\n * ```ts\n * formatAmount(1500000000000000000n, { decimals: 18, symbol: 'ALPHA' })\n * // '1.5 ALPHA'\n * ```\n */\nexport function formatAmount(\n amount: bigint | string,\n options: {\n decimals?: number;\n symbol?: string;\n maxFractionDigits?: number;\n } = {}\n): string {\n const { decimals = DEFAULT_TOKEN_DECIMALS, symbol, maxFractionDigits } = options;\n\n let readable = toHumanReadable(amount, decimals);\n\n // Limit fraction digits if specified\n if (maxFractionDigits !== undefined) {\n const [int, frac] = readable.split('.');\n if (frac && frac.length > maxFractionDigits) {\n readable = maxFractionDigits > 0 ? `${int}.${frac.slice(0, maxFractionDigits)}` : int;\n }\n }\n\n return symbol ? `${readable} ${symbol}` : readable;\n}\n\n// =============================================================================\n// Export as namespace for convenience\n// =============================================================================\n\nexport const CurrencyUtils = {\n toSmallestUnit,\n toHumanReadable,\n format: formatAmount,\n};\n"],"mappings":"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","names":["CryptoJS","generateMnemonic","validateMnemonic","mnemonicToSeed","mnemonicToSeedSync","mnemonicToEntropy","entropyToMnemonic","CryptoJS","bytesToHex","CryptoJS","CryptoJS","CryptoJS","elliptic","ec","elliptic","CryptoJS","CoinId","sha256","Token","TokenId","TokenState","HashAlgorithm","UnmaskedPredicate","waitInclusionProof","DEFAULT_DERIVATION_PATH","bytesToHex","SdkToken","TokenId","CoinId","TransferCommitment","UnmaskedPredicate","TokenState","HashAlgorithm","pending","requestId","UnmaskedPredicateReference","TokenType","UNICITY_TOKEN_TYPE_HEX","tokenId","broadcast","CryptoJS","encrypt","decrypt","CryptoJS","CryptoJS","CryptoJS","bytesToHex","CryptoJS","SigningService","TokenType","HashAlgorithm","UnmaskedPredicateReference","UNICITY_TOKEN_TYPE_HEX","sphere","validateMnemonic","generateMnemonic","DEFAULT_DERIVATION_PATH"]}