@@ -21,8 +21,9 @@ use gdk_common::be::{
21
21
} ;
22
22
use gdk_common:: error:: fn_err;
23
23
use gdk_common:: model:: {
24
- AccountInfo , AddressAmount , AddressPointer , Balances , CreateTransaction , GetTransactionsOpt ,
25
- SPVVerifyTxResult , TransactionMeta , UpdateAccountOpt , UtxoStrategy ,
24
+ parse_path, AccountInfo , AddressAmount , AddressPointer , Balances , CreateTransaction ,
25
+ GetTransactionsOpt , SPVVerifyTxResult , TransactionMeta , UnspentOutput , UpdateAccountOpt ,
26
+ UtxoStrategy ,
26
27
} ;
27
28
use gdk_common:: scripts:: { p2pkh_script, p2shwpkh_script_sig, ScriptType } ;
28
29
use gdk_common:: util:: is_confidential_txoutsecrets;
@@ -57,7 +58,7 @@ pub struct Account {
57
58
/// thus at following logins it will be false.
58
59
discovered : bool ,
59
60
60
- _path : DerivationPath ,
61
+ path : DerivationPath ,
61
62
}
62
63
63
64
/// Compare xpub ignoring the fingerprint (which computation might be skipped).
@@ -106,8 +107,7 @@ impl Account {
106
107
chains,
107
108
store,
108
109
master_blinding,
109
- // currently unused, but seems useful to have around
110
- _path : path,
110
+ path,
111
111
discovered,
112
112
} )
113
113
}
@@ -116,6 +116,16 @@ impl Account {
116
116
self . account_num
117
117
}
118
118
119
+ /// Get the full path from the master key to address index
120
+ ///
121
+ /// // < full path >
122
+ /// m / purpose' / coin_type ' / account' / change / address_index
123
+ /// // < account path >
124
+ ///
125
+ fn get_full_path ( & self , account_path : & DerivationPath ) -> DerivationPath {
126
+ self . path . extend ( account_path)
127
+ }
128
+
119
129
pub fn info ( & self ) -> Result < AccountInfo , Error > {
120
130
let settings = self . store . read ( ) ?. get_account_settings ( self . account_num ) . cloned ( ) ;
121
131
@@ -298,6 +308,57 @@ impl Account {
298
308
p2pkh_script ( public_key) . into ( )
299
309
}
300
310
311
+ fn txo ( & self , outpoint : & BEOutPoint ) -> Result < UnspentOutput , Error > {
312
+ let vout = outpoint. vout ( ) ;
313
+ let txid = outpoint. txid ( ) ;
314
+
315
+ let store_read = self . store . read ( ) ?;
316
+ let acc_store = store_read. account_cache ( self . account_num ) ?;
317
+
318
+ let txe =
319
+ acc_store. all_txs . get ( & txid) . ok_or_else ( || Error :: TxNotFound ( txid. to_string ( ) ) ) ?;
320
+ let tx = & txe. tx ;
321
+ let height = acc_store. heights . get ( & txid) . cloned ( ) . flatten ( ) . unwrap_or ( 0 ) ;
322
+ let script_pubkey = tx. output_script ( vout) ;
323
+ let account_path: DerivationPath = acc_store
324
+ . paths
325
+ . get ( & script_pubkey)
326
+ . ok_or_else ( || Error :: Generic ( "can't find derivation path" . into ( ) ) ) ?
327
+ . clone ( ) ;
328
+ let ( is_internal, pointer) = parse_path ( & account_path) ?;
329
+ let satoshi = tx. output_value ( vout, & acc_store. unblinded ) . unwrap_or_default ( ) ;
330
+
331
+ Ok ( UnspentOutput {
332
+ address_type : self . script_type . to_string ( ) ,
333
+ block_height : height,
334
+ pointer : pointer,
335
+ pt_idx : vout,
336
+ txhash : txid. to_hex ( ) ,
337
+ satoshi : satoshi,
338
+ subaccount : self . account_num ,
339
+ is_internal : is_internal,
340
+ confidential : tx. output_is_confidential ( vout) ,
341
+ scriptpubkey : tx. output_script ( vout) ,
342
+ sequence : None ,
343
+ script_code : self . script_code ( & account_path) . to_hex ( ) ,
344
+ user_path : self . get_full_path ( & account_path) . into ( ) ,
345
+ } )
346
+ }
347
+
348
+ pub fn used_utxos ( & self , tx : & BETransaction ) -> Result < Vec < UnspentOutput > , Error > {
349
+ tx. previous_sequence_and_outpoints ( )
350
+ . into_iter ( )
351
+ . map ( |( sequence, outpoint) | {
352
+ self . txo ( & outpoint)
353
+ . map ( |mut u| {
354
+ u. sequence = Some ( sequence) ;
355
+ u
356
+ } )
357
+ . map_err ( |_| Error :: Generic ( "missing inputs not supported yet" . into ( ) ) )
358
+ } )
359
+ . collect ( )
360
+ }
361
+
301
362
pub fn utxos ( & self , num_confs : u32 , confidential_utxos_only : bool ) -> Result < Utxos , Error > {
302
363
info ! ( "start utxos" ) ;
303
364
let store_read = self . store . read ( ) ?;
@@ -1181,6 +1242,7 @@ pub fn create_tx(
1181
1242
* v = v. abs ( ) ;
1182
1243
}
1183
1244
1245
+ let used_utxos = account. used_utxos ( & tx) ?;
1184
1246
let mut created_tx = TransactionMeta :: new (
1185
1247
tx,
1186
1248
None ,
@@ -1193,6 +1255,7 @@ pub fn create_tx(
1193
1255
false ,
1194
1256
SPVVerifyTxResult :: InProgress ,
1195
1257
) ;
1258
+ created_tx. used_utxos = used_utxos;
1196
1259
created_tx. changes_used = Some ( changes. len ( ) as u32 ) ;
1197
1260
created_tx. addressees_read_only = request. previous_transaction . is_some ( ) ;
1198
1261
info ! ( "returning: {:?}" , created_tx) ;
0 commit comments