UNPKG

@ledgerhq/hw-app-btc

Version:
83 lines 3.66 kB
import { detectScriptType } from "@ledgerhq/psbtv2"; import { pathArrayToString, pathStringToArray } from "../bip32"; import { checkBip32Derivation } from "./derivationAccessors"; export function arePathsEqual(path1, path2) { if (path1.length !== path2.length) return false; return path1.every((elem, idx) => elem === path2[idx]); } export function validateAccountPathConsistency(accountPath, newAccountPath, inputIndex) { if (accountPath.length > 0 && !arePathsEqual(accountPath, newAccountPath)) { throw new Error(`Mixed accounts detected in PSBT. Input ${inputIndex} uses account path ` + `${pathArrayToString(newAccountPath)} but expected ` + `${pathArrayToString(accountPath)}. All internal inputs must belong to the same account.`); } } export function validateScriptTypeConsistency(detectedScriptType, newScriptType, inputIndex) { if (detectedScriptType && newScriptType && detectedScriptType !== newScriptType) { throw new Error(`Mixed input types detected in PSBT. Input ${inputIndex} uses ${newScriptType} ` + `but expected ${detectedScriptType}. All internal inputs must use the same script type.`); } } export function resolveAccountPathFromOptions(accountPathOption) { if (!accountPathOption) { throw new Error("No internal inputs found in PSBT (no BIP32 derivation matching device fingerprint) " + "and no account path provided in options. Please provide accountPath in options " + "(e.g., \"m/84'/0'/0'\" for native segwit)"); } return pathStringToArray(accountPathOption); } /** * Determines the script type for a single input from witness UTXO or redeem script. */ export function determineInputScriptType(psbt, inputIndex) { const witnessUtxo = psbt.getInputWitnessUtxo(inputIndex); if (witnessUtxo) { return detectScriptType(witnessUtxo.scriptPubKey); } const redeemScript = psbt.getInputRedeemScript(inputIndex); if (redeemScript) { return "p2sh-p2wpkh"; } return undefined; } /** * Analyzes a single input to determine if it belongs to the connected signer and extracts account path and script type. */ export function analyzeInput(psbt, inputIndex, masterFp) { const derivationResult = checkBip32Derivation(psbt, inputIndex, masterFp); const scriptType = determineInputScriptType(psbt, inputIndex); return { belongsToSigner: derivationResult.belongsToSigner, accountPath: derivationResult.accountPath, scriptType, }; } /** * Analyzes all inputs and returns resolved account path, detected script type, and internal input indices. */ export function analyzeAllInputs(psbt, inputCount, masterFp, accountPathOption) { const internalInputIndices = []; let accountPath = []; let detectedScriptType; for (let i = 0; i < inputCount; i++) { const inputInfo = analyzeInput(psbt, i, masterFp); if (!inputInfo.belongsToSigner) { continue; } internalInputIndices.push(i); validateAccountPathConsistency(accountPath, inputInfo.accountPath, i); if (accountPath.length === 0) { accountPath = inputInfo.accountPath; } validateScriptTypeConsistency(detectedScriptType, inputInfo.scriptType, i); if (!detectedScriptType) { detectedScriptType = inputInfo.scriptType; } } if (internalInputIndices.length === 0) { accountPath = resolveAccountPathFromOptions(accountPathOption); } return { accountPath, detectedScriptType, internalInputIndices }; } //# sourceMappingURL=inputAnalysis.js.map