1use crate::error::{
2 AddressParseError, Bip32Error, ExtractTxError, FeeRateError, FromScriptError, HashParseError,
3 PsbtError, PsbtParseError, TransactionError,
4};
5use crate::error::{ParseAmountError, PsbtFinalizeError};
6use crate::keys::DerivationPath;
7
8use crate::{impl_from_core_type, impl_hash_like, impl_into_core_type};
9use bdk_wallet::bitcoin::address::NetworkChecked;
10use bdk_wallet::bitcoin::address::NetworkUnchecked;
11use bdk_wallet::bitcoin::address::{Address as BdkAddress, AddressData as BdkAddressData};
12use bdk_wallet::bitcoin::bip32::ChildNumber as BdkChildNumber;
13use bdk_wallet::bitcoin::blockdata::block::Block as BdkBlock;
14use bdk_wallet::bitcoin::blockdata::block::Header as BdkHeader;
15use bdk_wallet::bitcoin::consensus::encode::deserialize;
16use bdk_wallet::bitcoin::consensus::encode::serialize;
17use bdk_wallet::bitcoin::consensus::Decodable;
18use bdk_wallet::bitcoin::hashes::sha256::Hash as BitcoinSha256Hash;
19use bdk_wallet::bitcoin::hashes::sha256d::Hash as BitcoinDoubleSha256Hash;
20use bdk_wallet::bitcoin::io::Cursor;
21use bdk_wallet::bitcoin::psbt::Input as BdkInput;
22use bdk_wallet::bitcoin::psbt::Output as BdkOutput;
23use bdk_wallet::bitcoin::secp256k1::Secp256k1;
24use bdk_wallet::bitcoin::taproot::LeafNode as BdkLeafNode;
25use bdk_wallet::bitcoin::taproot::NodeInfo as BdkNodeInfo;
26use bdk_wallet::bitcoin::taproot::TapTree as BdkTapTree;
27use bdk_wallet::bitcoin::Amount as BdkAmount;
28use bdk_wallet::bitcoin::BlockHash as BitcoinBlockHash;
29use bdk_wallet::bitcoin::FeeRate as BdkFeeRate;
30use bdk_wallet::bitcoin::OutPoint as BdkOutPoint;
31use bdk_wallet::bitcoin::Psbt as BdkPsbt;
32use bdk_wallet::bitcoin::ScriptBuf as BdkScriptBuf;
33use bdk_wallet::bitcoin::Transaction as BdkTransaction;
34use bdk_wallet::bitcoin::TxIn as BdkTxIn;
35use bdk_wallet::bitcoin::TxOut as BdkTxOut;
36use bdk_wallet::bitcoin::Txid as BitcoinTxid;
37use bdk_wallet::bitcoin::Weight;
38use bdk_wallet::bitcoin::Wtxid as BitcoinWtxid;
39use bdk_wallet::miniscript::psbt::PsbtExt;
40use bdk_wallet::serde_json;
41
42use std::collections::HashMap;
43use std::convert::TryFrom;
44use std::fmt::Display;
45use std::fs::File;
46use std::io::{BufReader, BufWriter};
47use std::ops::Deref;
48use std::str::FromStr;
49use std::sync::{Arc, Mutex};
50
51pub type DescriptorType = bdk_wallet::miniscript::descriptor::DescriptorType;
52pub type Network = bdk_wallet::bitcoin::Network;
53pub(crate) type NetworkKind = bdk_wallet::bitcoin::NetworkKind;
54
55#[uniffi::remote(Enum)]
57pub enum NetworkKind {
58 Main,
60 Test,
62}
63
64#[derive(Debug, Clone, Eq, PartialEq, std::hash::Hash, uniffi:: Record)]
66pub struct OutPoint {
67 pub txid: Arc<Txid>,
69 pub vout: u32,
71}
72
73impl From<&BdkOutPoint> for OutPoint {
74 fn from(outpoint: &BdkOutPoint) -> Self {
75 OutPoint {
76 txid: Arc::new(Txid(outpoint.txid)),
77 vout: outpoint.vout,
78 }
79 }
80}
81
82impl From<BdkOutPoint> for OutPoint {
83 fn from(value: BdkOutPoint) -> Self {
84 Self {
85 txid: Arc::new(Txid(value.txid)),
86 vout: value.vout,
87 }
88 }
89}
90
91impl From<OutPoint> for BdkOutPoint {
92 fn from(outpoint: OutPoint) -> Self {
93 BdkOutPoint {
94 txid: BitcoinTxid::from_raw_hash(outpoint.txid.0.to_raw_hash()),
95 vout: outpoint.vout,
96 }
97 }
98}
99
100#[uniffi::remote(Enum)]
110pub enum Network {
111 Bitcoin,
112 Testnet,
113 Testnet4,
114 Signet,
115 Regtest,
116}
117
118#[derive(Debug, PartialEq, Eq, std::hash::Hash, uniffi::Object)]
123#[uniffi::export(Debug, Eq, Hash)]
124pub struct HashableOutPoint(pub(crate) OutPoint);
125
126#[uniffi::export]
127impl HashableOutPoint {
128 #[uniffi::constructor]
130 pub fn new(outpoint: OutPoint) -> Self {
131 Self(outpoint)
132 }
133
134 pub fn outpoint(&self) -> OutPoint {
136 self.0.clone()
137 }
138}
139
140#[derive(Clone, Debug, uniffi::Object)]
145#[uniffi::export(Display)]
146pub struct FeeRate(pub(crate) BdkFeeRate);
147
148#[uniffi::export]
149impl FeeRate {
150 #[uniffi::constructor]
152 pub fn from_sat_per_vb(sat_vb: u64) -> Result<Self, FeeRateError> {
153 let fee_rate: Option<BdkFeeRate> = BdkFeeRate::from_sat_per_vb(sat_vb);
154 match fee_rate {
155 Some(fee_rate) => Ok(FeeRate(fee_rate)),
156 None => Err(FeeRateError::ArithmeticOverflow),
157 }
158 }
159
160 #[uniffi::constructor]
162 pub fn from_sat_per_kwu(sat_kwu: u64) -> Self {
163 FeeRate(BdkFeeRate::from_sat_per_kwu(sat_kwu))
164 }
165
166 pub fn to_sat_per_vb_ceil(&self) -> u64 {
168 self.0.to_sat_per_vb_ceil()
169 }
170
171 pub fn to_sat_per_vb_floor(&self) -> u64 {
173 self.0.to_sat_per_vb_floor()
174 }
175
176 pub fn to_sat_per_kwu(&self) -> u64 {
178 self.0.to_sat_per_kwu()
179 }
180
181 pub fn fee_vb(&self, vb: u64) -> Option<Arc<Amount>> {
185 let rust_amount: BdkAmount = self.0.fee_vb(vb)?;
186 let amount: Amount = rust_amount.into();
187 Some(Arc::new(amount))
188
189 }
194
195 pub fn fee_wu(&self, wu: u64) -> Option<Arc<Amount>> {
199 let weight: Weight = Weight::from_wu(wu);
200 let rust_amount: BdkAmount = self.0.fee_wu(weight)?;
201 let amount: Amount = rust_amount.into();
202 Some(Arc::new(amount))
203 }
204}
205
206impl Display for FeeRate {
207 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
208 write!(f, "{:#}", self.0)
209 }
210}
211
212impl_from_core_type!(BdkFeeRate, FeeRate);
213impl_into_core_type!(FeeRate, BdkFeeRate);
214
215#[derive(Debug, Clone, PartialEq, Eq, uniffi::Object)]
220pub struct Amount(pub(crate) BdkAmount);
221
222#[uniffi::export]
223impl Amount {
224 #[uniffi::constructor]
226 pub fn from_sat(satoshi: u64) -> Self {
227 Amount(BdkAmount::from_sat(satoshi))
228 }
229
230 #[uniffi::constructor]
232 pub fn from_btc(btc: f64) -> Result<Self, ParseAmountError> {
233 let bitcoin_amount = BdkAmount::from_btc(btc).map_err(ParseAmountError::from)?;
234 Ok(Amount(bitcoin_amount))
235 }
236
237 pub fn to_sat(&self) -> u64 {
239 self.0.to_sat()
240 }
241
242 pub fn to_btc(&self) -> f64 {
245 self.0.to_btc()
246 }
247}
248
249impl_from_core_type!(BdkAmount, Amount);
250impl_into_core_type!(Amount, BdkAmount);
251
252#[derive(Clone, Debug, uniffi::Object)]
254#[uniffi::export(Display)]
255pub struct Script(pub(crate) BdkScriptBuf);
256
257#[uniffi::export]
258impl Script {
259 #[uniffi::constructor]
261 pub fn new(raw_output_script: Vec<u8>) -> Self {
262 let script: BdkScriptBuf = raw_output_script.into();
263 Script(script)
264 }
265
266 pub fn to_bytes(&self) -> Vec<u8> {
268 self.0.to_bytes()
269 }
270}
271
272impl_from_core_type!(BdkScriptBuf, Script);
273impl_into_core_type!(Script, BdkScriptBuf);
274
275impl Display for Script {
276 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
277 self.0.fmt_asm(f)
278 }
279}
280
281#[derive(uniffi::Record)]
285pub struct Header {
286 pub version: i32,
288 pub prev_blockhash: Arc<BlockHash>,
290 pub merkle_root: Arc<TxMerkleNode>,
292 pub time: u32,
294 pub bits: u32,
296 pub nonce: u32,
298}
299
300impl From<BdkHeader> for Header {
301 fn from(bdk_header: BdkHeader) -> Self {
302 Header {
303 version: bdk_header.version.to_consensus(),
304 prev_blockhash: Arc::new(BlockHash(bdk_header.prev_blockhash)),
305 merkle_root: Arc::new(TxMerkleNode(bdk_header.merkle_root.to_raw_hash())),
306 time: bdk_header.time,
307 bits: bdk_header.bits.to_consensus(),
308 nonce: bdk_header.nonce,
309 }
310 }
311}
312
313#[derive(uniffi::Record)]
316pub struct Block {
317 pub header: Header,
318 pub txdata: Vec<Arc<Transaction>>,
319}
320
321impl From<BdkBlock> for Block {
322 fn from(bdk_block: BdkBlock) -> Self {
323 Block {
324 header: bdk_block.header.into(),
325 txdata: bdk_block
326 .txdata
327 .into_iter()
328 .map(|tx| Arc::new(tx.into()))
329 .collect(),
330 }
331 }
332}
333
334#[derive(Debug, uniffi::Enum)]
336pub enum AddressData {
337 P2pkh { pubkey_hash: String },
339 P2sh { script_hash: String },
341 Segwit { witness_program: WitnessProgram },
343}
344
345#[derive(Debug, uniffi::Record)]
347pub struct WitnessProgram {
348 pub version: u8,
350 pub program: Vec<u8>,
352}
353
354#[derive(Debug, PartialEq, Eq, uniffi::Object)]
356#[uniffi::export(Eq, Display)]
357pub struct Address(pub(crate) BdkAddress<NetworkChecked>);
358
359#[uniffi::export]
360impl Address {
361 #[uniffi::constructor]
363 pub fn new(address: String, network: Network) -> Result<Self, AddressParseError> {
364 let parsed_address = address.parse::<bdk_wallet::bitcoin::Address<NetworkUnchecked>>()?;
365 let network_checked_address = parsed_address.require_network(network)?;
366
367 Ok(Address(network_checked_address))
368 }
369
370 #[uniffi::constructor]
372 pub fn from_script(script: Arc<Script>, network: Network) -> Result<Self, FromScriptError> {
373 let address = BdkAddress::from_script(&script.0.clone(), network)?;
374
375 Ok(Address(address))
376 }
377
378 pub fn script_pubkey(&self) -> Arc<Script> {
380 Arc::new(Script(self.0.script_pubkey()))
381 }
382
383 pub fn to_qr_uri(&self) -> String {
385 self.0.to_qr_uri()
386 }
387
388 pub fn is_valid_for_network(&self, network: Network) -> bool {
390 let address_str = self.0.to_string();
391 if let Ok(unchecked_address) = address_str.parse::<BdkAddress<NetworkUnchecked>>() {
392 unchecked_address.is_valid_for_network(network)
393 } else {
394 false
395 }
396 }
397
398 pub fn to_address_data(&self) -> AddressData {
400 match self.0.to_address_data() {
401 BdkAddressData::P2pkh { pubkey_hash } => AddressData::P2pkh {
402 pubkey_hash: pubkey_hash.to_string(),
403 },
404 BdkAddressData::P2sh { script_hash } => AddressData::P2sh {
405 script_hash: script_hash.to_string(),
406 },
407 BdkAddressData::Segwit { witness_program } => AddressData::Segwit {
408 witness_program: WitnessProgram {
409 version: witness_program.version().to_num(),
410 program: witness_program.program().as_bytes().to_vec(),
411 },
412 },
413 _ => unimplemented!("Unsupported address type"),
415 }
416 }
417}
418
419impl Display for Address {
420 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
421 write!(f, "{}", self.0)
422 }
423}
424
425impl_from_core_type!(BdkAddress, Address);
426impl_into_core_type!(Address, BdkAddress);
427
428#[derive(Debug, Clone, PartialEq, Eq, uniffi::Object)]
431#[uniffi::export(Eq, Display)]
432pub struct Transaction(BdkTransaction);
433
434#[uniffi::export]
435impl Transaction {
436 #[uniffi::constructor]
438 pub fn new(transaction_bytes: Vec<u8>) -> Result<Self, TransactionError> {
439 let mut decoder = Cursor::new(transaction_bytes);
440 let tx: BdkTransaction = BdkTransaction::consensus_decode(&mut decoder)?;
441 Ok(Transaction(tx))
442 }
443
444 pub fn compute_txid(&self) -> Arc<Txid> {
447 Arc::new(Txid(self.0.compute_txid()))
448 }
449
450 pub fn compute_wtxid(&self) -> Arc<Wtxid> {
452 Arc::new(Wtxid(self.0.compute_wtxid()))
453 }
454
455 #[inline]
474 pub fn weight(&self) -> u64 {
475 self.0.weight().to_wu()
476 }
477
478 pub fn total_size(&self) -> u64 {
483 self.0.total_size() as u64
484 }
485
486 #[inline]
494 pub fn vsize(&self) -> u64 {
495 self.0.vsize() as u64
496 }
497
498 pub fn is_coinbase(&self) -> bool {
503 self.0.is_coinbase()
504 }
505
506 pub fn is_explicitly_rbf(&self) -> bool {
516 self.0.is_explicitly_rbf()
517 }
518
519 pub fn is_lock_time_enabled(&self) -> bool {
523 self.0.is_lock_time_enabled()
524 }
525
526 pub fn version(&self) -> i32 {
528 self.0.version.0
529 }
530
531 pub fn serialize(&self) -> Vec<u8> {
533 serialize(&self.0)
534 }
535
536 pub fn input(&self) -> Vec<TxIn> {
538 self.0.input.iter().map(|tx_in| tx_in.into()).collect()
539 }
540
541 pub fn output(&self) -> Vec<TxOut> {
543 self.0.output.iter().map(|tx_out| tx_out.into()).collect()
544 }
545
546 pub fn lock_time(&self) -> u32 {
553 self.0.lock_time.to_consensus_u32()
554 }
555}
556
557impl From<BdkTransaction> for Transaction {
558 fn from(tx: BdkTransaction) -> Self {
559 Transaction(tx)
560 }
561}
562
563impl From<&BdkTransaction> for Transaction {
564 fn from(tx: &BdkTransaction) -> Self {
565 Transaction(tx.clone())
566 }
567}
568
569impl From<&Transaction> for BdkTransaction {
570 fn from(tx: &Transaction) -> Self {
571 tx.0.clone()
572 }
573}
574
575impl Display for Transaction {
576 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
577 write!(f, "{:?}", self.0)
578 }
579}
580
581#[derive(Clone, Debug, uniffi::Record)]
582pub struct TapScriptEntry {
583 pub script: Arc<Script>,
585 pub leaf_version: u8,
587}
588
589#[derive(Clone, Debug, uniffi::Record)]
590pub struct TapKeyOrigin {
591 pub tap_leaf_hashes: Vec<String>,
593 pub key_source: KeySource,
595}
596
597#[derive(Clone, Debug, uniffi::Record)]
598pub struct KeySource {
599 pub fingerprint: String,
601 pub path: Arc<DerivationPath>,
603}
604
605#[derive(Clone, Debug, Hash, Eq, PartialEq, uniffi::Record)]
606pub struct Key {
607 pub type_value: u8,
609 pub key: Vec<u8>,
612}
613
614#[derive(Clone, Debug, Hash, Eq, PartialEq, uniffi::Record)]
615pub struct ProprietaryKey {
616 pub prefix: Vec<u8>,
619 pub subtype: u8,
621 pub key: Vec<u8>,
623}
624
625#[derive(Clone, Debug, Hash, Eq, PartialEq, uniffi::Record)]
626pub struct ControlBlock {
627 pub internal_key: Vec<u8>,
629 pub merkle_branch: Vec<String>,
631 pub output_key_parity: u8,
633 pub leaf_version: u8,
635}
636
637#[derive(Clone, Debug, Hash, Eq, PartialEq, uniffi::Record)]
638pub struct TapScriptSigKey {
639 pub xonly_pubkey: String,
641 pub tap_leaf_hash: String,
644}
645
646#[derive(Clone, Debug, uniffi::Record)]
648pub struct Input {
649 pub non_witness_utxo: Option<Arc<Transaction>>,
653 pub witness_utxo: Option<TxOut>,
657 pub partial_sigs: HashMap<String, Vec<u8>>,
660 pub sighash_type: Option<String>,
663 pub redeem_script: Option<Arc<Script>>,
665 pub witness_script: Option<Arc<Script>>,
667 pub bip32_derivation: HashMap<String, KeySource>,
670
671 pub final_script_sig: Option<Arc<Script>>,
674
675 pub final_script_witness: Option<Vec<Vec<u8>>>,
678 pub ripemd160_preimages: HashMap<String, Vec<u8>>,
680 pub sha256_preimages: HashMap<String, Vec<u8>>,
682 pub hash160_preimages: HashMap<String, Vec<u8>>,
684 pub hash256_preimages: HashMap<String, Vec<u8>>,
686 pub tap_key_sig: Option<Vec<u8>>,
688 pub tap_script_sigs: HashMap<TapScriptSigKey, Vec<u8>>,
690 pub tap_scripts: HashMap<ControlBlock, TapScriptEntry>,
692 pub tap_key_origins: HashMap<String, TapKeyOrigin>,
694 pub tap_internal_key: Option<String>,
696 pub tap_merkle_root: Option<String>,
698 pub proprietary: HashMap<ProprietaryKey, Vec<u8>>,
700 pub unknown: HashMap<Key, Vec<u8>>,
702}
703
704use crate::error::AddForeignUtxoError;
705
706impl From<&BdkInput> for Input {
707 fn from(input: &BdkInput) -> Self {
708 Input {
709 non_witness_utxo: input
710 .non_witness_utxo
711 .as_ref()
712 .map(|tx| Arc::new(Transaction(tx.clone()))),
713 witness_utxo: input.witness_utxo.as_ref().map(TxOut::from),
714 partial_sigs: input
715 .partial_sigs
716 .iter()
717 .map(|(k, v)| (k.to_string(), v.to_vec()))
718 .collect(),
719 sighash_type: input.sighash_type.as_ref().map(|s| s.to_string()),
720 redeem_script: input
721 .redeem_script
722 .as_ref()
723 .map(|s| Arc::new(Script(s.clone()))),
724 witness_script: input
725 .witness_script
726 .as_ref()
727 .map(|s| Arc::new(Script(s.clone()))),
728 bip32_derivation: input
729 .bip32_derivation
730 .iter()
731 .map(|(pk, (fingerprint, deriv_path))| {
732 (
733 pk.to_string(),
734 KeySource {
735 fingerprint: fingerprint.to_string(),
736 path: Arc::new(deriv_path.clone().into()),
737 },
738 )
739 })
740 .collect(),
741 final_script_sig: input
742 .final_script_sig
743 .as_ref()
744 .map(|s| Arc::new(Script(s.clone()))),
745 final_script_witness: input.final_script_witness.as_ref().map(|w| w.to_vec()),
746 ripemd160_preimages: input
747 .ripemd160_preimages
748 .iter()
749 .map(|(k, v)| (k.to_string(), v.clone()))
750 .collect(),
751 sha256_preimages: input
752 .sha256_preimages
753 .iter()
754 .map(|(k, v)| (k.to_string(), v.clone()))
755 .collect(),
756 hash160_preimages: input
757 .hash160_preimages
758 .iter()
759 .map(|(k, v)| (k.to_string(), v.clone()))
760 .collect(),
761 hash256_preimages: input
762 .hash256_preimages
763 .iter()
764 .map(|(k, v)| (k.to_string(), v.clone()))
765 .collect(),
766 tap_key_sig: input.tap_key_sig.as_ref().map(|s| s.serialize().to_vec()),
767 tap_script_sigs: input
768 .tap_script_sigs
769 .iter()
770 .map(|(k, v)| {
771 let key = TapScriptSigKey {
772 xonly_pubkey: k.0.to_string(),
773 tap_leaf_hash: k.1.to_string(),
774 };
775 (key, v.to_vec())
776 })
777 .collect(),
778 tap_scripts: input
779 .tap_scripts
780 .iter()
781 .map(|(k, v)| {
782 let key = ControlBlock {
783 internal_key: k.internal_key.serialize().to_vec(),
784 merkle_branch: k.merkle_branch.iter().map(|h| h.to_string()).collect(),
785 output_key_parity: k.output_key_parity.to_u8(),
786 leaf_version: k.leaf_version.to_consensus(),
787 };
788 let entry = TapScriptEntry {
789 script: Arc::new(v.0.clone().into()),
790 leaf_version: v.1.to_consensus(),
791 };
792 (key, entry)
793 })
794 .collect(),
795 tap_key_origins: input
796 .tap_key_origins
797 .iter()
798 .map(|(k, v)| {
799 let key = k.to_string();
800 let value = TapKeyOrigin {
801 tap_leaf_hashes: v.0.iter().map(|h| h.to_string()).collect(),
802 key_source: KeySource {
803 #[rustfmt::skip]
805 fingerprint: v.1.0.to_string(),
806 #[rustfmt::skip]
807 path: Arc::new(v.1.1.clone().into()),
808 },
809 };
810 (key, value)
811 })
812 .collect(),
813 tap_internal_key: input.tap_internal_key.as_ref().map(|k| k.to_string()),
814 tap_merkle_root: input.tap_merkle_root.as_ref().map(|k| k.to_string()),
815 proprietary: input
816 .proprietary
817 .iter()
818 .map(|(k, v)| {
819 (
820 ProprietaryKey {
821 prefix: k.prefix.clone(),
822 subtype: k.subtype,
823 key: k.key.clone(),
824 },
825 v.to_vec(),
826 )
827 })
828 .collect(),
829 unknown: input
830 .unknown
831 .iter()
832 .map(|(k, v)| {
833 (
834 Key {
835 key: k.key.clone(),
836 type_value: k.type_value,
837 },
838 v.to_vec(),
839 )
840 })
841 .collect(),
842 }
843 }
844}
845
846impl TryFrom<Input> for BdkInput {
847 type Error = AddForeignUtxoError;
848
849 fn try_from(input: Input) -> Result<Self, Self::Error> {
850 use bdk_wallet::bitcoin::ecdsa;
851 use bdk_wallet::bitcoin::hashes::Hash as HashTrait;
852 use bdk_wallet::bitcoin::key::PublicKey as Secp256k1PublicKey;
853 use bdk_wallet::bitcoin::psbt::PsbtSighashType;
854 use bdk_wallet::bitcoin::secp256k1::XOnlyPublicKey;
855 use bdk_wallet::bitcoin::taproot::{
856 ControlBlock as BdkControlBlock, LeafVersion, TapLeafHash, TapNodeHash,
857 };
858 use std::str::FromStr;
859
860 let non_witness_utxo = input.non_witness_utxo.map(|tx| tx.0.clone());
861
862 let witness_utxo = input.witness_utxo.map(|txout| txout.into());
863
864 let partial_sigs = input
865 .partial_sigs
866 .into_iter()
867 .map(|(k, v)| {
868 let pubkey = Secp256k1PublicKey::from_str(&k).map_err(|e| {
869 AddForeignUtxoError::InputConversionError {
870 error_message: format!("invalid public key in partial_sigs: {}", e),
871 }
872 })?;
873 let sig = ecdsa::Signature::from_slice(&v).map_err(|e| {
874 AddForeignUtxoError::InputConversionError {
875 error_message: format!("invalid signature in partial_sigs: {}", e),
876 }
877 })?;
878 Ok((pubkey, sig))
879 })
880 .collect::<Result<std::collections::BTreeMap<_, _>, AddForeignUtxoError>>()?;
881
882 let sighash_type = input
883 .sighash_type
884 .map(|s| {
885 PsbtSighashType::from_str(&s).map_err(|e| {
886 AddForeignUtxoError::InputConversionError {
887 error_message: format!("invalid sighash type: {}", e),
888 }
889 })
890 })
891 .transpose()?;
892
893 let redeem_script = input.redeem_script.map(|s| s.0.clone());
894 let witness_script = input.witness_script.map(|s| s.0.clone());
895
896 let bip32_derivation = input
897 .bip32_derivation
898 .into_iter()
899 .map(|(k, v)| {
900 use bdk_wallet::bitcoin::bip32::{DerivationPath, Fingerprint};
901 use bdk_wallet::bitcoin::secp256k1::PublicKey as Secp256k1RawPublicKey;
902 let pubkey = Secp256k1RawPublicKey::from_str(&k).map_err(|e| {
903 AddForeignUtxoError::InputConversionError {
904 error_message: format!("invalid public key in bip32_derivation: {}", e),
905 }
906 })?;
907 let fingerprint = Fingerprint::from_str(&v.fingerprint).map_err(|e| {
908 AddForeignUtxoError::InputConversionError {
909 error_message: format!("invalid fingerprint: {}", e),
910 }
911 })?;
912 let path: DerivationPath = v.path.0.clone();
913 Ok((pubkey, (fingerprint, path)))
914 })
915 .collect::<Result<std::collections::BTreeMap<_, _>, AddForeignUtxoError>>()?;
916
917 let final_script_sig = input.final_script_sig.map(|s| s.0.clone());
918
919 let final_script_witness = input.final_script_witness.map(|w| {
920 use bdk_wallet::bitcoin::Witness;
921 Witness::from_slice(&w)
922 });
923
924 let ripemd160_preimages = input
925 .ripemd160_preimages
926 .into_iter()
927 .map(|(k, v)| {
928 use bdk_wallet::bitcoin::hashes::ripemd160;
929 let hash = ripemd160::Hash::from_str(&k).map_err(|e| {
930 AddForeignUtxoError::InputConversionError {
931 error_message: format!("invalid ripemd160 hash: {}", e),
932 }
933 })?;
934 Ok((hash, v))
935 })
936 .collect::<Result<_, AddForeignUtxoError>>()?;
937
938 let sha256_preimages = input
939 .sha256_preimages
940 .into_iter()
941 .map(|(k, v)| {
942 use bdk_wallet::bitcoin::hashes::sha256;
943 let hash = sha256::Hash::from_str(&k).map_err(|e| {
944 AddForeignUtxoError::InputConversionError {
945 error_message: format!("invalid sha256 hash: {}", e),
946 }
947 })?;
948 Ok((hash, v))
949 })
950 .collect::<Result<_, AddForeignUtxoError>>()?;
951
952 let hash160_preimages = input
953 .hash160_preimages
954 .into_iter()
955 .map(|(k, v)| {
956 use bdk_wallet::bitcoin::hashes::hash160;
957 let hash = hash160::Hash::from_str(&k).map_err(|e| {
958 AddForeignUtxoError::InputConversionError {
959 error_message: format!("invalid hash160: {}", e),
960 }
961 })?;
962 Ok((hash, v))
963 })
964 .collect::<Result<_, AddForeignUtxoError>>()?;
965
966 let hash256_preimages = input
967 .hash256_preimages
968 .into_iter()
969 .map(|(k, v)| {
970 use bdk_wallet::bitcoin::hashes::sha256d;
971 let hash = sha256d::Hash::from_str(&k).map_err(|e| {
972 AddForeignUtxoError::InputConversionError {
973 error_message: format!("invalid hash256: {}", e),
974 }
975 })?;
976 Ok((hash, v))
977 })
978 .collect::<Result<_, AddForeignUtxoError>>()?;
979
980 let tap_key_sig = input
981 .tap_key_sig
982 .map(|s| {
983 use bdk_wallet::bitcoin::taproot::Signature;
984 Signature::from_slice(&s).map_err(|e| AddForeignUtxoError::InputConversionError {
985 error_message: format!("invalid taproot signature: {}", e),
986 })
987 })
988 .transpose()?;
989
990 let tap_script_sigs = input
991 .tap_script_sigs
992 .into_iter()
993 .map(|(k, v)| {
994 use bdk_wallet::bitcoin::taproot::Signature;
995 let xonly = XOnlyPublicKey::from_str(&k.xonly_pubkey).map_err(|e| {
996 AddForeignUtxoError::InputConversionError {
997 error_message: format!("invalid xonly pubkey: {}", e),
998 }
999 })?;
1000 let leaf_hash = TapLeafHash::from_str(&k.tap_leaf_hash).map_err(|e| {
1001 AddForeignUtxoError::InputConversionError {
1002 error_message: format!("invalid tap leaf hash: {}", e),
1003 }
1004 })?;
1005 let sig = Signature::from_slice(&v).map_err(|e| {
1006 AddForeignUtxoError::InputConversionError {
1007 error_message: format!("invalid taproot script signature: {}", e),
1008 }
1009 })?;
1010 Ok(((xonly, leaf_hash), sig))
1011 })
1012 .collect::<Result<_, AddForeignUtxoError>>()?;
1013
1014 let tap_scripts = input
1015 .tap_scripts
1016 .into_iter()
1017 .map(|(k, v)| {
1018 use bdk_wallet::bitcoin::key::XOnlyPublicKey as BdkXOnlyPublicKey;
1019 use bdk_wallet::bitcoin::taproot::TapNodeHash;
1020
1021 let internal_key = BdkXOnlyPublicKey::from_slice(&k.internal_key).map_err(|e| {
1022 AddForeignUtxoError::InputConversionError {
1023 error_message: format!("invalid internal key: {}", e),
1024 }
1025 })?;
1026
1027 let output_key_parity = k.output_key_parity;
1028 let leaf_version_u8 = k.leaf_version;
1029
1030 let merkle_branch: Vec<TapNodeHash> = k
1031 .merkle_branch
1032 .into_iter()
1033 .map(|h| {
1034 TapNodeHash::from_str(&h).map_err(|e| {
1035 AddForeignUtxoError::InputConversionError {
1036 error_message: format!("invalid merkle branch hash: {}", e),
1037 }
1038 })
1039 })
1040 .collect::<Result<_, AddForeignUtxoError>>()?;
1041
1042 let mut control_block_bytes = vec![output_key_parity | leaf_version_u8];
1043 control_block_bytes.extend_from_slice(&internal_key.serialize());
1044 for hash in &merkle_branch {
1045 control_block_bytes.extend_from_slice(&hash.to_byte_array());
1046 }
1047
1048 let control_block = BdkControlBlock::decode(&control_block_bytes).map_err(|e| {
1049 AddForeignUtxoError::InputConversionError {
1050 error_message: format!("invalid control block: {}", e),
1051 }
1052 })?;
1053
1054 let leaf_version = LeafVersion::from_consensus(leaf_version_u8).map_err(|_| {
1055 AddForeignUtxoError::InputConversionError {
1056 error_message: format!("invalid leaf version: {}", leaf_version_u8),
1057 }
1058 })?;
1059
1060 Ok((control_block, (v.script.0.clone(), leaf_version)))
1061 })
1062 .collect::<Result<_, AddForeignUtxoError>>()?;
1063
1064 let tap_key_origins = input
1065 .tap_key_origins
1066 .into_iter()
1067 .map(|(k, v)| {
1068 use bdk_wallet::bitcoin::bip32::{DerivationPath, Fingerprint};
1069
1070 let xonly = XOnlyPublicKey::from_str(&k).map_err(|e| {
1071 AddForeignUtxoError::InputConversionError {
1072 error_message: format!("invalid xonly pubkey in tap_key_origins: {}", e),
1073 }
1074 })?;
1075
1076 let leaf_hashes: Vec<TapLeafHash> = v
1077 .tap_leaf_hashes
1078 .into_iter()
1079 .map(|h| {
1080 TapLeafHash::from_str(&h).map_err(|e| {
1081 AddForeignUtxoError::InputConversionError {
1082 error_message: format!("invalid tap leaf hash: {}", e),
1083 }
1084 })
1085 })
1086 .collect::<Result<_, AddForeignUtxoError>>()?;
1087
1088 let fingerprint =
1089 Fingerprint::from_str(&v.key_source.fingerprint).map_err(|e| {
1090 AddForeignUtxoError::InputConversionError {
1091 error_message: format!("invalid fingerprint in tap_key_origins: {}", e),
1092 }
1093 })?;
1094
1095 let path: DerivationPath = v.key_source.path.0.clone();
1096
1097 Ok((xonly, (leaf_hashes, (fingerprint, path))))
1098 })
1099 .collect::<Result<_, AddForeignUtxoError>>()?;
1100
1101 let tap_internal_key = input
1102 .tap_internal_key
1103 .map(|k| {
1104 XOnlyPublicKey::from_str(&k).map_err(|e| {
1105 AddForeignUtxoError::InputConversionError {
1106 error_message: format!("invalid tap internal key: {}", e),
1107 }
1108 })
1109 })
1110 .transpose()?;
1111
1112 let tap_merkle_root = input
1113 .tap_merkle_root
1114 .map(|k| {
1115 TapNodeHash::from_str(&k).map_err(|e| AddForeignUtxoError::InputConversionError {
1116 error_message: format!("invalid tap merkle root: {}", e),
1117 })
1118 })
1119 .transpose()?;
1120
1121 let proprietary = input
1122 .proprietary
1123 .into_iter()
1124 .map(|(k, v)| {
1125 use bdk_wallet::bitcoin::psbt::raw::ProprietaryKey as BdkProprietaryKey;
1126 (
1127 BdkProprietaryKey {
1128 prefix: k.prefix,
1129 subtype: k.subtype,
1130 key: k.key,
1131 },
1132 v,
1133 )
1134 })
1135 .collect();
1136
1137 let unknown = input
1138 .unknown
1139 .into_iter()
1140 .map(|(k, v)| {
1141 use bdk_wallet::bitcoin::psbt::raw::Key as BdkKey;
1142 (
1143 BdkKey {
1144 type_value: k.type_value,
1145 key: k.key,
1146 },
1147 v,
1148 )
1149 })
1150 .collect();
1151
1152 Ok(BdkInput {
1153 non_witness_utxo,
1154 witness_utxo,
1155 partial_sigs,
1156 sighash_type,
1157 redeem_script,
1158 witness_script,
1159 bip32_derivation,
1160 final_script_sig,
1161 final_script_witness,
1162 ripemd160_preimages,
1163 sha256_preimages,
1164 hash160_preimages,
1165 hash256_preimages,
1166 tap_key_sig,
1167 tap_script_sigs,
1168 tap_scripts,
1169 tap_key_origins,
1170 tap_internal_key,
1171 tap_merkle_root,
1172 proprietary,
1173 unknown,
1174 })
1175 }
1176}
1177
1178#[derive(Debug, uniffi::Object)]
1180#[uniffi::export(Display)]
1181pub struct LeafNode(BdkLeafNode);
1182
1183#[uniffi::export]
1184impl LeafNode {
1185 pub fn depth(&self) -> u8 {
1187 self.0.depth()
1188 }
1189
1190 pub fn leaf_hash(&self) -> Option<String> {
1194 self.0.leaf_hash().map(|h| h.to_string())
1195 }
1196
1197 pub fn node_hash(&self) -> String {
1202 self.0.node_hash().to_string()
1203 }
1204
1205 pub fn script(&self) -> Option<Arc<Script>> {
1207 self.0.script().map(|s| Arc::new(Script(s.to_owned())))
1208 }
1209
1210 pub fn leaf_version(&self) -> Option<u8> {
1212 self.0.leaf_version().map(|n| n.to_consensus())
1213 }
1214
1215 pub fn merkle_branch(&self) -> Vec<String> {
1218 self.0
1219 .merkle_branch()
1220 .to_vec()
1221 .iter()
1222 .map(|h| h.to_string())
1223 .collect()
1224 }
1225}
1226
1227impl Display for LeafNode {
1228 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1229 write!(f, "{:?}", self)
1230 }
1231}
1232
1233#[derive(Debug, uniffi::Object)]
1237#[uniffi::export(Display)]
1238pub struct TapTree(BdkTapTree);
1239
1240#[uniffi::export]
1241impl TapTree {
1242 pub fn root_hash(&self) -> String {
1244 self.0.root_hash().to_string()
1245 }
1246
1247 pub fn node_info(&self) -> Arc<NodeInfo> {
1249 Arc::new(NodeInfo(self.0.node_info().clone()))
1250 }
1251}
1252
1253impl Display for TapTree {
1254 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1255 write!(f, "{:?}", self)
1256 }
1257}
1258
1259#[derive(Debug, uniffi::Object)]
1264#[uniffi::export(Display)]
1265pub struct NodeInfo(BdkNodeInfo);
1266
1267#[uniffi::export]
1268impl NodeInfo {
1269 pub fn leaf_nodes(&self) -> Vec<Arc<LeafNode>> {
1271 self.0
1272 .leaf_nodes()
1273 .map(|ln| Arc::new(LeafNode(ln.clone())))
1274 .collect()
1275 }
1276
1277 pub fn node_hash(&self) -> String {
1279 self.0.node_hash().to_string()
1280 }
1281}
1282
1283impl Display for NodeInfo {
1284 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1285 write!(f, "{:?}", self)
1286 }
1287}
1288
1289#[derive(Debug, uniffi::Record)]
1292pub struct Output {
1293 pub redeem_script: Option<Arc<Script>>,
1295 pub witness_script: Option<Arc<Script>>,
1297 pub bip32_derivation: HashMap<String, KeySource>,
1300 pub tap_internal_key: Option<String>,
1302 pub tap_tree: Option<Arc<TapTree>>,
1304 pub tap_key_origins: HashMap<String, TapKeyOrigin>,
1306 pub proprietary: HashMap<ProprietaryKey, Vec<u8>>,
1308 pub unknown: HashMap<Key, Vec<u8>>,
1310}
1311
1312impl From<&BdkOutput> for Output {
1313 fn from(output: &BdkOutput) -> Self {
1314 Output {
1315 redeem_script: output
1316 .redeem_script
1317 .as_ref()
1318 .map(|s| Arc::new(Script(s.clone()))),
1319 witness_script: output
1320 .witness_script
1321 .as_ref()
1322 .map(|s| Arc::new(Script(s.clone()))),
1323 bip32_derivation: output
1324 .bip32_derivation
1325 .iter()
1326 .map(|(pk, (fingerprint, deriv_path))| {
1327 (
1328 pk.to_string(),
1329 KeySource {
1330 fingerprint: fingerprint.to_string(),
1331 path: Arc::new(deriv_path.clone().into()),
1332 },
1333 )
1334 })
1335 .collect(),
1336 tap_internal_key: output.tap_internal_key.as_ref().map(|k| k.to_string()),
1337 tap_tree: output
1338 .tap_tree
1339 .as_ref()
1340 .map(|t| Arc::new(TapTree(t.clone()))),
1341 tap_key_origins: output
1342 .tap_key_origins
1343 .iter()
1344 .map(|(k, v)| {
1345 let key = k.to_string();
1346 let value = TapKeyOrigin {
1347 tap_leaf_hashes: v.0.iter().map(|h| h.to_string()).collect(),
1348 key_source: KeySource {
1349 #[rustfmt::skip]
1351 fingerprint: v.1.0.to_string(),
1352 #[rustfmt::skip]
1353 path: Arc::new(v.1.1.clone().into()),
1354 },
1355 };
1356 (key, value)
1357 })
1358 .collect(),
1359 proprietary: output
1360 .proprietary
1361 .iter()
1362 .map(|(k, v)| {
1363 (
1364 ProprietaryKey {
1365 prefix: k.prefix.clone(),
1366 subtype: k.subtype,
1367 key: k.key.clone(),
1368 },
1369 v.to_vec(),
1370 )
1371 })
1372 .collect(),
1373 unknown: output
1374 .unknown
1375 .iter()
1376 .map(|(k, v)| {
1377 (
1378 Key {
1379 key: k.key.clone(),
1380 type_value: k.type_value,
1381 },
1382 v.to_vec(),
1383 )
1384 })
1385 .collect(),
1386 }
1387 }
1388}
1389
1390#[derive(uniffi::Object)]
1392pub struct Psbt(pub(crate) Mutex<BdkPsbt>);
1393
1394#[uniffi::export]
1395impl Psbt {
1396 #[uniffi::constructor]
1398 pub fn new(psbt_base64: String) -> Result<Self, PsbtParseError> {
1399 let psbt: BdkPsbt = BdkPsbt::from_str(&psbt_base64)?;
1400 Ok(Psbt(Mutex::new(psbt)))
1401 }
1402
1403 #[uniffi::constructor]
1409 pub fn from_unsigned_tx(tx: Arc<Transaction>) -> Result<Arc<Psbt>, PsbtError> {
1410 let psbt: BdkPsbt = BdkPsbt::from_unsigned_tx(tx.0.clone())?;
1411 Ok(Arc::new(Psbt(Mutex::new(psbt))))
1412 }
1413
1414 #[uniffi::constructor]
1416 pub fn from_file(path: String) -> Result<Self, PsbtError> {
1417 let file = File::open(path)?;
1418 let mut buf_read = BufReader::new(file);
1419 let psbt: BdkPsbt = BdkPsbt::deserialize_from_reader(&mut buf_read)?;
1420 Ok(Psbt(Mutex::new(psbt)))
1421 }
1422
1423 pub fn serialize(&self) -> String {
1425 let psbt = self.0.lock().unwrap().clone();
1426 psbt.to_string()
1427 }
1428
1429 pub fn extract_tx(&self) -> Result<Arc<Transaction>, ExtractTxError> {
1437 let tx: BdkTransaction = self.0.lock().unwrap().clone().extract_tx()?;
1438 let transaction: Transaction = tx.into();
1439 Ok(Arc::new(transaction))
1440 }
1441
1442 pub fn fee(&self) -> Result<u64, PsbtError> {
1453 self.0
1454 .lock()
1455 .unwrap()
1456 .fee()
1457 .map(|fee| fee.to_sat())
1458 .map_err(PsbtError::from)
1459 }
1460
1461 pub fn combine(&self, other: Arc<Psbt>) -> Result<Arc<Psbt>, PsbtError> {
1465 let mut original_psbt = self.0.lock().unwrap().clone();
1466 let other_psbt = other.0.lock().unwrap().clone();
1467 original_psbt.combine(other_psbt)?;
1468 Ok(Arc::new(Psbt(Mutex::new(original_psbt))))
1469 }
1470
1471 pub fn finalize(&self) -> FinalizedPsbtResult {
1475 let curve = Secp256k1::verification_only();
1476 let finalized = self.0.lock().unwrap().clone().finalize(&curve);
1477 match finalized {
1478 Ok(psbt) => FinalizedPsbtResult {
1479 psbt: Arc::new(psbt.into()),
1480 could_finalize: true,
1481 errors: None,
1482 },
1483 Err((psbt, errors)) => {
1484 let errors = errors.into_iter().map(|e| e.into()).collect();
1485 FinalizedPsbtResult {
1486 psbt: Arc::new(psbt.into()),
1487 could_finalize: false,
1488 errors: Some(errors),
1489 }
1490 }
1491 }
1492 }
1493
1494 pub fn write_to_file(&self, path: String) -> Result<(), PsbtError> {
1496 let file = File::create_new(path)?;
1497 let mut writer = BufWriter::new(file);
1498 let psbt = self.0.lock().unwrap();
1499 psbt.serialize_to_writer(&mut writer)?;
1500 Ok(())
1501 }
1502
1503 pub fn json_serialize(&self) -> String {
1505 let psbt = self.0.lock().unwrap();
1506 serde_json::to_string(psbt.deref()).unwrap()
1507 }
1508
1509 pub fn spend_utxo(&self, input_index: u64) -> String {
1511 let psbt = self.0.lock().unwrap();
1512 let utxo = psbt.spend_utxo(input_index as usize).unwrap();
1513 serde_json::to_string(&utxo).unwrap()
1514 }
1515
1516 pub fn input(&self) -> Vec<Input> {
1518 let psbt = self.0.lock().unwrap();
1519 psbt.inputs.iter().map(|input| input.into()).collect()
1520 }
1521
1522 pub fn output(&self) -> Vec<Output> {
1524 let psbt = self.0.lock().unwrap();
1525 psbt.outputs.iter().map(|o| o.into()).collect()
1526 }
1527}
1528
1529impl From<BdkPsbt> for Psbt {
1530 fn from(psbt: BdkPsbt) -> Self {
1531 Psbt(Mutex::new(psbt))
1532 }
1533}
1534
1535#[derive(uniffi::Record)]
1536pub struct FinalizedPsbtResult {
1537 pub psbt: Arc<Psbt>,
1538 pub could_finalize: bool,
1539 pub errors: Option<Vec<PsbtFinalizeError>>,
1540}
1541
1542#[derive(Debug, Clone, uniffi::Record)]
1544pub struct TxIn {
1545 pub previous_output: OutPoint,
1547 pub script_sig: Arc<Script>,
1549 pub sequence: u32,
1551 pub witness: Vec<Vec<u8>>,
1553}
1554
1555impl From<&BdkTxIn> for TxIn {
1556 fn from(tx_in: &BdkTxIn) -> Self {
1557 TxIn {
1558 previous_output: OutPoint {
1559 txid: Arc::new(Txid(tx_in.previous_output.txid)),
1560 vout: tx_in.previous_output.vout,
1561 },
1562 script_sig: Arc::new(Script(tx_in.script_sig.clone())),
1563 sequence: tx_in.sequence.0,
1564 witness: tx_in.witness.to_vec(),
1565 }
1566 }
1567}
1568
1569#[derive(Debug, Clone, uniffi::Record)]
1577pub struct TxOut {
1578 pub value: Arc<Amount>,
1580 pub script_pubkey: Arc<Script>,
1582}
1583
1584impl From<&BdkTxOut> for TxOut {
1585 fn from(tx_out: &BdkTxOut) -> Self {
1586 TxOut {
1587 value: Arc::new(Amount(tx_out.value)),
1588 script_pubkey: Arc::new(Script(tx_out.script_pubkey.clone())),
1589 }
1590 }
1591}
1592
1593impl From<BdkTxOut> for TxOut {
1594 fn from(tx_out: BdkTxOut) -> Self {
1595 Self {
1596 value: Arc::new(Amount(tx_out.value)),
1597 script_pubkey: Arc::new(Script(tx_out.script_pubkey)),
1598 }
1599 }
1600}
1601
1602impl From<TxOut> for BdkTxOut {
1603 fn from(tx_out: TxOut) -> Self {
1604 Self {
1605 value: tx_out.value.0,
1606 script_pubkey: tx_out.script_pubkey.0.clone(),
1607 }
1608 }
1609}
1610
1611#[derive(Copy, Clone, uniffi::Enum)]
1613pub enum ChildNumber {
1614 Normal {
1616 index: u32,
1618 },
1619 Hardened {
1621 index: u32,
1623 },
1624}
1625
1626impl From<BdkChildNumber> for ChildNumber {
1627 fn from(value: BdkChildNumber) -> Self {
1628 match value {
1629 BdkChildNumber::Normal { index } => ChildNumber::Normal { index },
1630 BdkChildNumber::Hardened { index } => ChildNumber::Hardened { index },
1631 }
1632 }
1633}
1634
1635impl TryFrom<ChildNumber> for BdkChildNumber {
1636 type Error = Bip32Error;
1637
1638 fn try_from(value: ChildNumber) -> Result<Self, Self::Error> {
1639 match value {
1640 ChildNumber::Normal { index } => {
1641 BdkChildNumber::from_normal_idx(index).map_err(Bip32Error::from)
1642 }
1643 ChildNumber::Hardened { index } => {
1644 BdkChildNumber::from_hardened_idx(index).map_err(Bip32Error::from)
1645 }
1646 }
1647 }
1648}
1649
1650#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, std::hash::Hash, uniffi::Object)]
1652#[uniffi::export(Display, Eq, Hash, Ord)]
1653pub struct BlockHash(pub(crate) BitcoinBlockHash);
1654
1655impl_hash_like!(BlockHash, BitcoinBlockHash);
1656
1657#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, std::hash::Hash, uniffi::Object)]
1659#[uniffi::export(Display, Eq, Hash, Ord)]
1660pub struct Txid(pub(crate) BitcoinTxid);
1661
1662impl_hash_like!(Txid, BitcoinTxid);
1663
1664#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, std::hash::Hash, uniffi::Object)]
1667#[uniffi::export(Display, Eq, Hash, Ord)]
1668pub struct Wtxid(pub(crate) BitcoinWtxid);
1669
1670impl_hash_like!(Wtxid, BitcoinWtxid);
1671
1672#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, std::hash::Hash, uniffi::Object)]
1674#[uniffi::export(Display, Eq, Hash, Ord)]
1675pub struct DescriptorId(pub(crate) BitcoinSha256Hash);
1676
1677impl_hash_like!(DescriptorId, BitcoinSha256Hash);
1678
1679#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, std::hash::Hash, uniffi::Object)]
1681#[uniffi::export(Display, Eq, Hash, Ord)]
1682pub struct TxMerkleNode(pub(crate) BitcoinDoubleSha256Hash);
1683
1684impl_hash_like!(TxMerkleNode, BitcoinDoubleSha256Hash);
1685
1686#[uniffi::remote(Enum)]
1688pub enum DescriptorType {
1689 Bare,
1691 Sh,
1693 Pkh,
1695 Wpkh,
1697 Wsh,
1699 ShWsh,
1701 ShWpkh,
1703 ShSortedMulti,
1705 WshSortedMulti,
1707 ShWshSortedMulti,
1709 Tr,
1711}