bitcoind_async_client/
types.rs

1use std::collections::BTreeMap;
2
3use bitcoin::{
4    absolute::Height,
5    address::{self, NetworkUnchecked},
6    block::Header,
7    consensus::{self, encode},
8    Address, Amount, Block, BlockHash, SignedAmount, Transaction, Txid, Wtxid,
9};
10use serde::{
11    de::{self, IntoDeserializer, Visitor},
12    Deserialize, Deserializer, Serialize,
13};
14use tracing::*;
15
16use crate::error::SignRawTransactionWithWalletError;
17
18/// The category of a transaction.
19///
20/// This is one of the results of `listtransactions` RPC method.
21///
22/// # Note
23///
24/// This is a subset of the categories available in Bitcoin Core.
25/// It also assumes that the transactions are present in the underlying Bitcoin
26/// client's wallet.
27#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize)]
28#[serde(rename_all = "lowercase")]
29pub enum TransactionCategory {
30    /// Transactions sent.
31    Send,
32    /// Non-coinbase transactions received.
33    Receive,
34    /// Coinbase transactions received with more than 100 confirmations.
35    Generate,
36    /// Coinbase transactions received with 100 or less confirmations.
37    Immature,
38    /// Orphaned coinbase transactions received.
39    Orphan,
40}
41
42/// Result of JSON-RPC method `getblockchaininfo`.
43///
44/// Method call: `getblockchaininfo`
45///
46/// > Returns an object containing various state info regarding blockchain processing.
47#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
48pub struct GetBlockchainInfo {
49    /// Current network name as defined in BIP70 (main, test, signet, regtest).
50    pub chain: String,
51    /// The current number of blocks processed in the server.
52    pub blocks: u64,
53    /// The current number of headers we have validated.
54    pub headers: u64,
55    /// The hash of the currently best block.
56    #[serde(rename = "bestblockhash")]
57    pub best_block_hash: String,
58    /// The current difficulty.
59    pub difficulty: f64,
60    /// Median time for the current best block.
61    #[serde(rename = "mediantime")]
62    pub median_time: u64,
63    /// Estimate of verification progress (between 0 and 1).
64    #[serde(rename = "verificationprogress")]
65    pub verification_progress: f64,
66    /// Estimate of whether this node is in Initial Block Download (IBD) mode.
67    #[serde(rename = "initialblockdownload")]
68    pub initial_block_download: bool,
69    /// Total amount of work in active chain, in hexadecimal.
70    #[serde(rename = "chainwork")]
71    pub chain_work: String,
72    /// The estimated size of the block and undo files on disk.
73    pub size_on_disk: u64,
74    /// If the blocks are subject to pruning.
75    pub pruned: bool,
76    /// Lowest-height complete block stored (only present if pruning is enabled).
77    #[serde(rename = "pruneheight")]
78    pub prune_height: Option<u64>,
79    /// Whether automatic pruning is enabled (only present if pruning is enabled).
80    pub automatic_pruning: Option<bool>,
81    /// The target size used by pruning (only present if automatic pruning is enabled).
82    pub prune_target_size: Option<u64>,
83}
84
85/// Result of JSON-RPC method `getblockheader` with verbosity set to 0.
86///
87/// A string that is serialized, hex-encoded data for block 'hash'.
88///
89/// Method call: `getblockheader "blockhash" ( verbosity )`
90#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
91pub struct GetBlockHeaderVerbosityZero(pub String);
92
93impl GetBlockHeaderVerbosityZero {
94    /// Converts json straight to a [`Header`].
95    pub fn header(self) -> Result<Header, encode::FromHexError> {
96        let header: Header = encode::deserialize_hex(&self.0)?;
97        Ok(header)
98    }
99}
100
101/// Result of JSON-RPC method `getblock` with verbosity set to 0.
102///
103/// A string that is serialized, hex-encoded data for block 'hash'.
104///
105/// Method call: `getblock "blockhash" ( verbosity )`
106#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
107pub struct GetBlockVerbosityZero(pub String);
108
109impl GetBlockVerbosityZero {
110    /// Converts json straight to a [`Block`].
111    pub fn block(self) -> Result<Block, encode::FromHexError> {
112        let block: Block = encode::deserialize_hex(&self.0)?;
113        Ok(block)
114    }
115}
116
117/// Result of JSON-RPC method `getblock` with verbosity set to 1.
118#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
119pub struct GetBlockVerbosityOne {
120    /// The block hash (same as provided) in RPC call.
121    pub hash: String,
122    /// The number of confirmations, or -1 if the block is not on the main chain.
123    pub confirmations: i32,
124    /// The block size.
125    pub size: usize,
126    /// The block size excluding witness data.
127    #[serde(rename = "strippedsize")]
128    pub stripped_size: Option<usize>,
129    /// The block weight as defined in BIP-141.
130    pub weight: u64,
131    /// The block height or index.
132    pub height: usize,
133    /// The block version.
134    pub version: i32,
135    /// The block version formatted in hexadecimal.
136    #[serde(rename = "versionHex")]
137    pub version_hex: String,
138    /// The merkle root
139    #[serde(rename = "merkleroot")]
140    pub merkle_root: String,
141    /// The transaction ids
142    pub tx: Vec<String>,
143    /// The block time expressed in UNIX epoch time.
144    pub time: usize,
145    /// The median block time expressed in UNIX epoch time.
146    #[serde(rename = "mediantime")]
147    pub median_time: Option<usize>,
148    /// The nonce
149    pub nonce: u32,
150    /// The bits.
151    pub bits: String,
152    /// The difficulty.
153    pub difficulty: f64,
154    /// Expected number of hashes required to produce the chain up to this block (in hex).
155    #[serde(rename = "chainwork")]
156    pub chain_work: String,
157    /// The number of transactions in the block.
158    #[serde(rename = "nTx")]
159    pub n_tx: u32,
160    /// The hash of the previous block (if available).
161    #[serde(rename = "previousblockhash")]
162    pub previous_block_hash: Option<String>,
163    /// The hash of the next block (if available).
164    #[serde(rename = "nextblockhash")]
165    pub next_block_hash: Option<String>,
166}
167
168/// Result of JSON-RPC method `getrawtransaction` with verbosity set to 0.
169///
170/// A string that is serialized, hex-encoded data for transaction.
171///
172/// Method call: `getrawtransaction "txid" ( verbosity )`
173#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
174pub struct GetRawTransactionVerbosityZero(pub String);
175
176impl GetRawTransactionVerbosityZero {
177    /// Converts json straight to a [`Transaction`].
178    pub fn transaction(self) -> Result<Transaction, encode::FromHexError> {
179        let transaction: Transaction = encode::deserialize_hex(&self.0)?;
180        Ok(transaction)
181    }
182}
183
184/// Result of JSON-RPC method `getmempoolinfo`.
185///
186/// Method call: `getmempoolinfo`
187#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
188pub struct GetMempoolInfo {
189    pub loaded: bool,
190    pub size: usize,
191    pub bytes: usize,
192    pub usage: usize,
193    pub maxmempool: usize,
194    pub mempoolminfee: f64,
195    pub minrelaytxfee: f64,
196    pub unbroadcastcount: usize,
197}
198
199/// Result of JSON-RPC method `getrawtransaction` with verbosity set to 1.
200///
201/// Method call: `getrawtransaction "txid" ( verbosity )`
202#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
203pub struct GetRawTransactionVerbosityOne {
204    pub in_active_chain: Option<bool>,
205    #[serde(deserialize_with = "deserialize_tx")]
206    #[serde(rename = "hex")]
207    pub transaction: Transaction,
208    pub txid: Txid,
209    pub hash: Wtxid,
210    pub size: usize,
211    pub vsize: usize,
212    pub version: u32,
213    pub locktime: u32,
214    pub blockhash: Option<BlockHash>,
215    pub confirmations: Option<u32>,
216    pub time: Option<usize>,
217    pub blocktime: Option<usize>,
218}
219
220/// Result of JSON-RPC method `gettxout`.
221///
222/// > gettxout "txid" n ( include_mempool )
223/// >
224/// > Returns details about an unspent transaction output.
225/// >
226/// > Arguments:
227/// > 1. txid               (string, required) The transaction id
228/// > 2. n                  (numeric, required) vout number
229#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
230pub struct GetTxOut {
231    /// The hash of the block at the tip of the chain.
232    #[serde(rename = "bestblock")]
233    pub best_block: String,
234    /// The number of confirmations.
235    pub confirmations: u32, // TODO: Change this to an i64.
236    /// The transaction value in BTC.
237    pub value: f64,
238    /// The script pubkey.
239    #[serde(rename = "scriptPubkey")]
240    pub script_pubkey: Option<ScriptPubkey>,
241    /// Coinbase or not.
242    pub coinbase: bool,
243}
244
245/// A script pubkey.
246#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
247pub struct ScriptPubkey {
248    /// Script assembly.
249    pub asm: String,
250    /// Script hex.
251    pub hex: String,
252    #[serde(rename = "reqSigs")]
253    pub req_sigs: i64,
254    /// The type, eg pubkeyhash.
255    #[serde(rename = "type")]
256    pub type_: String,
257    /// Bitcoin address.
258    pub address: Option<String>,
259}
260
261/// Models the arguments of JSON-RPC method `createrawtransaction`.
262///
263/// # Note
264///
265/// Assumes that the transaction is always "replaceable" by default and has a locktime of 0.
266#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
267pub struct CreateRawTransaction {
268    pub inputs: Vec<CreateRawTransactionInput>,
269    pub outputs: Vec<CreateRawTransactionOutput>,
270}
271
272/// Models the input of JSON-RPC method `createrawtransaction`.
273#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
274pub struct CreateRawTransactionInput {
275    pub txid: String,
276    pub vout: u32,
277}
278
279/// Models the output of JSON-RPC method `createrawtransaction`.
280///
281/// The outputs specified as key-value pairs, where the keys is an address,
282/// and the values are the amounts to be sent to that address.
283#[derive(Clone, Debug, PartialEq, Deserialize)]
284#[serde(untagged)]
285pub enum CreateRawTransactionOutput {
286    /// A pair of an [`Address`] string and an [`Amount`] in BTC.
287    AddressAmount {
288        /// An [`Address`] string.
289        address: String,
290        /// An [`Amount`] in BTC.
291        amount: f64,
292    },
293    /// A payload such as in `OP_RETURN` transactions.
294    Data {
295        /// The payload.
296        data: String,
297    },
298}
299
300impl Serialize for CreateRawTransactionOutput {
301    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
302    where
303        S: serde::Serializer,
304    {
305        match self {
306            CreateRawTransactionOutput::AddressAmount { address, amount } => {
307                let mut map = serde_json::Map::new();
308                map.insert(
309                    address.clone(),
310                    serde_json::Value::Number(serde_json::Number::from_f64(*amount).unwrap()),
311                );
312                map.serialize(serializer)
313            }
314            CreateRawTransactionOutput::Data { data } => {
315                let mut map = serde_json::Map::new();
316                map.insert("data".to_string(), serde_json::Value::String(data.clone()));
317                map.serialize(serializer)
318            }
319        }
320    }
321}
322
323/// Result of JSON-RPC method `submitpackage`.
324///
325/// > submitpackage ["rawtx",...] ( maxfeerate maxburnamount )
326/// >
327/// > Submit a package of raw transactions (serialized, hex-encoded) to local node.
328/// > The package will be validated according to consensus and mempool policy rules. If any
329/// > transaction passes, it will be accepted to mempool.
330/// > This RPC is experimental and the interface may be unstable. Refer to doc/policy/packages.md
331/// > for documentation on package policies.
332/// > Warning: successful submission does not mean the transactions will propagate throughout the
333/// > network.
334/// >
335/// > Arguments:
336/// > 1. package          (json array, required) An array of raw transactions.
337/// > The package must solely consist of a child and its parents. None of the parents may depend on
338/// > each other.
339/// > The package must be topologically sorted, with the child being the last element in the array.
340/// > [
341/// > "rawtx",     (string)
342/// > ...
343/// > ]
344#[allow(clippy::doc_lazy_continuation)]
345#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
346pub struct SubmitPackage {
347    /// The transaction package result message.
348    ///
349    /// "success" indicates all transactions were accepted into or are already in the mempool.
350    pub package_msg: String,
351    /// Transaction results keyed by wtxid.
352    #[serde(rename = "tx-results")]
353    pub tx_results: BTreeMap<String, SubmitPackageTxResult>,
354    /// List of txids of replaced transactions.
355    #[serde(rename = "replaced-transactions")]
356    pub replaced_transactions: Vec<String>,
357}
358
359/// Models the per-transaction result included in the JSON-RPC method `submitpackage`.
360#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
361pub struct SubmitPackageTxResult {
362    /// The transaction id.
363    pub txid: String,
364    /// The wtxid of a different transaction with the same txid but different witness found in the
365    /// mempool.
366    ///
367    /// If set, this means the submitted transaction was ignored.
368    #[serde(rename = "other-wtxid")]
369    pub other_wtxid: Option<String>,
370    /// Sigops-adjusted virtual transaction size.
371    pub vsize: i64,
372    /// Transaction fees.
373    pub fees: Option<SubmitPackageTxResultFees>,
374    /// The transaction error string, if it was rejected by the mempool
375    pub error: Option<String>,
376}
377
378/// Models the fees included in the per-transaction result of the JSON-RPC method `submitpackage`.
379#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
380pub struct SubmitPackageTxResultFees {
381    /// Transaction fee.
382    #[serde(rename = "base")]
383    pub base_fee: f64,
384    /// The effective feerate.
385    ///
386    /// Will be `None` if the transaction was already in the mempool. For example, the package
387    /// feerate and/or feerate with modified fees from the `prioritisetransaction` JSON-RPC method.
388    #[serde(rename = "effective-feerate")]
389    pub effective_fee_rate: Option<f64>,
390    /// If [`Self::effective_fee_rate`] is provided, this holds the wtxid's of the transactions
391    /// whose fees and vsizes are included in effective-feerate.
392    #[serde(rename = "effective-includes")]
393    pub effective_includes: Option<Vec<String>>,
394}
395
396/// Result of JSON-RPC method `gettxout`.
397///
398/// # Note
399///
400/// This assumes that the UTXOs are present in the underlying Bitcoin
401/// client's wallet.
402#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
403pub struct GetTransactionDetail {
404    pub address: String,
405    pub category: GetTransactionDetailCategory,
406    pub amount: f64,
407    pub label: Option<String>,
408    pub vout: u32,
409    pub fee: Option<f64>,
410    pub abandoned: Option<bool>,
411}
412
413/// Enum to represent the category of a transaction.
414#[derive(Copy, Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
415#[serde(rename_all = "lowercase")]
416pub enum GetTransactionDetailCategory {
417    Send,
418    Receive,
419    Generate,
420    Immature,
421    Orphan,
422}
423
424/// Result of the JSON-RPC method `getnewaddress`.
425///
426/// # Note
427///
428/// This assumes that the UTXOs are present in the underlying Bitcoin
429/// client's wallet.
430#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
431pub struct GetNewAddress(pub String);
432
433impl GetNewAddress {
434    /// Converts json straight to a [`Address`].
435    pub fn address(self) -> Result<Address<NetworkUnchecked>, address::ParseError> {
436        let address = self.0.parse::<Address<_>>()?;
437        Ok(address)
438    }
439}
440
441/// Models the result of JSON-RPC method `listunspent`.
442///
443/// # Note
444///
445/// This assumes that the UTXOs are present in the underlying Bitcoin
446/// client's wallet.
447///
448/// Careful with the amount field. It is a [`SignedAmount`], hence can be negative.
449/// Negative amounts for the [`TransactionCategory::Send`], and is positive
450/// for all other categories.
451#[derive(Clone, Debug, PartialEq, Deserialize)]
452pub struct GetTransaction {
453    /// The signed amount in BTC.
454    #[serde(deserialize_with = "deserialize_signed_bitcoin")]
455    pub amount: SignedAmount,
456    /// The signed fee in BTC.
457    pub confirmations: u64,
458    pub generated: Option<bool>,
459    pub trusted: Option<bool>,
460    pub blockhash: Option<String>,
461    pub blockheight: Option<u64>,
462    pub blockindex: Option<u32>,
463    pub blocktime: Option<u64>,
464    /// The transaction id.
465    #[serde(deserialize_with = "deserialize_txid")]
466    pub txid: Txid,
467    pub wtxid: String,
468    pub walletconflicts: Vec<String>,
469    pub replaced_by_txid: Option<String>,
470    pub replaces_txid: Option<String>,
471    pub comment: Option<String>,
472    pub to: Option<String>,
473    pub time: u64,
474    pub timereceived: u64,
475    #[serde(rename = "bip125-replaceable")]
476    pub bip125_replaceable: String,
477    pub details: Vec<GetTransactionDetail>,
478    /// The transaction itself.
479    #[serde(deserialize_with = "deserialize_tx")]
480    pub hex: Transaction,
481}
482
483impl GetTransaction {
484    pub fn block_height(&self) -> u64 {
485        if self.confirmations == 0 {
486            return 0;
487        }
488        self.blockheight.unwrap_or_else(|| {
489            warn!("Txn confirmed but did not obtain blockheight. Setting height to zero");
490            0
491        })
492    }
493}
494
495/// Models the result of JSON-RPC method `listunspent`.
496///
497/// # Note
498///
499/// This assumes that the UTXOs are present in the underlying Bitcoin
500/// client's wallet.
501#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
502pub struct ListUnspent {
503    /// The transaction id.
504    #[serde(deserialize_with = "deserialize_txid")]
505    pub txid: Txid,
506    /// The vout value.
507    pub vout: u32,
508    /// The Bitcoin address.
509    #[serde(deserialize_with = "deserialize_address")]
510    pub address: Address<NetworkUnchecked>,
511    // The associated label, if any.
512    pub label: Option<String>,
513    /// The script pubkey.
514    #[serde(rename = "scriptPubKey")]
515    pub script_pubkey: String,
516    /// The transaction output amount in BTC.
517    #[serde(deserialize_with = "deserialize_bitcoin")]
518    pub amount: Amount,
519    /// The number of confirmations.
520    pub confirmations: u32,
521    /// Whether we have the private keys to spend this output.
522    pub spendable: bool,
523    /// Whether we know how to spend this output, ignoring the lack of keys.
524    pub solvable: bool,
525    /// Whether this output is considered safe to spend.
526    /// Unconfirmed transactions from outside keys and unconfirmed replacement
527    /// transactions are considered unsafe and are not eligible for spending by
528    /// `fundrawtransaction` and `sendtoaddress`.
529    pub safe: bool,
530}
531
532/// Models the result of JSON-RPC method `listtransactions`.
533///
534/// # Note
535///
536/// This assumes that the transactions are present in the underlying Bitcoin
537/// client's wallet.
538///
539/// Careful with the amount field. It is a [`SignedAmount`], hence can be negative.
540/// Negative amounts for the [`TransactionCategory::Send`], and is positive
541/// for all other categories.
542#[derive(Clone, Debug, PartialEq, Deserialize)]
543pub struct ListTransactions {
544    /// The Bitcoin address.
545    #[serde(deserialize_with = "deserialize_address")]
546    pub address: Address<NetworkUnchecked>,
547    /// Category of the transaction.
548    category: TransactionCategory,
549    /// The signed amount in BTC.
550    #[serde(deserialize_with = "deserialize_signed_bitcoin")]
551    pub amount: SignedAmount,
552    /// The label associated with the address, if any.
553    pub label: Option<String>,
554    /// The number of confirmations.
555    pub confirmations: u32,
556    pub trusted: Option<bool>,
557    pub generated: Option<bool>,
558    pub blockhash: Option<String>,
559    pub blockheight: Option<u64>,
560    pub blockindex: Option<u32>,
561    pub blocktime: Option<u64>,
562    /// The transaction id.
563    #[serde(deserialize_with = "deserialize_txid")]
564    pub txid: Txid,
565}
566
567/// Models the result of JSON-RPC method `testmempoolaccept`.
568#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
569pub struct TestMempoolAccept {
570    /// The transaction id.
571    #[serde(deserialize_with = "deserialize_txid")]
572    pub txid: Txid,
573    /// Rejection reason, if any.
574    pub reject_reason: Option<String>,
575}
576
577/// Models the result of JSON-RPC method `signrawtransactionwithwallet`.
578///
579/// # Note
580///
581/// This assumes that the transactions are present in the underlying Bitcoin
582/// client's wallet.
583#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
584pub struct SignRawTransactionWithWallet {
585    /// The Transaction ID.
586    pub hex: String,
587    /// If the transaction has a complete set of signatures.
588    pub complete: bool,
589    /// Errors, if any.
590    pub errors: Option<Vec<SignRawTransactionWithWalletError>>,
591}
592
593/// Models the optional previous transaction outputs argument for the method
594/// `signrawtransactionwithwallet`.
595///
596/// These are the outputs that this transaction depends on but may not yet be in the block chain.
597/// Widely used for One Parent One Child (1P1C) Relay in Bitcoin >28.0.
598///
599/// > transaction outputs
600/// > [
601/// > {                            (json object)
602/// > "txid": "hex",             (string, required) The transaction id
603/// > "vout": n,                 (numeric, required) The output number
604/// > "scriptPubKey": "hex",     (string, required) The output script
605/// > "redeemScript": "hex",     (string, optional) (required for P2SH) redeem script
606/// > "witnessScript": "hex",    (string, optional) (required for P2WSH or P2SH-P2WSH) witness
607/// > script
608/// > "amount": amount,          (numeric or string, optional) (required for Segwit inputs) the
609/// > amount spent
610/// > },
611/// > ...
612/// > ]
613#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
614pub struct PreviousTransactionOutput {
615    /// The transaction id.
616    #[serde(deserialize_with = "deserialize_txid")]
617    pub txid: Txid,
618    /// The output number.
619    pub vout: u32,
620    /// The output script.
621    #[serde(rename = "scriptPubKey")]
622    pub script_pubkey: String,
623    /// The redeem script.
624    #[serde(rename = "redeemScript")]
625    pub redeem_script: Option<String>,
626    /// The witness script.
627    #[serde(rename = "witnessScript")]
628    pub witness_script: Option<String>,
629    /// The amount spent.
630    pub amount: Option<f64>,
631}
632
633/// Models the result of the JSON-RPC method `listdescriptors`.
634#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
635pub struct ListDescriptors {
636    /// The descriptors
637    pub descriptors: Vec<ListDescriptor>,
638}
639
640/// Models the Descriptor in the result of the JSON-RPC method `listdescriptors`.
641#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
642pub struct ListDescriptor {
643    /// The descriptor.
644    pub desc: String,
645}
646
647/// Models the result of the JSON-RPC method `importdescriptors`.
648#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
649pub struct ImportDescriptors {
650    /// The descriptors
651    pub descriptors: Vec<ListDescriptor>,
652}
653
654/// Models the Descriptor in the result of the JSON-RPC method `importdescriptors`.
655#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
656pub struct ImportDescriptor {
657    /// The descriptor.
658    pub desc: String,
659    /// Set this descriptor to be the active descriptor
660    /// for the corresponding output type/externality.
661    pub active: Option<bool>,
662    /// Time from which to start rescanning the blockchain for this descriptor,
663    /// in UNIX epoch time. Can also be a string "now"
664    pub timestamp: String,
665}
666/// Models the Descriptor in the result of the JSON-RPC method `importdescriptors`.
667#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
668pub struct ImportDescriptorResult {
669    /// Result.
670    pub success: bool,
671}
672
673/// Models the `createwallet` JSON-RPC method.
674///
675/// # Note
676///
677/// This can also be used for the `loadwallet` JSON-RPC method.
678#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
679pub struct CreateWallet {
680    /// Wallet name
681    pub wallet_name: String,
682    /// Load on startup
683    pub load_on_startup: Option<bool>,
684}
685
686/// Deserializes the amount in BTC into proper [`Amount`]s.
687fn deserialize_bitcoin<'d, D>(deserializer: D) -> Result<Amount, D::Error>
688where
689    D: Deserializer<'d>,
690{
691    struct SatVisitor;
692
693    impl Visitor<'_> for SatVisitor {
694        type Value = Amount;
695
696        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
697            write!(formatter, "a float representation of btc values expected")
698        }
699
700        fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
701        where
702            E: de::Error,
703        {
704            let amount = Amount::from_btc(v).expect("Amount deserialization failed");
705            Ok(amount)
706        }
707    }
708    deserializer.deserialize_any(SatVisitor)
709}
710
711/// Deserializes the *signed* amount in BTC into proper [`SignedAmount`]s.
712fn deserialize_signed_bitcoin<'d, D>(deserializer: D) -> Result<SignedAmount, D::Error>
713where
714    D: Deserializer<'d>,
715{
716    struct SatVisitor;
717
718    impl Visitor<'_> for SatVisitor {
719        type Value = SignedAmount;
720
721        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
722            write!(formatter, "a float representation of btc values expected")
723        }
724
725        fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
726        where
727            E: de::Error,
728        {
729            let signed_amount = SignedAmount::from_btc(v).expect("Amount deserialization failed");
730            Ok(signed_amount)
731        }
732    }
733    deserializer.deserialize_any(SatVisitor)
734}
735
736/// Deserializes the *signed* amount in BTC into proper [`SignedAmount`]s.
737#[expect(dead_code)]
738fn deserialize_signed_bitcoin_option<'d, D>(
739    deserializer: D,
740) -> Result<Option<SignedAmount>, D::Error>
741where
742    D: Deserializer<'d>,
743{
744    let f: Option<f64> = Option::deserialize(deserializer)?;
745    match f {
746        Some(v) => deserialize_signed_bitcoin(v.into_deserializer()).map(Some),
747        None => Ok(None),
748    }
749}
750
751/// Deserializes the transaction id string into proper [`Txid`]s.
752fn deserialize_txid<'d, D>(deserializer: D) -> Result<Txid, D::Error>
753where
754    D: Deserializer<'d>,
755{
756    struct TxidVisitor;
757
758    impl Visitor<'_> for TxidVisitor {
759        type Value = Txid;
760
761        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
762            write!(formatter, "a transaction id string expected")
763        }
764
765        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
766        where
767            E: de::Error,
768        {
769            let txid = v.parse::<Txid>().expect("invalid txid");
770
771            Ok(txid)
772        }
773    }
774    deserializer.deserialize_any(TxidVisitor)
775}
776
777/// Deserializes the transaction hex string into proper [`Transaction`]s.
778fn deserialize_tx<'d, D>(deserializer: D) -> Result<Transaction, D::Error>
779where
780    D: Deserializer<'d>,
781{
782    struct TxVisitor;
783
784    impl Visitor<'_> for TxVisitor {
785        type Value = Transaction;
786
787        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
788            write!(formatter, "a transaction hex string expected")
789        }
790
791        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
792        where
793            E: de::Error,
794        {
795            let tx = consensus::encode::deserialize_hex::<Transaction>(v)
796                .expect("failed to deserialize tx hex");
797            Ok(tx)
798        }
799    }
800    deserializer.deserialize_any(TxVisitor)
801}
802
803/// Deserializes the address string into proper [`Address`]s.
804///
805/// # Note
806///
807/// The user is responsible for ensuring that the address is valid,
808/// since this functions returns an [`Address<NetworkUnchecked>`].
809fn deserialize_address<'d, D>(deserializer: D) -> Result<Address<NetworkUnchecked>, D::Error>
810where
811    D: Deserializer<'d>,
812{
813    struct AddressVisitor;
814    impl Visitor<'_> for AddressVisitor {
815        type Value = Address<NetworkUnchecked>;
816
817        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
818            write!(formatter, "a Bitcoin address string expected")
819        }
820
821        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
822        where
823            E: de::Error,
824        {
825            let address = v
826                .parse::<Address<_>>()
827                .expect("Address deserialization failed");
828            Ok(address)
829        }
830    }
831    deserializer.deserialize_any(AddressVisitor)
832}
833
834/// Deserializes the blockhash string into proper [`BlockHash`]s.
835#[expect(dead_code)]
836fn deserialize_blockhash<'d, D>(deserializer: D) -> Result<BlockHash, D::Error>
837where
838    D: Deserializer<'d>,
839{
840    struct BlockHashVisitor;
841
842    impl Visitor<'_> for BlockHashVisitor {
843        type Value = BlockHash;
844
845        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
846            write!(formatter, "a blockhash string expected")
847        }
848
849        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
850        where
851            E: de::Error,
852        {
853            let blockhash = consensus::encode::deserialize_hex::<BlockHash>(v)
854                .expect("BlockHash deserialization failed");
855            Ok(blockhash)
856        }
857    }
858    deserializer.deserialize_any(BlockHashVisitor)
859}
860
861/// Deserializes the height string into proper [`Height`]s.
862#[expect(dead_code)]
863fn deserialize_height<'d, D>(deserializer: D) -> Result<Height, D::Error>
864where
865    D: Deserializer<'d>,
866{
867    struct HeightVisitor;
868
869    impl Visitor<'_> for HeightVisitor {
870        type Value = Height;
871
872        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
873            write!(formatter, "a height u32 string expected")
874        }
875
876        fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
877        where
878            E: de::Error,
879        {
880            let height = Height::from_consensus(v).expect("Height deserialization failed");
881            Ok(height)
882        }
883    }
884    deserializer.deserialize_any(HeightVisitor)
885}