@@ -116,6 +116,13 @@ pub enum AddressIndex {
116
116
/// caller is untrusted; for example when deriving donation addresses on-demand for a public
117
117
/// web page.
118
118
LastUnused ,
119
+ /// Return the address for the first address in the keychain that has not been used in a received
120
+ /// transaction. Otherwise return a new address as with [`AddressIndex::New`].
121
+ ///
122
+ /// Use with caution, if the wallet has not yet detected an address has been used it could
123
+ /// return an already used address. This function is primarily meant for making use of addresses earlier
124
+ /// in the keychain that were infact never used.
125
+ FirstUnused ,
119
126
/// Return the address for a specific descriptor index. Does not change the current descriptor
120
127
/// index used by `AddressIndex::New` and `AddressIndex::LastUsed`.
121
128
///
@@ -287,7 +294,7 @@ where
287
294
288
295
// Return the the last previously derived address for `keychain` if it has not been used in a
289
296
// received transaction. Otherwise return a new address using [`Wallet::get_new_address`].
290
- fn get_unused_address ( & self , keychain : KeychainKind ) -> Result < AddressInfo , Error > {
297
+ fn get_last_unused_address ( & self , keychain : KeychainKind ) -> Result < AddressInfo , Error > {
291
298
let mut unused_key_indexes = self . get_unused_key_indexes ( keychain) ?;
292
299
match unused_key_indexes. pop ( ) {
293
300
None => self . get_new_address ( keychain) ,
@@ -307,6 +314,26 @@ where
307
314
}
308
315
}
309
316
317
+ // Return the the first address in the keychain which has not been a recipient of a transaction
318
+ fn get_first_unused_address ( & self , keychain : KeychainKind ) -> Result < AddressInfo , Error > {
319
+ let unused_key_indexes = self . get_unused_key_indexes ( keychain) ?;
320
+ if unused_key_indexes. is_empty ( ) {
321
+ self . get_new_address ( keychain)
322
+ } else {
323
+ let derived_key = self
324
+ . get_descriptor_for_keychain ( keychain)
325
+ . as_derived ( unused_key_indexes[ 0 ] , & self . secp ) ;
326
+
327
+ derived_key
328
+ . address ( self . network )
329
+ . map ( |address| AddressInfo {
330
+ address,
331
+ index : unused_key_indexes[ 0 ] ,
332
+ } )
333
+ . map_err ( |_| Error :: ScriptDoesntHaveAddressForm )
334
+ }
335
+ }
336
+
310
337
// Return derived address for the descriptor of given [`KeychainKind`] at a specific index
311
338
fn peek_address ( & self , index : u32 , keychain : KeychainKind ) -> Result < AddressInfo , Error > {
312
339
self . get_descriptor_for_keychain ( keychain)
@@ -353,7 +380,8 @@ where
353
380
) -> Result < AddressInfo , Error > {
354
381
match address_index {
355
382
AddressIndex :: New => self . get_new_address ( keychain) ,
356
- AddressIndex :: LastUnused => self . get_unused_address ( keychain) ,
383
+ AddressIndex :: LastUnused => self . get_last_unused_address ( keychain) ,
384
+ AddressIndex :: FirstUnused => self . get_first_unused_address ( keychain) ,
357
385
AddressIndex :: Peek ( index) => self . peek_address ( index, keychain) ,
358
386
AddressIndex :: Reset ( index) => self . reset_address ( index, keychain) ,
359
387
}
@@ -1638,7 +1666,7 @@ pub(crate) mod test {
1638
1666
1639
1667
use super :: * ;
1640
1668
use crate :: signer:: { SignOptions , SignerError } ;
1641
- use crate :: wallet:: AddressIndex :: { LastUnused , New , Peek , Reset } ;
1669
+ use crate :: wallet:: AddressIndex :: { FirstUnused , LastUnused , New , Peek , Reset } ;
1642
1670
1643
1671
#[ test]
1644
1672
fn test_cache_addresses_fixed ( ) {
@@ -3846,6 +3874,36 @@ pub(crate) mod test {
3846
3874
) ;
3847
3875
}
3848
3876
3877
+ #[ test]
3878
+ fn test_firstunused_address ( ) {
3879
+ let descriptor = "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" ;
3880
+ let descriptors = testutils ! ( @descriptors ( descriptor) ) ;
3881
+ let wallet = Wallet :: new_offline (
3882
+ & descriptors. 0 ,
3883
+ None ,
3884
+ Network :: Testnet ,
3885
+ MemoryDatabase :: new ( ) ,
3886
+ )
3887
+ . unwrap ( ) ;
3888
+
3889
+ assert_eq ! (
3890
+ wallet. get_address( FirstUnused ) . unwrap( ) . to_string( ) ,
3891
+ "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a"
3892
+ ) ;
3893
+
3894
+ // use the first address
3895
+ crate :: populate_test_db!(
3896
+ wallet. database. borrow_mut( ) ,
3897
+ testutils! ( @tx ( ( @external descriptors, 0 ) => 25_000 ) ( @confirmations 1 ) ) ,
3898
+ Some ( 100 ) ,
3899
+ ) ;
3900
+
3901
+ assert_eq ! (
3902
+ wallet. get_address( FirstUnused ) . unwrap( ) . to_string( ) ,
3903
+ "tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7"
3904
+ ) ;
3905
+ }
3906
+
3849
3907
#[ test]
3850
3908
fn test_peek_address_at_index ( ) {
3851
3909
let db = MemoryDatabase :: new ( ) ;
0 commit comments