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 `getrawtransaction` with verbosity set to 1.
185///
186/// Method call: `getrawtransaction "txid" ( verbosity )`
187#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
188pub struct GetRawTransactionVerbosityOne {
189    pub in_active_chain: Option<bool>,
190    #[serde(deserialize_with = "deserialize_tx")]
191    #[serde(rename = "hex")]
192    pub transaction: Transaction,
193    pub txid: Txid,
194    pub hash: Wtxid,
195    pub size: usize,
196    pub vsize: usize,
197    pub version: u32,
198    pub locktime: u32,
199    pub blockhash: Option<BlockHash>,
200    pub confirmations: Option<u32>,
201    pub time: Option<usize>,
202    pub blocktime: Option<usize>,
203}
204
205/// Result of JSON-RPC method `gettxout`.
206///
207/// > gettxout "txid" n ( include_mempool )
208/// >
209/// > Returns details about an unspent transaction output.
210/// >
211/// > Arguments:
212/// > 1. txid               (string, required) The transaction id
213/// > 2. n                  (numeric, required) vout number
214#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
215pub struct GetTxOut {
216    /// The hash of the block at the tip of the chain.
217    #[serde(rename = "bestblock")]
218    pub best_block: String,
219    /// The number of confirmations.
220    pub confirmations: u32, // TODO: Change this to an i64.
221    /// The transaction value in BTC.
222    pub value: f64,
223    /// The script pubkey.
224    #[serde(rename = "scriptPubkey")]
225    pub script_pubkey: Option<ScriptPubkey>,
226    /// Coinbase or not.
227    pub coinbase: bool,
228}
229
230/// A script pubkey.
231#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
232pub struct ScriptPubkey {
233    /// Script assembly.
234    pub asm: String,
235    /// Script hex.
236    pub hex: String,
237    #[serde(rename = "reqSigs")]
238    pub req_sigs: i64,
239    /// The type, eg pubkeyhash.
240    #[serde(rename = "type")]
241    pub type_: String,
242    /// Bitcoin address.
243    pub address: Option<String>,
244}
245
246/// Models the arguments of JSON-RPC method `createrawtransaction`.
247///
248/// # Note
249///
250/// Assumes that the transaction is always "replaceable" by default and has a locktime of 0.
251#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
252pub struct CreateRawTransaction {
253    pub inputs: Vec<CreateRawTransactionInput>,
254    pub outputs: Vec<CreateRawTransactionOutput>,
255}
256
257/// Models the input of JSON-RPC method `createrawtransaction`.
258#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
259pub struct CreateRawTransactionInput {
260    pub txid: String,
261    pub vout: u32,
262}
263
264/// Models the output of JSON-RPC method `createrawtransaction`.
265///
266/// The outputs specified as key-value pairs, where the keys is an address,
267/// and the values are the amounts to be sent to that address.
268#[derive(Clone, Debug, PartialEq, Deserialize)]
269#[serde(untagged)]
270pub enum CreateRawTransactionOutput {
271    /// A pair of an [`Address`] string and an [`Amount`] in BTC.
272    AddressAmount {
273        /// An [`Address`] string.
274        address: String,
275        /// An [`Amount`] in BTC.
276        amount: f64,
277    },
278    /// A payload such as in `OP_RETURN` transactions.
279    Data {
280        /// The payload.
281        data: String,
282    },
283}
284
285impl Serialize for CreateRawTransactionOutput {
286    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
287    where
288        S: serde::Serializer,
289    {
290        match self {
291            CreateRawTransactionOutput::AddressAmount { address, amount } => {
292                let mut map = serde_json::Map::new();
293                map.insert(
294                    address.clone(),
295                    serde_json::Value::Number(serde_json::Number::from_f64(*amount).unwrap()),
296                );
297                map.serialize(serializer)
298            }
299            CreateRawTransactionOutput::Data { data } => {
300                let mut map = serde_json::Map::new();
301                map.insert("data".to_string(), serde_json::Value::String(data.clone()));
302                map.serialize(serializer)
303            }
304        }
305    }
306}
307
308/// Result of JSON-RPC method `submitpackage`.
309///
310/// > submitpackage ["rawtx",...] ( maxfeerate maxburnamount )
311/// >
312/// > Submit a package of raw transactions (serialized, hex-encoded) to local node.
313/// > The package will be validated according to consensus and mempool policy rules. If any
314/// > transaction passes, it will be accepted to mempool.
315/// > This RPC is experimental and the interface may be unstable. Refer to doc/policy/packages.md
316/// > for documentation on package policies.
317/// > Warning: successful submission does not mean the transactions will propagate throughout the
318/// > network.
319/// >
320/// > Arguments:
321/// > 1. package          (json array, required) An array of raw transactions.
322/// > The package must solely consist of a child and its parents. None of the parents may depend on
323/// > each other.
324/// > The package must be topologically sorted, with the child being the last element in the array.
325/// > [
326/// > "rawtx",     (string)
327/// > ...
328/// > ]
329#[allow(clippy::doc_lazy_continuation)]
330#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
331pub struct SubmitPackage {
332    /// The transaction package result message.
333    ///
334    /// "success" indicates all transactions were accepted into or are already in the mempool.
335    pub package_msg: String,
336    /// Transaction results keyed by wtxid.
337    #[serde(rename = "tx-results")]
338    pub tx_results: BTreeMap<String, SubmitPackageTxResult>,
339    /// List of txids of replaced transactions.
340    #[serde(rename = "replaced-transactions")]
341    pub replaced_transactions: Vec<String>,
342}
343
344/// Models the per-transaction result included in the JSON-RPC method `submitpackage`.
345#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
346pub struct SubmitPackageTxResult {
347    /// The transaction id.
348    pub txid: String,
349    /// The wtxid of a different transaction with the same txid but different witness found in the
350    /// mempool.
351    ///
352    /// If set, this means the submitted transaction was ignored.
353    #[serde(rename = "other-wtxid")]
354    pub other_wtxid: Option<String>,
355    /// Sigops-adjusted virtual transaction size.
356    pub vsize: i64,
357    /// Transaction fees.
358    pub fees: Option<SubmitPackageTxResultFees>,
359    /// The transaction error string, if it was rejected by the mempool
360    pub error: Option<String>,
361}
362
363/// Models the fees included in the per-transaction result of the JSON-RPC method `submitpackage`.
364#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
365pub struct SubmitPackageTxResultFees {
366    /// Transaction fee.
367    #[serde(rename = "base")]
368    pub base_fee: f64,
369    /// The effective feerate.
370    ///
371    /// Will be `None` if the transaction was already in the mempool. For example, the package
372    /// feerate and/or feerate with modified fees from the `prioritisetransaction` JSON-RPC method.
373    #[serde(rename = "effective-feerate")]
374    pub effective_fee_rate: Option<f64>,
375    /// If [`Self::effective_fee_rate`] is provided, this holds the wtxid's of the transactions
376    /// whose fees and vsizes are included in effective-feerate.
377    #[serde(rename = "effective-includes")]
378    pub effective_includes: Option<Vec<String>>,
379}
380
381/// Result of JSON-RPC method `gettxout`.
382///
383/// # Note
384///
385/// This assumes that the UTXOs are present in the underlying Bitcoin
386/// client's wallet.
387#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
388pub struct GetTransactionDetail {
389    pub address: String,
390    pub category: GetTransactionDetailCategory,
391    pub amount: f64,
392    pub label: Option<String>,
393    pub vout: u32,
394    pub fee: Option<f64>,
395    pub abandoned: Option<bool>,
396}
397
398/// Enum to represent the category of a transaction.
399#[derive(Copy, Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
400#[serde(rename_all = "lowercase")]
401pub enum GetTransactionDetailCategory {
402    Send,
403    Receive,
404    Generate,
405    Immature,
406    Orphan,
407}
408
409/// Result of the JSON-RPC method `getnewaddress`.
410///
411/// # Note
412///
413/// This assumes that the UTXOs are present in the underlying Bitcoin
414/// client's wallet.
415#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
416pub struct GetNewAddress(pub String);
417
418impl GetNewAddress {
419    /// Converts json straight to a [`Address`].
420    pub fn address(self) -> Result<Address<NetworkUnchecked>, address::ParseError> {
421        let address = self.0.parse::<Address<_>>()?;
422        Ok(address)
423    }
424}
425
426/// Models the result of JSON-RPC method `listunspent`.
427///
428/// # Note
429///
430/// This assumes that the UTXOs are present in the underlying Bitcoin
431/// client's wallet.
432///
433/// Careful with the amount field. It is a [`SignedAmount`], hence can be negative.
434/// Negative amounts for the [`TransactionCategory::Send`], and is positive
435/// for all other categories.
436#[derive(Clone, Debug, PartialEq, Deserialize)]
437pub struct GetTransaction {
438    /// The signed amount in BTC.
439    #[serde(deserialize_with = "deserialize_signed_bitcoin")]
440    pub amount: SignedAmount,
441    /// The signed fee in BTC.
442    pub confirmations: u64,
443    pub generated: Option<bool>,
444    pub trusted: Option<bool>,
445    pub blockhash: Option<String>,
446    pub blockheight: Option<u64>,
447    pub blockindex: Option<u32>,
448    pub blocktime: Option<u64>,
449    /// The transaction id.
450    #[serde(deserialize_with = "deserialize_txid")]
451    pub txid: Txid,
452    pub wtxid: String,
453    pub walletconflicts: Vec<String>,
454    pub replaced_by_txid: Option<String>,
455    pub replaces_txid: Option<String>,
456    pub comment: Option<String>,
457    pub to: Option<String>,
458    pub time: u64,
459    pub timereceived: u64,
460    #[serde(rename = "bip125-replaceable")]
461    pub bip125_replaceable: String,
462    pub details: Vec<GetTransactionDetail>,
463    /// The transaction itself.
464    #[serde(deserialize_with = "deserialize_tx")]
465    pub hex: Transaction,
466}
467
468impl GetTransaction {
469    pub fn block_height(&self) -> u64 {
470        if self.confirmations == 0 {
471            return 0;
472        }
473        self.blockheight.unwrap_or_else(|| {
474            warn!("Txn confirmed but did not obtain blockheight. Setting height to zero");
475            0
476        })
477    }
478}
479
480/// Models the result of JSON-RPC method `listunspent`.
481///
482/// # Note
483///
484/// This assumes that the UTXOs are present in the underlying Bitcoin
485/// client's wallet.
486#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
487pub struct ListUnspent {
488    /// The transaction id.
489    #[serde(deserialize_with = "deserialize_txid")]
490    pub txid: Txid,
491    /// The vout value.
492    pub vout: u32,
493    /// The Bitcoin address.
494    #[serde(deserialize_with = "deserialize_address")]
495    pub address: Address<NetworkUnchecked>,
496    // The associated label, if any.
497    pub label: Option<String>,
498    /// The script pubkey.
499    #[serde(rename = "scriptPubKey")]
500    pub script_pubkey: String,
501    /// The transaction output amount in BTC.
502    #[serde(deserialize_with = "deserialize_bitcoin")]
503    pub amount: Amount,
504    /// The number of confirmations.
505    pub confirmations: u32,
506    /// Whether we have the private keys to spend this output.
507    pub spendable: bool,
508    /// Whether we know how to spend this output, ignoring the lack of keys.
509    pub solvable: bool,
510    /// Whether this output is considered safe to spend.
511    /// Unconfirmed transactions from outside keys and unconfirmed replacement
512    /// transactions are considered unsafe and are not eligible for spending by
513    /// `fundrawtransaction` and `sendtoaddress`.
514    pub safe: bool,
515}
516
517/// Models the result of JSON-RPC method `listtransactions`.
518///
519/// # Note
520///
521/// This assumes that the transactions are present in the underlying Bitcoin
522/// client's wallet.
523///
524/// Careful with the amount field. It is a [`SignedAmount`], hence can be negative.
525/// Negative amounts for the [`TransactionCategory::Send`], and is positive
526/// for all other categories.
527#[derive(Clone, Debug, PartialEq, Deserialize)]
528pub struct ListTransactions {
529    /// The Bitcoin address.
530    #[serde(deserialize_with = "deserialize_address")]
531    pub address: Address<NetworkUnchecked>,
532    /// Category of the transaction.
533    category: TransactionCategory,
534    /// The signed amount in BTC.
535    #[serde(deserialize_with = "deserialize_signed_bitcoin")]
536    pub amount: SignedAmount,
537    /// The label associated with the address, if any.
538    pub label: Option<String>,
539    /// The number of confirmations.
540    pub confirmations: u32,
541    pub trusted: Option<bool>,
542    pub generated: Option<bool>,
543    pub blockhash: Option<String>,
544    pub blockheight: Option<u64>,
545    pub blockindex: Option<u32>,
546    pub blocktime: Option<u64>,
547    /// The transaction id.
548    #[serde(deserialize_with = "deserialize_txid")]
549    pub txid: Txid,
550}
551
552/// Models the result of JSON-RPC method `testmempoolaccept`.
553#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
554pub struct TestMempoolAccept {
555    /// The transaction id.
556    #[serde(deserialize_with = "deserialize_txid")]
557    pub txid: Txid,
558    /// Rejection reason, if any.
559    pub reject_reason: Option<String>,
560}
561
562/// Models the result of JSON-RPC method `signrawtransactionwithwallet`.
563///
564/// # Note
565///
566/// This assumes that the transactions are present in the underlying Bitcoin
567/// client's wallet.
568#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
569pub struct SignRawTransactionWithWallet {
570    /// The Transaction ID.
571    pub hex: String,
572    /// If the transaction has a complete set of signatures.
573    pub complete: bool,
574    /// Errors, if any.
575    pub errors: Option<Vec<SignRawTransactionWithWalletError>>,
576}
577
578/// Models the optional previous transaction outputs argument for the method
579/// `signrawtransactionwithwallet`.
580///
581/// These are the outputs that this transaction depends on but may not yet be in the block chain.
582/// Widely used for One Parent One Child (1P1C) Relay in Bitcoin >28.0.
583///
584/// > transaction outputs
585/// > [
586/// > {                            (json object)
587/// > "txid": "hex",             (string, required) The transaction id
588/// > "vout": n,                 (numeric, required) The output number
589/// > "scriptPubKey": "hex",     (string, required) The output script
590/// > "redeemScript": "hex",     (string, optional) (required for P2SH) redeem script
591/// > "witnessScript": "hex",    (string, optional) (required for P2WSH or P2SH-P2WSH) witness
592/// > script
593/// > "amount": amount,          (numeric or string, optional) (required for Segwit inputs) the
594/// > amount spent
595/// > },
596/// > ...
597/// > ]
598#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
599pub struct PreviousTransactionOutput {
600    /// The transaction id.
601    #[serde(deserialize_with = "deserialize_txid")]
602    pub txid: Txid,
603    /// The output number.
604    pub vout: u32,
605    /// The output script.
606    #[serde(rename = "scriptPubKey")]
607    pub script_pubkey: String,
608    /// The redeem script.
609    #[serde(rename = "redeemScript")]
610    pub redeem_script: Option<String>,
611    /// The witness script.
612    #[serde(rename = "witnessScript")]
613    pub witness_script: Option<String>,
614    /// The amount spent.
615    pub amount: Option<f64>,
616}
617
618/// Models the result of the JSON-RPC method `listdescriptors`.
619#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
620pub struct ListDescriptors {
621    /// The descriptors
622    pub descriptors: Vec<ListDescriptor>,
623}
624
625/// Models the Descriptor in the result of the JSON-RPC method `listdescriptors`.
626#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
627pub struct ListDescriptor {
628    /// The descriptor.
629    pub desc: String,
630}
631
632/// Models the result of the JSON-RPC method `importdescriptors`.
633#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
634pub struct ImportDescriptors {
635    /// The descriptors
636    pub descriptors: Vec<ListDescriptor>,
637}
638
639/// Models the Descriptor in the result of the JSON-RPC method `importdescriptors`.
640#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
641pub struct ImportDescriptor {
642    /// The descriptor.
643    pub desc: String,
644    /// Set this descriptor to be the active descriptor
645    /// for the corresponding output type/externality.
646    pub active: Option<bool>,
647    /// Time from which to start rescanning the blockchain for this descriptor,
648    /// in UNIX epoch time. Can also be a string "now"
649    pub timestamp: String,
650}
651/// Models the Descriptor in the result of the JSON-RPC method `importdescriptors`.
652#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
653pub struct ImportDescriptorResult {
654    /// Result.
655    pub success: bool,
656}
657
658/// Models the `createwallet` JSON-RPC method.
659///
660/// # Note
661///
662/// This can also be used for the `loadwallet` JSON-RPC method.
663#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
664pub struct CreateWallet {
665    /// Wallet name
666    pub wallet_name: String,
667    /// Load on startup
668    pub load_on_startup: Option<bool>,
669}
670
671/// Deserializes the amount in BTC into proper [`Amount`]s.
672fn deserialize_bitcoin<'d, D>(deserializer: D) -> Result<Amount, D::Error>
673where
674    D: Deserializer<'d>,
675{
676    struct SatVisitor;
677
678    impl Visitor<'_> for SatVisitor {
679        type Value = Amount;
680
681        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
682            write!(formatter, "a float representation of btc values expected")
683        }
684
685        fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
686        where
687            E: de::Error,
688        {
689            let amount = Amount::from_btc(v).expect("Amount deserialization failed");
690            Ok(amount)
691        }
692    }
693    deserializer.deserialize_any(SatVisitor)
694}
695
696/// Deserializes the *signed* amount in BTC into proper [`SignedAmount`]s.
697fn deserialize_signed_bitcoin<'d, D>(deserializer: D) -> Result<SignedAmount, D::Error>
698where
699    D: Deserializer<'d>,
700{
701    struct SatVisitor;
702
703    impl Visitor<'_> for SatVisitor {
704        type Value = SignedAmount;
705
706        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
707            write!(formatter, "a float representation of btc values expected")
708        }
709
710        fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
711        where
712            E: de::Error,
713        {
714            let signed_amount = SignedAmount::from_btc(v).expect("Amount deserialization failed");
715            Ok(signed_amount)
716        }
717    }
718    deserializer.deserialize_any(SatVisitor)
719}
720
721/// Deserializes the *signed* amount in BTC into proper [`SignedAmount`]s.
722#[expect(dead_code)]
723fn deserialize_signed_bitcoin_option<'d, D>(
724    deserializer: D,
725) -> Result<Option<SignedAmount>, D::Error>
726where
727    D: Deserializer<'d>,
728{
729    let f: Option<f64> = Option::deserialize(deserializer)?;
730    match f {
731        Some(v) => deserialize_signed_bitcoin(v.into_deserializer()).map(Some),
732        None => Ok(None),
733    }
734}
735
736/// Deserializes the transaction id string into proper [`Txid`]s.
737fn deserialize_txid<'d, D>(deserializer: D) -> Result<Txid, D::Error>
738where
739    D: Deserializer<'d>,
740{
741    struct TxidVisitor;
742
743    impl Visitor<'_> for TxidVisitor {
744        type Value = Txid;
745
746        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
747            write!(formatter, "a transaction id string expected")
748        }
749
750        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
751        where
752            E: de::Error,
753        {
754            let txid = v.parse::<Txid>().expect("invalid txid");
755
756            Ok(txid)
757        }
758    }
759    deserializer.deserialize_any(TxidVisitor)
760}
761
762/// Deserializes the transaction hex string into proper [`Transaction`]s.
763fn deserialize_tx<'d, D>(deserializer: D) -> Result<Transaction, D::Error>
764where
765    D: Deserializer<'d>,
766{
767    struct TxVisitor;
768
769    impl Visitor<'_> for TxVisitor {
770        type Value = Transaction;
771
772        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
773            write!(formatter, "a transaction hex string expected")
774        }
775
776        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
777        where
778            E: de::Error,
779        {
780            let tx = consensus::encode::deserialize_hex::<Transaction>(v)
781                .expect("failed to deserialize tx hex");
782            Ok(tx)
783        }
784    }
785    deserializer.deserialize_any(TxVisitor)
786}
787
788/// Deserializes the address string into proper [`Address`]s.
789///
790/// # Note
791///
792/// The user is responsible for ensuring that the address is valid,
793/// since this functions returns an [`Address<NetworkUnchecked>`].
794fn deserialize_address<'d, D>(deserializer: D) -> Result<Address<NetworkUnchecked>, D::Error>
795where
796    D: Deserializer<'d>,
797{
798    struct AddressVisitor;
799    impl Visitor<'_> for AddressVisitor {
800        type Value = Address<NetworkUnchecked>;
801
802        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
803            write!(formatter, "a Bitcoin address string expected")
804        }
805
806        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
807        where
808            E: de::Error,
809        {
810            let address = v
811                .parse::<Address<_>>()
812                .expect("Address deserialization failed");
813            Ok(address)
814        }
815    }
816    deserializer.deserialize_any(AddressVisitor)
817}
818
819/// Deserializes the blockhash string into proper [`BlockHash`]s.
820#[expect(dead_code)]
821fn deserialize_blockhash<'d, D>(deserializer: D) -> Result<BlockHash, D::Error>
822where
823    D: Deserializer<'d>,
824{
825    struct BlockHashVisitor;
826
827    impl Visitor<'_> for BlockHashVisitor {
828        type Value = BlockHash;
829
830        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
831            write!(formatter, "a blockhash string expected")
832        }
833
834        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
835        where
836            E: de::Error,
837        {
838            let blockhash = consensus::encode::deserialize_hex::<BlockHash>(v)
839                .expect("BlockHash deserialization failed");
840            Ok(blockhash)
841        }
842    }
843    deserializer.deserialize_any(BlockHashVisitor)
844}
845
846/// Deserializes the height string into proper [`Height`]s.
847#[expect(dead_code)]
848fn deserialize_height<'d, D>(deserializer: D) -> Result<Height, D::Error>
849where
850    D: Deserializer<'d>,
851{
852    struct HeightVisitor;
853
854    impl Visitor<'_> for HeightVisitor {
855        type Value = Height;
856
857        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
858            write!(formatter, "a height u32 string expected")
859        }
860
861        fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
862        where
863            E: de::Error,
864        {
865            let height = Height::from_consensus(v).expect("Height deserialization failed");
866            Ok(height)
867        }
868    }
869    deserializer.deserialize_any(HeightVisitor)
870}