@@ -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
///
@@ -290,7 +297,7 @@ where
290
297
291
298
// Return the the last previously derived address for `keychain` if it has not been used in a
292
299
// received transaction. Otherwise return a new address using [`Wallet::get_new_address`].
293
- fn get_unused_address ( & self , keychain : KeychainKind ) -> Result < AddressInfo , Error > {
300
+ fn get_last_unused_address ( & self , keychain : KeychainKind ) -> Result < AddressInfo , Error > {
294
301
let mut unused_key_indexes = self . get_unused_key_indexes ( keychain) ?;
295
302
match unused_key_indexes. pop ( ) {
296
303
None => self . get_new_address ( keychain) ,
@@ -324,6 +331,27 @@ where
324
331
}
325
332
}
326
333
334
+ // Return the the first address in the keychain which has not been a recipient of a transaction
335
+ fn get_first_unused_address ( & self , keychain : KeychainKind ) -> Result < AddressInfo , Error > {
336
+ let unused_key_indexes = self . get_unused_key_indexes ( keychain) ?;
337
+ if unused_key_indexes. is_empty ( ) {
338
+ self . get_new_address ( keychain)
339
+ } else {
340
+ let derived_key = self
341
+ . get_descriptor_for_keychain ( keychain)
342
+ . as_derived ( unused_key_indexes[ 0 ] , & self . secp ) ;
343
+
344
+ derived_key
345
+ . address ( self . network )
346
+ . map ( |address| AddressInfo {
347
+ address,
348
+ index : unused_key_indexes[ 0 ] ,
349
+ keychain,
350
+ } )
351
+ . map_err ( |_| Error :: ScriptDoesntHaveAddressForm )
352
+ }
353
+ }
354
+
327
355
// Return derived address for the descriptor of given [`KeychainKind`] at a specific index
328
356
fn peek_address ( & self , index : u32 , keychain : KeychainKind ) -> Result < AddressInfo , Error > {
329
357
self . get_descriptor_for_keychain ( keychain)
@@ -378,7 +406,8 @@ where
378
406
) -> Result < AddressInfo , Error > {
379
407
match address_index {
380
408
AddressIndex :: New => self . get_new_address ( keychain) ,
381
- AddressIndex :: LastUnused => self . get_unused_address ( keychain) ,
409
+ AddressIndex :: LastUnused => self . get_last_unused_address ( keychain) ,
410
+ AddressIndex :: FirstUnused => self . get_first_unused_address ( keychain) ,
382
411
AddressIndex :: Peek ( index) => self . peek_address ( index, keychain) ,
383
412
AddressIndex :: Reset ( index) => self . reset_address ( index, keychain) ,
384
413
}
@@ -1703,7 +1732,7 @@ pub(crate) mod test {
1703
1732
1704
1733
use super :: * ;
1705
1734
use crate :: signer:: { SignOptions , SignerError } ;
1706
- use crate :: wallet:: AddressIndex :: { LastUnused , New , Peek , Reset } ;
1735
+ use crate :: wallet:: AddressIndex :: { FirstUnused , LastUnused , New , Peek , Reset } ;
1707
1736
1708
1737
#[ test]
1709
1738
fn test_cache_addresses_fixed ( ) {
@@ -3911,6 +3940,36 @@ pub(crate) mod test {
3911
3940
) ;
3912
3941
}
3913
3942
3943
+ #[ test]
3944
+ fn test_firstunused_address ( ) {
3945
+ let descriptor = "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" ;
3946
+ let descriptors = testutils ! ( @descriptors ( descriptor) ) ;
3947
+ let wallet = Wallet :: new (
3948
+ & descriptors. 0 ,
3949
+ None ,
3950
+ Network :: Testnet ,
3951
+ MemoryDatabase :: new ( ) ,
3952
+ )
3953
+ . unwrap ( ) ;
3954
+
3955
+ assert_eq ! (
3956
+ wallet. get_address( FirstUnused ) . unwrap( ) . to_string( ) ,
3957
+ "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a"
3958
+ ) ;
3959
+
3960
+ // use the first address
3961
+ crate :: populate_test_db!(
3962
+ wallet. database. borrow_mut( ) ,
3963
+ testutils! ( @tx ( ( @external descriptors, 0 ) => 25_000 ) ( @confirmations 1 ) ) ,
3964
+ Some ( 100 ) ,
3965
+ ) ;
3966
+
3967
+ assert_eq ! (
3968
+ wallet. get_address( FirstUnused ) . unwrap( ) . to_string( ) ,
3969
+ "tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7"
3970
+ ) ;
3971
+ }
3972
+
3914
3973
#[ test]
3915
3974
fn test_peek_address_at_index ( ) {
3916
3975
let db = MemoryDatabase :: new ( ) ;
0 commit comments