@@ -149,24 +149,24 @@ impl From<SyncResponse> for Update {
149
149
/// A derived address and the index it was found at.
150
150
/// For convenience this automatically derefs to `Address`
151
151
#[ derive( Debug , Clone , PartialEq , Eq ) ]
152
- pub struct AddressInfo {
152
+ pub struct AddressInfo < K > {
153
153
/// Child index of this address
154
154
pub index : u32 ,
155
155
/// Address
156
156
pub address : Address ,
157
157
/// Type of keychain
158
- pub keychain : KeychainKind ,
158
+ pub keychain : K ,
159
159
}
160
160
161
- impl Deref for AddressInfo {
161
+ impl < K > Deref for AddressInfo < K > {
162
162
type Target = Address ;
163
163
164
164
fn deref ( & self ) -> & Self :: Target {
165
165
& self . address
166
166
}
167
167
}
168
168
169
- impl fmt:: Display for AddressInfo {
169
+ impl < K > fmt:: Display for AddressInfo < K > {
170
170
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
171
171
write ! ( f, "{}" , self . address)
172
172
}
@@ -353,6 +353,77 @@ where
353
353
stage,
354
354
}
355
355
}
356
+
357
+ /// Reveal the next address of the default `keychain`.
358
+ ///
359
+ /// This is equivalent to calling [`Self::reveal_next_address`] with the default `keychain` as
360
+ /// argument. Note: This is not fallible as the default keychain must always exist!
361
+ ///
362
+ /// **WARNING**: To avoid address reuse you must persist the changes resulting from one or more
363
+ /// calls to this method before closing the wallet. For example:
364
+ // TODO: Fix the following example:
365
+ // ///
366
+ // /// ```rust,no_run
367
+ // /// # use bdk_wallet::{LoadParams, ChangeSet, KeychainKind};
368
+ // /// use bdk_chain::rusqlite::Connection;
369
+ // /// let mut conn = Connection::open_in_memory().expect("must open connection");
370
+ // /// let mut wallet = LoadParams::new()
371
+ // /// .load_wallet(&mut conn)
372
+ // /// .expect("database is okay")
373
+ // /// .expect("database has data");
374
+ // /// let next_address = wallet.reveal_next_address(KeychainKind::External);
375
+ // /// wallet.persist(&mut conn).expect("write is okay");
376
+ // ///
377
+ // /// // Now it's safe to show the user their next address!
378
+ // /// println!("Next address: {}", next_address.address);
379
+ // /// # Ok::<(), anyhow::Error>(())
380
+ // /// ```
381
+ pub fn reveal_next_default_address ( & mut self ) -> AddressInfo < K > {
382
+ self . reveal_next_address ( self . keyring . default_keychain ( ) )
383
+ . expect ( "default keychain must always exist!" )
384
+ }
385
+
386
+ /// Attempt to reveal the next address of the given `keychain`.
387
+ ///
388
+ /// This will increment the keychain's derivation index. If the keychain's descriptor doesn't
389
+ /// contain a wildcard or every address is already revealed up to the maximum derivation
390
+ /// index defined in [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki),
391
+ /// then the last revealed address will be returned.
392
+ ///
393
+ /// **WARNING**: To avoid address reuse you must persist the changes resulting from one or more
394
+ /// calls to this method before closing the wallet. For example:
395
+ // TODO: Fix the following example:
396
+ // ///
397
+ // /// ```rust,no_run
398
+ // /// # use bdk_wallet::{LoadParams, ChangeSet, KeychainKind};
399
+ // /// use bdk_chain::rusqlite::Connection;
400
+ // /// let mut conn = Connection::open_in_memory().expect("must open connection");
401
+ // /// let mut wallet = LoadParams::new()
402
+ // /// .load_wallet(&mut conn)
403
+ // /// .expect("database is okay")
404
+ // /// .expect("database has data");
405
+ // /// let next_address = wallet.reveal_next_address(KeychainKind::External);
406
+ // /// wallet.persist(&mut conn).expect("write is okay");
407
+ // ///
408
+ // /// // Now it's safe to show the user their next address!
409
+ // /// println!("Next address: {}", next_address.address);
410
+ // /// # Ok::<(), anyhow::Error>(())
411
+ // /// ```
412
+ pub fn reveal_next_address ( & mut self , keychain : K ) -> Option < AddressInfo < K > > {
413
+ let index = & mut self . tx_graph . index ;
414
+ let stage = & mut self . stage ;
415
+
416
+ let ( ( index, spk) , index_changeset) = index. reveal_next_spk ( keychain. clone ( ) ) ?;
417
+
418
+ stage. merge ( index_changeset. into ( ) ) ;
419
+
420
+ Some ( AddressInfo {
421
+ index,
422
+ address : Address :: from_script ( spk. as_script ( ) , self . keyring . network )
423
+ . expect ( "must have address form" ) ,
424
+ keychain,
425
+ } )
426
+ }
356
427
}
357
428
358
429
// impl Wallet {
@@ -2861,6 +2932,82 @@ mod test {
2861
2932
// use crate::miniscript::Error::Unexpected;
2862
2933
// use crate::test_utils::get_test_tr_single_sig_xprv_and_change_desc;
2863
2934
// use crate::test_utils::insert_tx;
2935
+ use bdk_chain:: DescriptorId ;
2936
+ use core:: str:: FromStr ;
2937
+ use miniscript:: { Descriptor , DescriptorPublicKey } ;
2938
+
2939
+ const DESCRIPTORS : [ & str ; 6 ] = [
2940
+ "wpkh(tpubDCzuCBKnZA5TNKhiJnASku7kq8Q4iqcVF82JV7mHo2NxWpXkLRbrJaGA5ToE7LCuWpcPErBbpDzbdWKN8aTdJzmRy1jQPmZvnqpwwDwCdy7/1/*)" ,
2941
+ "wpkh(tpubDCzuCBKnZA5TNKhiJnASku7kq8Q4iqcVF82JV7mHo2NxWpXkLRbrJaGA5ToE7LCuWpcPErBbpDzbdWKN8aTdJzmRy1jQPmZvnqpwwDwCdy7/2/*)" ,
2942
+ "tr(tpubDCzuCBKnZA5TNKhiJnASku7kq8Q4iqcVF82JV7mHo2NxWpXkLRbrJaGA5ToE7LCuWpcPErBbpDzbdWKN8aTdJzmRy1jQPmZvnqpwwDwCdy7/3/*)" ,
2943
+ "tr(tpubDCzuCBKnZA5TNKhiJnASku7kq8Q4iqcVF82JV7mHo2NxWpXkLRbrJaGA5ToE7LCuWpcPErBbpDzbdWKN8aTdJzmRy1jQPmZvnqpwwDwCdy7/4/*)" ,
2944
+ "pkh(tpubDCzuCBKnZA5TNKhiJnASku7kq8Q4iqcVF82JV7mHo2NxWpXkLRbrJaGA5ToE7LCuWpcPErBbpDzbdWKN8aTdJzmRy1jQPmZvnqpwwDwCdy7/5/*)" ,
2945
+ "pkh(tpubDCzuCBKnZA5TNKhiJnASku7kq8Q4iqcVF82JV7mHo2NxWpXkLRbrJaGA5ToE7LCuWpcPErBbpDzbdWKN8aTdJzmRy1jQPmZvnqpwwDwCdy7/6/*)" ] ;
2946
+
2947
+ /// Parse a descriptor string
2948
+ fn parse_descriptor ( s : & str ) -> Descriptor < DescriptorPublicKey > {
2949
+ Descriptor :: parse_descriptor ( & Secp256k1 :: new ( ) , s)
2950
+ . expect ( "failed to parse descriptor" )
2951
+ . 0
2952
+ }
2953
+
2954
+ fn test_keyring ( desc_strs : impl IntoIterator < Item = & ' static str > ) -> KeyRing < DescriptorId > {
2955
+ let mut desc_strs = desc_strs. into_iter ( ) ;
2956
+ let desc = parse_descriptor ( desc_strs. next ( ) . unwrap ( ) ) ;
2957
+ let mut keyring = KeyRing :: new ( Network :: Testnet4 , desc. descriptor_id ( ) , desc) ;
2958
+ for desc_str in desc_strs {
2959
+ let desc = parse_descriptor ( desc_str) ;
2960
+ keyring. add_descriptor ( desc. descriptor_id ( ) , desc, false ) ;
2961
+ }
2962
+ keyring
2963
+ }
2964
+
2965
+ #[ test]
2966
+ fn correct_address_is_revealed ( ) {
2967
+ let mut wallet = Wallet :: new ( test_keyring ( DESCRIPTORS ) ) ;
2968
+ let addrinfo = wallet. reveal_next_default_address ( ) ;
2969
+ assert_eq ! (
2970
+ addrinfo. address. into_unchecked( ) ,
2971
+ Address :: from_str( "tb1qat8h88r778d8e0x38t2ljtzmgkjusgn2u38avs" ) . unwrap( )
2972
+ ) ;
2973
+ let addrinfo = wallet
2974
+ . reveal_next_address ( parse_descriptor ( DESCRIPTORS [ 1 ] ) . descriptor_id ( ) )
2975
+ . unwrap ( ) ;
2976
+ assert_eq ! (
2977
+ addrinfo. address. into_unchecked( ) ,
2978
+ Address :: from_str( "tb1qun8txyd3p4xgts6y6lj8h2dcxk20s487ll7ss3" ) . unwrap( )
2979
+ ) ;
2980
+ let addrinfo = wallet
2981
+ . reveal_next_address ( parse_descriptor ( DESCRIPTORS [ 2 ] ) . descriptor_id ( ) )
2982
+ . unwrap ( ) ;
2983
+ assert_eq ! (
2984
+ addrinfo. address. into_unchecked( ) ,
2985
+ Address :: from_str( "tb1pnz3jex4wnz88e46rfzckpd9xyvdde8h2hnes4wrllkhygump8c2se9rusg" )
2986
+ . unwrap( )
2987
+ ) ;
2988
+ let addrinfo = wallet
2989
+ . reveal_next_address ( parse_descriptor ( DESCRIPTORS [ 3 ] ) . descriptor_id ( ) )
2990
+ . unwrap ( ) ;
2991
+ assert_eq ! (
2992
+ addrinfo. address. into_unchecked( ) ,
2993
+ Address :: from_str( "tb1pv6hmnghp0wtxzeqsvshdq4ennvmqg3eq78vluvzvfkqtmtd5e49q8zht5v" )
2994
+ . unwrap( )
2995
+ ) ;
2996
+ let addrinfo = wallet
2997
+ . reveal_next_address ( parse_descriptor ( DESCRIPTORS [ 4 ] ) . descriptor_id ( ) )
2998
+ . unwrap ( ) ;
2999
+ assert_eq ! (
3000
+ addrinfo. address. into_unchecked( ) ,
3001
+ Address :: from_str( "n3TJoFpLPBMGisVYHUGcEBwd9d1FVBwbJQ" ) . unwrap( )
3002
+ ) ;
3003
+ let addrinfo = wallet
3004
+ . reveal_next_address ( parse_descriptor ( DESCRIPTORS [ 5 ] ) . descriptor_id ( ) )
3005
+ . unwrap ( ) ;
3006
+ assert_eq ! (
3007
+ addrinfo. address. into_unchecked( ) ,
3008
+ Address :: from_str( "mq2r39CD8ZnMqyuytQq2zPa1sfHTT6Rjo8" ) . unwrap( )
3009
+ ) ;
3010
+ }
2864
3011
2865
3012
// #[test]
2866
3013
// fn not_duplicated_utxos_across_optional_and_required() {
0 commit comments