@@ -17,7 +17,7 @@ use bip39::rand::thread_rng;
1717
1818use elements_miniscript:: {
1919 ConfidentialDescriptor , Descriptor , DescriptorPublicKey ,
20- bitcoin:: { NetworkKind , PrivateKey , PublicKey , bip32:: DerivationPath } ,
20+ bitcoin:: { PrivateKey , PublicKey , bip32:: DerivationPath } ,
2121 elements:: {
2222 EcdsaSighashType ,
2323 bitcoin:: bip32:: { Fingerprint , Xpriv , Xpub } ,
@@ -121,22 +121,23 @@ enum Estimate {
121121 Failure ( u64 ) ,
122122}
123123
124+ // TODO: refactor descriptors to be a standalone object to specify custom derivation paths.
124125impl Signer {
125126 /// Creates a new `Signer` instance seeded from the provided mnemonic and paired with the specified provider.
126127 ///
127128 /// # Panics
128129 /// Panics if the mnemonic fails to parse, or if deriving the master private key fails.
129130 #[ must_use]
130131 pub fn new ( mnemonic : & str , provider : Box < dyn ProviderTrait > ) -> Self {
132+ let network = * provider. get_network ( ) ;
131133 let secp = Secp256k1 :: new ( ) ;
132134 let mnemonic: Mnemonic = mnemonic
133135 . parse ( )
134136 . map_err ( |e : bip39:: Error | SignerError :: Mnemonic ( e. to_string ( ) ) )
135137 . unwrap ( ) ;
136- let seed = mnemonic. to_seed ( "" ) ;
137- let xprv = Xpriv :: new_master ( NetworkKind :: Test , & seed) . unwrap ( ) ;
138138
139- let network = * provider. get_network ( ) ;
139+ let seed = mnemonic. to_seed ( "" ) ;
140+ let xprv = Xpriv :: new_master ( network, & seed) . unwrap ( ) ;
140141
141142 Self {
142143 mnemonic,
@@ -278,7 +279,7 @@ impl Signer {
278279 descriptor. descriptor = descriptor. descriptor . into_single_descriptors ( ) . unwrap ( ) [ 0 ] . clone ( ) ;
279280
280281 descriptor
281- . at_derivation_index ( 1 )
282+ . at_derivation_index ( 0 )
282283 . unwrap ( )
283284 . address ( & self . secp , self . network . address_params ( ) )
284285 . unwrap ( )
@@ -295,7 +296,7 @@ impl Signer {
295296 . unwrap ( ) ;
296297
297298 descriptor. into_single_descriptors ( ) . unwrap ( ) [ 0 ]
298- . at_derivation_index ( 1 )
299+ . at_derivation_index ( 0 )
299300 . unwrap ( )
300301 . address ( self . network . address_params ( ) )
301302 . unwrap ( )
@@ -390,19 +391,19 @@ impl Signer {
390391 let full_path = self . get_derivation_path ( ) . unwrap ( ) ;
391392
392393 let derived = full_path. extend (
393- DerivationPath :: from_str ( "0/1 " )
394+ DerivationPath :: from_str ( "0/0 " )
394395 . map_err ( |e| SignerError :: DerivationPath ( e. to_string ( ) ) )
395396 . unwrap ( ) ,
396397 ) ;
397398
398399 let ext_derived = master_xprv. derive_priv ( & self . secp , & derived) . unwrap ( ) ;
399400
400- PrivateKey :: new ( ext_derived. private_key , NetworkKind :: Test )
401+ PrivateKey :: new ( ext_derived. private_key , self . network )
401402 }
402403
403404 /// Generates the private key linked to confidential payload blinding.
404405 ///
405- /// The generated `PrivateKey` is associated with the `Test` (non-Bitcoin-mainnet) network kind.
406+ /// The generated `PrivateKey` is associated with the `Test` (non-Bitcoin/Liquid -mainnet) network kind.
406407 /// Retrieves the blinding private key derived from the master SLIP77 key and the script public key of the address.
407408 ///
408409 /// # Panics
@@ -414,7 +415,7 @@ impl Signer {
414415 . unwrap ( )
415416 . blinding_private_key ( & self . get_address ( ) . script_pubkey ( ) ) ;
416417
417- PrivateKey :: new ( blinding_key, NetworkKind :: Test )
418+ PrivateKey :: new ( blinding_key, self . network )
418419 }
419420
420421 fn unblind ( & self , utxos : Vec < UTXO > ) -> Result < Vec < UTXO > , SignerError > {
@@ -440,12 +441,14 @@ impl Signer {
440441 ) -> Result < Estimate , SignerError > {
441442 // estimate the tx fee with the change
442443 // use this wpkh address as a change script
443- // TODO: this should be confidential
444- fee_tx. add_output ( PartialOutput :: new (
445- self . get_address ( ) . script_pubkey ( ) ,
446- PLACEHOLDER_FEE ,
447- self . network . policy_asset ( ) ,
448- ) ) ;
444+ fee_tx. add_output (
445+ PartialOutput :: new (
446+ self . get_address ( ) . script_pubkey ( ) ,
447+ PLACEHOLDER_FEE ,
448+ self . network . policy_asset ( ) ,
449+ )
450+ . with_blinding_key ( self . get_blinding_public_key ( ) ) ,
451+ ) ;
449452
450453 fee_tx. add_output ( PartialOutput :: new (
451454 Script :: new ( ) ,
@@ -469,6 +472,10 @@ impl Signer {
469472 }
470473
471474 // not enough funds, so we need to estimate without the change
475+ // TODO: if a UTXO being spent is confidential + there are no
476+ // confidential outputs + there is no change, this will fail
477+ // with `RPC error -26: bad-txns-in-ne-out, value in != value out`.
478+ // Fix this by adding a dummy change or throwing a clear error.
472479 fee_tx. remove_output ( fee_tx. n_outputs ( ) - 2 ) ;
473480
474481 let final_tx = self . sign_tx ( & fee_tx) ?;
@@ -624,7 +631,10 @@ impl Signer {
624631 fn get_wpkh_descriptor ( & self ) -> Result < String , SignerError > {
625632 let fingerprint = self . fingerprint ( ) ?;
626633 let path = self . get_derivation_path ( ) ?;
627- let xpub = self . derive_xpub ( & path) ?;
634+ let mut xpub = self . derive_xpub ( & path) ?;
635+
636+ // TODO: Blockstream app does this. Is this a bug?
637+ xpub. parent_fingerprint = Fingerprint :: default ( ) ;
628638
629639 Ok ( format ! ( "elwpkh([{fingerprint}/{path}]{xpub}/<0;1>/*)" ) )
630640 }
@@ -646,7 +656,7 @@ mod tests {
646656
647657 fn create_signer ( ) -> Signer {
648658 let url = "https://blockstream.info/liquidtestnet/api" . to_string ( ) ;
649- let network = SimplicityNetwork :: LiquidTestnet ;
659+ let network = SimplicityNetwork :: Liquid ;
650660
651661 Signer :: new ( random_mnemonic ( ) . as_str ( ) , Box :: new ( EsploraProvider :: new ( url, network) ) )
652662 }
0 commit comments