1+ import { TapLeafScript } from 'bip174/src/lib/interfaces' ;
12import * as utxolib from '@bitgo/utxo-lib' ;
2- import { Descriptor } from '@bitgo/wasm-miniscript' ;
3+ import { Descriptor , Miniscript } from '@bitgo/wasm-miniscript' ;
34
45import { DerivedDescriptorWalletOutput , WithOptDescriptor } from '../Output' ;
56import { Output } from '../../Output' ;
@@ -13,18 +14,43 @@ import { assertSatisfiable } from './assertSatisfiable';
1314 * */
1415export const MAX_BIP125_RBF_SEQUENCE = 0xffffffff - 2 ;
1516
16- function updateInputsWithDescriptors ( psbt : utxolib . bitgo . UtxoPsbt , descriptors : Descriptor [ ] ) {
17- if ( psbt . txInputs . length !== descriptors . length ) {
18- throw new Error ( `Input count mismatch (psbt=${ psbt . txInputs . length } , descriptors=${ descriptors . length } )` ) ;
17+ export function findTapLeafScript ( input : TapLeafScript [ ] , script : Buffer | Miniscript ) : TapLeafScript {
18+ if ( ! Buffer . isBuffer ( script ) ) {
19+ script = Buffer . from ( script . encode ( ) ) ;
20+ }
21+ const matches = input . filter ( ( leaf ) => {
22+ return leaf . script . equals ( script ) ;
23+ } ) ;
24+ if ( matches . length === 0 ) {
25+ throw new Error ( `No tapLeafScript found for script: ${ script . toString ( 'hex' ) } ` ) ;
26+ }
27+ if ( matches . length > 1 ) {
28+ throw new Error ( `Multiple tapLeafScripts found for script: ${ script . toString ( 'hex' ) } ` ) ;
29+ }
30+ return matches [ 0 ] ;
31+ }
32+
33+ function updateInputsWithDescriptors (
34+ psbt : utxolib . bitgo . UtxoPsbt ,
35+ inputParams : Array < { descriptor : Descriptor ; selectTapLeafScript ?: Miniscript } >
36+ ) {
37+ if ( psbt . txInputs . length !== inputParams . length ) {
38+ throw new Error ( `Input count mismatch (psbt=${ psbt . txInputs . length } , inputParams=${ inputParams . length } )` ) ;
1939 }
2040 const wrappedPsbt = toWrappedPsbt ( psbt ) ;
21- for ( const [ inputIndex , descriptor ] of descriptors . entries ( ) ) {
22- assertSatisfiable ( psbt , inputIndex , descriptor ) ;
23- wrappedPsbt . updateInputWithDescriptor ( inputIndex , descriptor ) ;
41+ for ( const [ inputIndex , v ] of inputParams . entries ( ) ) {
42+ assertSatisfiable ( psbt , inputIndex , v . descriptor ) ;
43+ wrappedPsbt . updateInputWithDescriptor ( inputIndex , v . descriptor ) ;
2444 }
2545 const unwrappedPsbt = toUtxoPsbt ( wrappedPsbt , psbt . network ) ;
2646 for ( const inputIndex in psbt . txInputs ) {
27- psbt . data . inputs [ inputIndex ] = unwrappedPsbt . data . inputs [ inputIndex ] ;
47+ const preparedInput = unwrappedPsbt . data . inputs [ inputIndex ] ;
48+ const v = inputParams [ inputIndex ] ;
49+ if ( v . selectTapLeafScript && preparedInput . tapLeafScript ) {
50+ const selected = findTapLeafScript ( preparedInput . tapLeafScript , v . selectTapLeafScript ) ;
51+ preparedInput . tapLeafScript = [ selected ] ;
52+ }
53+ psbt . data . inputs [ inputIndex ] = preparedInput ;
2854 }
2955}
3056
@@ -49,6 +75,7 @@ export type PsbtParams = {
4975} ;
5076
5177export type DerivedDescriptorTransactionInput = DerivedDescriptorWalletOutput & {
78+ selectTapLeafScript ?: Miniscript ;
5279 sequence ?: number ;
5380} ;
5481
@@ -64,7 +91,10 @@ export function createPsbt(
6491 psbt . addOutputs ( outputs ) ;
6592 updateInputsWithDescriptors (
6693 psbt ,
67- inputs . map ( ( i ) => i . descriptor )
94+ inputs . map ( ( { descriptor, selectTapLeafScript } ) => ( {
95+ descriptor,
96+ selectTapLeafScript,
97+ } ) )
6898 ) ;
6999 updateOutputsWithDescriptors ( psbt , outputs ) ;
70100 return psbt ;
0 commit comments