import { PsbtV2, detectScriptType } from "@ledgerhq/psbtv2"; import { AccountType, p2pkh, p2tr, p2wpkh, p2wpkhWrapped } from "../newops/accounttype"; import type { DefaultDescriptorTemplate } from "../newops/policy"; import type { AddressFormat } from "../getWalletPublicKey"; import type { ScriptType } from "./types"; function descrTemplFrom(addressFormat: AddressFormat): DefaultDescriptorTemplate { switch (addressFormat) { case "legacy": return "pkh(@0)"; case "p2sh": return "sh(wpkh(@0))"; case "bech32": return "wpkh(@0)"; case "bech32m": return "tr(@0)"; default: throw new Error("Unsupported address format " + addressFormat); } } export function createAccountTypeFromScriptType( scriptType: ScriptType, psbt: PsbtV2, masterFp: Buffer, ): AccountType { switch (scriptType) { case "p2wpkh": return new p2wpkh(psbt, masterFp); case "p2tr": return new p2tr(psbt, masterFp); case "p2sh": case "p2sh-p2wpkh": return new p2wpkhWrapped(psbt, masterFp); case "p2pkh": return new p2pkh(psbt, masterFp); } } export function determineAccountTypeFromWitnessUtxo( psbt: PsbtV2, inputIndex: number, masterFp: Buffer, ): AccountType | null { const witnessUtxo = psbt.getInputWitnessUtxo(inputIndex); if (!witnessUtxo) { return null; } const scriptType = detectScriptType(witnessUtxo.scriptPubKey); if (!scriptType) { throw new Error(`Unsupported script type: ${witnessUtxo.scriptPubKey.toString("hex")}`); } return createAccountTypeFromScriptType(scriptType, psbt, masterFp); } export function createAccountTypeFromAddressFormat( addressFormat: AddressFormat, psbt: PsbtV2, masterFp: Buffer, ): AccountType { const descrTemplate = descrTemplFrom(addressFormat); switch (descrTemplate) { case "pkh(@0)": return new p2pkh(psbt, masterFp); case "wpkh(@0)": return new p2wpkh(psbt, masterFp); case "sh(wpkh(@0))": return new p2wpkhWrapped(psbt, masterFp); case "tr(@0)": return new p2tr(psbt, masterFp); default: throw new Error(`Unsupported descriptor template: ${descrTemplate}`); } } export function determineAccountTypeFromPurpose( accountPath: number[], psbt: PsbtV2, masterFp: Buffer, ): AccountType | null { if (accountPath.length < 1) { return null; } const purpose = accountPath[0] - 0x80000000; switch (purpose) { case 44: return new p2pkh(psbt, masterFp); case 49: return new p2wpkhWrapped(psbt, masterFp); case 84: return new p2wpkh(psbt, masterFp); case 86: return new p2tr(psbt, masterFp); default: return null; } } /** * Determines the account type based on detected script type, account path, or options. */ export function determineAccountType( psbt: PsbtV2, inputIndex: number, masterFp: Buffer, detectedScriptType: ScriptType | undefined, accountPath: number[], addressFormat?: AddressFormat, ): AccountType { if (detectedScriptType) { return createAccountTypeFromScriptType(detectedScriptType, psbt, masterFp); } const witnessUtxoType = determineAccountTypeFromWitnessUtxo(psbt, inputIndex, masterFp); if (witnessUtxoType) { return witnessUtxoType; } if (psbt.getInputRedeemScript(inputIndex)) { return new p2wpkhWrapped(psbt, masterFp); } if (addressFormat) { return createAccountTypeFromAddressFormat(addressFormat, psbt, masterFp); } const purposeBasedType = determineAccountTypeFromPurpose(accountPath, psbt, masterFp); if (purposeBasedType) { return purposeBasedType; } return new p2wpkh(psbt, masterFp); }