@@ -3,9 +3,13 @@ use crate::wasm::descriptor::WrapDescriptorEnum;
33use crate :: wasm:: try_into_js_value:: TryIntoJsValue ;
44use crate :: wasm:: WrapDescriptor ;
55use miniscript:: bitcoin:: bip32:: Fingerprint ;
6+ use miniscript:: bitcoin:: locktime:: absolute:: LockTime ;
67use miniscript:: bitcoin:: secp256k1:: { Secp256k1 , Signing } ;
7- use miniscript:: bitcoin:: { bip32, psbt, PublicKey , XOnlyPublicKey } ;
8- use miniscript:: bitcoin:: { PrivateKey , Psbt } ;
8+ use miniscript:: bitcoin:: transaction:: { Transaction , Version } ;
9+ use miniscript:: bitcoin:: {
10+ bip32, psbt, Amount , OutPoint , PublicKey , ScriptBuf , Sequence , XOnlyPublicKey ,
11+ } ;
12+ use miniscript:: bitcoin:: { PrivateKey , Psbt , TxIn , TxOut , Txid } ;
913use miniscript:: descriptor:: { SinglePub , SinglePubKey } ;
1014use miniscript:: psbt:: PsbtExt ;
1115use miniscript:: { DescriptorPublicKey , ToPublicKey } ;
@@ -78,6 +82,22 @@ pub struct WrapPsbt(Psbt);
7882
7983#[ wasm_bindgen( ) ]
8084impl WrapPsbt {
85+ /// Create an empty PSBT
86+ ///
87+ /// # Arguments
88+ /// * `version` - Transaction version (default: 2)
89+ /// * `lock_time` - Transaction lock time (default: 0)
90+ #[ wasm_bindgen( constructor) ]
91+ pub fn new ( version : Option < i32 > , lock_time : Option < u32 > ) -> WrapPsbt {
92+ let tx = Transaction {
93+ version : Version ( version. unwrap_or ( 2 ) ) ,
94+ lock_time : LockTime :: from_consensus ( lock_time. unwrap_or ( 0 ) ) ,
95+ input : vec ! [ ] ,
96+ output : vec ! [ ] ,
97+ } ;
98+ WrapPsbt ( Psbt :: from_unsigned_tx ( tx) . expect ( "empty transaction should be valid" ) )
99+ }
100+
81101 pub fn deserialize ( psbt : Vec < u8 > ) -> Result < WrapPsbt , JsError > {
82102 Ok ( WrapPsbt ( Psbt :: deserialize ( & psbt) . map_err ( JsError :: from) ?) )
83103 }
@@ -91,6 +111,91 @@ impl WrapPsbt {
91111 Clone :: clone ( self )
92112 }
93113
114+ /// Add an input to the PSBT
115+ ///
116+ /// # Arguments
117+ /// * `txid` - Transaction ID (hex string, 32 bytes reversed)
118+ /// * `vout` - Output index being spent
119+ /// * `value` - Value in satoshis of the output being spent
120+ /// * `script` - The scriptPubKey of the output being spent
121+ /// * `sequence` - Sequence number (default: 0xFFFFFFFE for RBF)
122+ ///
123+ /// # Returns
124+ /// The index of the newly added input
125+ #[ wasm_bindgen( js_name = addInput) ]
126+ pub fn add_input (
127+ & mut self ,
128+ txid : & str ,
129+ vout : u32 ,
130+ value : u64 ,
131+ script : & [ u8 ] ,
132+ sequence : Option < u32 > ,
133+ ) -> Result < usize , JsError > {
134+ let txid =
135+ Txid :: from_str ( txid) . map_err ( |e| JsError :: new ( & format ! ( "Invalid txid: {}" , e) ) ) ?;
136+ let script = ScriptBuf :: from_bytes ( script. to_vec ( ) ) ;
137+
138+ let tx_in = TxIn {
139+ previous_output : OutPoint { txid, vout } ,
140+ script_sig : ScriptBuf :: new ( ) ,
141+ sequence : Sequence ( sequence. unwrap_or ( 0xFFFFFFFE ) ) ,
142+ witness : miniscript:: bitcoin:: Witness :: default ( ) ,
143+ } ;
144+
145+ let psbt_input = psbt:: Input {
146+ witness_utxo : Some ( TxOut {
147+ value : Amount :: from_sat ( value) ,
148+ script_pubkey : script,
149+ } ) ,
150+ ..Default :: default ( )
151+ } ;
152+
153+ self . 0 . unsigned_tx . input . push ( tx_in) ;
154+ self . 0 . inputs . push ( psbt_input) ;
155+
156+ Ok ( self . 0 . inputs . len ( ) - 1 )
157+ }
158+
159+ /// Add an output to the PSBT
160+ ///
161+ /// # Arguments
162+ /// * `script` - The output script (scriptPubKey)
163+ /// * `value` - Value in satoshis
164+ ///
165+ /// # Returns
166+ /// The index of the newly added output
167+ #[ wasm_bindgen( js_name = addOutput) ]
168+ pub fn add_output ( & mut self , script : & [ u8 ] , value : u64 ) -> usize {
169+ let script = ScriptBuf :: from_bytes ( script. to_vec ( ) ) ;
170+
171+ let tx_out = TxOut {
172+ value : Amount :: from_sat ( value) ,
173+ script_pubkey : script,
174+ } ;
175+
176+ let psbt_output = psbt:: Output :: default ( ) ;
177+
178+ self . 0 . unsigned_tx . output . push ( tx_out) ;
179+ self . 0 . outputs . push ( psbt_output) ;
180+
181+ self . 0 . outputs . len ( ) - 1
182+ }
183+
184+ /// Get the unsigned transaction bytes
185+ ///
186+ /// # Returns
187+ /// The serialized unsigned transaction
188+ #[ wasm_bindgen( js_name = getUnsignedTx) ]
189+ pub fn get_unsigned_tx ( & self ) -> Vec < u8 > {
190+ use miniscript:: bitcoin:: consensus:: Encodable ;
191+ let mut buf = Vec :: new ( ) ;
192+ self . 0
193+ . unsigned_tx
194+ . consensus_encode ( & mut buf)
195+ . expect ( "encoding to vec should not fail" ) ;
196+ buf
197+ }
198+
94199 #[ wasm_bindgen( js_name = updateInputWithDescriptor) ]
95200 pub fn update_input_with_descriptor (
96201 & mut self ,
0 commit comments