// Wallet operations: mnemonic generation, HD derivation, signing. // All crypto delegated to ethers.js. const { Mnemonic, HDNodeWallet, Wallet } = require("ethers"); const { DEBUG, DEBUG_MNEMONIC, BIP44_ETH_PATH } = require("./constants"); function generateMnemonic() { if (DEBUG) return DEBUG_MNEMONIC; const m = Mnemonic.fromEntropy( globalThis.crypto.getRandomValues(new Uint8Array(16)), ); return m.phrase; } function deriveAddressFromXpub(xpub, index) { const node = HDNodeWallet.fromExtendedKey(xpub); return node.deriveChild(index).address; } function hdWalletFromMnemonic(mnemonic) { const node = HDNodeWallet.fromPhrase(mnemonic, "", BIP44_ETH_PATH); const xpub = node.neuter().extendedKey; const firstAddress = node.deriveChild(0).address; return { xpub, firstAddress }; } function hdWalletFromXprv(xprv) { const root = HDNodeWallet.fromExtendedKey(xprv); if (!root.privateKey) { throw new Error("Not an extended private key (xprv)."); } const node = root.derivePath("44'/60'/0'/0"); const xpub = node.neuter().extendedKey; const firstAddress = node.deriveChild(0).address; return { xpub, firstAddress }; } function isValidXprv(key) { try { const node = HDNodeWallet.fromExtendedKey(key); return !!node.privateKey; } catch { return false; } } function addressFromPrivateKey(key) { const w = new Wallet(key); return w.address; } function getSignerForAddress(walletData, addrIndex, decryptedSecret) { if (walletData.type === "hd") { const node = HDNodeWallet.fromPhrase( decryptedSecret, "", BIP44_ETH_PATH, ); return node.deriveChild(addrIndex); } if (walletData.type === "xprv") { const root = HDNodeWallet.fromExtendedKey(decryptedSecret); const node = root.derivePath("44'/60'/0'/0"); return node.deriveChild(addrIndex); } return new Wallet(decryptedSecret); } function isValidMnemonic(mnemonic) { return Mnemonic.isValidMnemonic(mnemonic); } module.exports = { generateMnemonic, deriveAddressFromXpub, hdWalletFromMnemonic, hdWalletFromXprv, isValidXprv, addressFromPrivateKey, getSignerForAddress, isValidMnemonic, };