Untitled
declare enum AddressType { p2pkh = "p2pkh", p2sh = "p2sh", p2wpkh = "p2wpkh", p2wsh = "p2wsh", p2tr = "p2tr" } const networkModes = ['mainnet', 'testnet'] as const; type NetworkModes = (typeof networkModes)[number]; const getCoinType = (network: NetworkModes) => (network === 'mainnet' ? 0 : 1); const walletTypes = [ { type: 'Native Segwit', path: `m/84'/`, addressType: AddressType.p2wpkh }, { type: 'Nested Segwit', path: `m/49'/`, addressType: AddressType.p2sh }, { type: 'Legacy', path: `m/44'/`, addressType: AddressType.p2pkh }, { type: 'Taproot', path: `m/86'/`, addressType: AddressType.p2tr }, ]; function getPublicKeyFromXpubAtIndex(xpub: string, index: number, network: string): Buffer { const btcNetwork = network === 'mainnet' ? networks.bitcoin : networks.testnet; const { publicKey } = bip32.fromBase58(xpub, btcNetwork).derivePath(`0/${index}`); return Buffer.from(publicKey); } function publicKeyToAddress(publicKey: string, type: AddressType, network: Network) { if (!publicKey) return ''; const pubkey = Buffer.from(publicKey, 'hex'); if (type === AddressType.p2pkh) { const { address } = bitcoin.payments.p2pkh({ pubkey, network, }); return address || ''; } else if (type === AddressType.p2wpkh) { const { address } = bitcoin.payments.p2wpkh({ pubkey, network, }); return address || ''; } else if (type === AddressType.p2tr) { const { address } = bitcoin.payments.p2tr({ internalPubkey: pubkey.length === 32 ? pubkey : pubkey.slice(1, 33), network, }); return address || ''; } else if (type === AddressType.p2sh) { const { address } = bitcoin.payments.p2sh({ pubkey: pubkey, network, redeem: bitcoin.payments.p2wpkh({ pubkey: pubkey, network }), }); return address || ''; } else { return ''; } } async function importAccointFromLedger({ extendedPublicKey, network, addressIndex, addressType, }: { extendedPublicKey: string; network: NetworkModes; addressIndex: number; addressType: AddressType; }): Promise<{ address: string; publicKey: string }> { const publicKey = getPublicKeyFromXpubAtIndex(extendedPublicKey, addressIndex, network).toString( 'hex' ); const net = network === 'mainnet' ? networks.bitcoin : networks.testnet; const address = publicKeyToAddress(publicKey, addressType, net); return { address, publicKey: publicKey }; } export function pullBitcoinKeysFromLedgerDevice( app: BitcoinApp, derivationPath: string, addressType: AddressType ) { return async ({ onRequestKey, network }) => { const amountOfKeysToExtractFromDevice = 10; const btcNetwork = getCoinType(network); const keys: IAddressSelection[] = []; for (let accountIndex = 0; accountIndex < amountOfKeysToExtractFromDevice; accountIndex++) { const xpubDerivationPath = `${derivationPath}${btcNetwork}'/${accountIndex}'`; const extendedPublicKey = await app.getExtendedPubkey(xpubDerivationPath); onRequestKey?.(accountIndex); const { publicKey, address } = await importAccointFromLedger({ extendedPublicKey, network, addressIndex: 0, addressType, }); const fullDerivationPath = `${xpubDerivationPath}/0/0`; keys.push({ publicKey, address, xpub: extendedPublicKey, derivationPath: fullDerivationPath, }); } return { status: 'success', keys }; }; }
Leave a Comment