liquid_rpc/
lib.rs

1// To the extent possible under law, the author(s) have dedicated all
2// copyright and related and neighboring rights to this software to
3// the public domain worldwide. This software is distributed without
4// any warranty.
5//
6// You should have received a copy of the CC0 Public Domain Dedication
7// along with this software.
8// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
9//
10
11//! # Rust Client for Liquid API
12//!
13//! This is a client library for the Liquid JSON-RPC API.
14//!
15
16#![crate_name = "liquid_rpc"]
17#![crate_type = "rlib"]
18
19pub extern crate bitcoincore_rpc;
20pub extern crate elements;
21pub extern crate jsonrpc;
22extern crate serde;
23extern crate serde_json;
24
25pub extern crate liquid_rpc_json;
26pub use json::{bitcoin_asset, AssetId, BITCOIN_ASSET_HEX};
27pub use liquid_rpc_json as json;
28
29mod error;
30
31pub use error::Error;
32pub use bitcoincore_rpc::json as btcjson;
33pub use bitcoincore_rpc::Auth;
34
35pub type Result<T> = ::std::result::Result<T, Error>;
36
37use std::collections::HashMap;
38
39use elements::bitcoin;
40
41use bitcoin::hashes::hex::{FromHex, ToHex};
42use bitcoin::util::bip32;
43//TODO(stevenroose) use secp public key as soon as it has hex serde
44use bitcoin::{PublicKey, Script};
45use bitcoin::hashes::sha256d;
46use bitcoin::secp256k1::SecretKey;
47use bitcoin::util::amount::{self, Amount};
48use elements::encode;
49
50/// Serialize an amount returned by the RPC.
51fn ser_amount(amount: &Amount) -> serde_json::Value {
52    amount.to_float_in(amount::Denomination::Bitcoin).into()
53}
54
55fn deser_amount(val: serde_json::Value) -> Result<Amount> {
56    Amount::from_float_in(val.as_f64().unwrap(), amount::Denomination::Bitcoin).map_err(From::from)
57}
58
59fn convert_balances(balances: HashMap<String, serde_json::Value>) -> Result<HashMap<String, Amount>> {
60    let mut ret = HashMap::new();
61    for (k, v) in balances.into_iter() {
62        ret.insert(k, deser_amount(v)?);
63    }
64    Ok(ret)
65}
66
67/// Shorthand for converting a variable into a serde_json::Value.
68fn into_json<T>(val: T) -> Result<serde_json::Value>
69where
70    T: serde::ser::Serialize,
71{
72    Ok(serde_json::to_value(val)?)
73}
74
75/// Shorthand for converting bytes into a serde_json::Value.
76fn into_json_hex<T: AsRef<[u8]>>(val: T) -> Result<serde_json::Value> {
77    Ok(serde_json::to_value(val.as_ref().to_hex())?)
78}
79
80/// Shorthand for converting an Option into an Option<serde_json::Value>.
81fn opt_into_json<T>(opt: Option<T>) -> Result<serde_json::Value>
82where
83    T: serde::ser::Serialize,
84{
85    match opt {
86        Some(val) => Ok(into_json(val)?),
87        None => Ok(serde_json::Value::Null),
88    }
89}
90
91/// Shorthand for converting bytes into a serde_json::Value.
92fn opt_into_json_hex<T: AsRef<[u8]>>(opt: Option<T>) -> Result<serde_json::Value> {
93    match opt {
94        Some(b) => Ok(serde_json::to_value(b.as_ref().to_hex())?),
95        None => Ok(serde_json::Value::Null),
96    }
97}
98
99/// Shorthand for `serde_json::Value::Null`.
100fn null() -> serde_json::Value {
101    serde_json::Value::Null
102}
103
104/// Shorthand for an empty serde_json::Value array.
105fn empty() -> serde_json::Value {
106    serde_json::Value::Array(vec![])
107}
108
109/// Shorthand for an empty serde_json object.
110fn empty_obj() -> serde_json::Value {
111    serde_json::Value::Object(Default::default())
112}
113
114/// Handle default values in the argument list
115///
116/// Substitute `Value::Null`s with corresponding values from `defaults` table,
117/// except when they are trailing, in which case just skip them altogether
118/// in returned list.
119///
120/// Note, that `defaults` corresponds to the last elements of `args`.
121///
122/// ```norust
123/// arg1 arg2 arg3 arg4
124///           def1 def2
125/// ```
126///
127/// Elements of `args` without corresponding `defaults` value, won't
128/// be substituted, because they are required.
129fn handle_defaults<'a, 'b>(
130    args: &'a mut [serde_json::Value],
131    defaults: &'b [serde_json::Value],
132) -> &'a [serde_json::Value] {
133    assert!(args.len() >= defaults.len());
134
135    // Pass over the optional arguments in backwards order, filling in defaults after the first
136    // non-null optional argument has been observed.
137    let mut first_non_null_optional_idx = None;
138    for i in 0..defaults.len() {
139        let args_i = args.len() - 1 - i;
140        let defaults_i = defaults.len() - 1 - i;
141        if args[args_i] == serde_json::Value::Null {
142            if first_non_null_optional_idx.is_some() {
143                if defaults[defaults_i] == serde_json::Value::Null {
144                    panic!("Missing `default` for argument idx {}", args_i);
145                }
146                args[args_i] = defaults[defaults_i].clone();
147            }
148        } else if first_non_null_optional_idx.is_none() {
149            first_non_null_optional_idx = Some(args_i);
150        }
151    }
152
153    let required_num = args.len() - defaults.len();
154
155    if let Some(i) = first_non_null_optional_idx {
156        &args[..i + 1]
157    } else {
158        &args[..required_num]
159    }
160}
161
162/// Convert a possible-null result into an Option.
163fn opt_result<T: for<'a> serde::de::Deserialize<'a>>(
164    result: serde_json::Value,
165) -> Result<Option<T>> {
166    if result == serde_json::Value::Null {
167        Ok(None)
168    } else {
169        Ok(serde_json::from_value(result)?)
170    }
171}
172
173/// Used to pass raw txs into the API.
174pub trait RawTx: Sized {
175    fn raw_hex(self) -> String;
176}
177
178impl<'a> RawTx for &'a elements::Transaction {
179    fn raw_hex(self) -> String {
180        encode::serialize(self).to_hex()
181    }
182}
183
184impl<'a> RawTx for &'a [u8] {
185    fn raw_hex(self) -> String {
186        self.to_hex()
187    }
188}
189
190impl<'a> RawTx for &'a Vec<u8> {
191    fn raw_hex(self) -> String {
192        self.to_hex()
193    }
194}
195
196impl<'a> RawTx for &'a str {
197    fn raw_hex(self) -> String {
198        self.to_owned()
199    }
200}
201
202impl RawTx for String {
203    fn raw_hex(self) -> String {
204        self
205    }
206}
207
208/// Trait implementing the Liquid RPC commands.
209pub trait LiquidRpcApi: Sized {
210    fn call<T: for<'a> serde::de::Deserialize<'a>>(
211        &self,
212        cmd: &str,
213        args: &[serde_json::Value],
214    ) -> Result<T>;
215
216    fn get_block_header_raw(&self, hash: &sha256d::Hash) -> Result<elements::BlockHeader> {
217        let hex: String = self.call("getblockheader", &[into_json(hash)?, false.into()])?;
218        let bytes = Vec::<u8>::from_hex(&hex)?;
219        Ok(encode::deserialize(&bytes)?)
220    }
221
222    fn get_block_header_verbose(&self, hash: &sha256d::Hash) -> Result<json::GetBlockHeaderResult> {
223        self.call("getblockheader", &[into_json(hash)?, true.into()])
224    }
225
226    /// Returns a data structure containing various state info regarding
227    /// blockchain processing.
228    fn get_blockchain_info(&self) -> Result<json::GetBlockchainInfoResult> {
229        self.call("getblockchaininfo", &[])
230    }
231
232    fn get_raw_transaction(
233        &self,
234        txid: &sha256d::Hash,
235        block_hash: Option<&sha256d::Hash>,
236    ) -> Result<elements::Transaction> {
237        let mut args = [into_json(txid)?, into_json(false)?, opt_into_json(block_hash)?];
238        let hex: String = self.call("getrawtransaction", handle_defaults(&mut args, &[null()]))?;
239        let bytes = Vec::<u8>::from_hex(&hex)?;
240        Ok(encode::deserialize(&bytes)?)
241    }
242
243    fn get_raw_transaction_verbose(
244        &self,
245        txid: &sha256d::Hash,
246        block_hash: Option<&sha256d::Hash>,
247    ) -> Result<json::GetRawTransactionResult> {
248        let mut args = [into_json(txid)?, into_json(true)?, opt_into_json(block_hash)?];
249        self.call("getrawtransaction", handle_defaults(&mut args, &[null()]))
250    }
251
252    fn send_to_address(
253        &self,
254        address: &str,
255        amount: f64,
256        comment: Option<&str>,
257        comment_to: Option<&str>,
258        substract_fee: Option<bool>,
259        replaceable: Option<bool>,
260        confirmation_target: Option<u32>,
261        estimate_mode: Option<btcjson::EstimateMode>,
262        asset_label: Option<&str>,
263        ignore_blind_fail: Option<bool>,
264    ) -> Result<sha256d::Hash> {
265        let mut args = [
266            address.into(),
267            into_json(amount)?,
268            opt_into_json(comment)?,
269            opt_into_json(comment_to)?,
270            opt_into_json(substract_fee)?,
271            opt_into_json(replaceable)?,
272            opt_into_json(confirmation_target)?,
273            opt_into_json(estimate_mode)?,
274            opt_into_json(asset_label)?,
275            opt_into_json(ignore_blind_fail)?,
276        ];
277        self.call("sendtoaddress", handle_defaults(&mut args, &vec![null(); 8]))
278    }
279
280    fn create_raw_transaction_hex(
281        &self,
282        utxos: &[btcjson::CreateRawTransactionInput],
283        outs: &HashMap<String, f64>,
284        locktime: Option<i64>,
285        replaceable: Option<bool>,
286        assets: Option<&HashMap<String, AssetId>>,
287    ) -> Result<String> {
288        let mut args = [
289            into_json(utxos)?,
290            into_json(outs)?,
291            opt_into_json(locktime)?,
292            opt_into_json(replaceable)?,
293            opt_into_json(assets)?,
294        ];
295        let defaults = [into_json(0i64)?, false.into(), null()];
296        self.call("createrawtransaction", handle_defaults(&mut args, &defaults))
297    }
298
299    fn create_raw_transaction(
300        &self,
301        utxos: &[btcjson::CreateRawTransactionInput],
302        outs: &HashMap<String, f64>,
303        locktime: Option<i64>,
304        replaceable: Option<bool>,
305        assets: Option<&HashMap<String, AssetId>>,
306    ) -> Result<elements::Transaction> {
307        let hex: String =
308            self.create_raw_transaction_hex(utxos, outs, locktime, replaceable, assets)?;
309        let bytes = Vec::<u8>::from_hex(&hex)?;
310        Ok(encode::deserialize(&bytes)?)
311    }
312
313    fn fund_raw_transaction<R: RawTx>(
314        &self,
315        tx: R,
316        options: Option<&json::FundRawTransactionOptions>,
317        is_witness: Option<bool>,
318    ) -> Result<json::FundRawTransactionResult> {
319        let mut args = [tx.raw_hex().into(), opt_into_json(options)?, opt_into_json(is_witness)?];
320        let defaults = [empty_obj(), null()];
321        self.call("fundrawtransaction", handle_defaults(&mut args, &defaults))
322    }
323
324    fn sign_raw_transaction_with_wallet<R: RawTx>(
325        &self,
326        tx: R,
327        utxos: Option<&[json::SignRawTransactionInput]>,
328        sighash_type: Option<btcjson::SigHashType>,
329    ) -> Result<json::SignRawTransactionResult> {
330        let mut args = [tx.raw_hex().into(), opt_into_json(utxos)?, opt_into_json(sighash_type)?];
331        let defaults = [empty(), null()];
332        self.call("signrawtransactionwithwallet", handle_defaults(&mut args, &defaults))
333    }
334
335    /// We use [bitcoin::PrivateKey] because the keys need to be WIF-encoded.
336    /// Use [bitcoin::Network::Bitcoin] for Liquid and
337    /// [bitcoin::Network::Regtest] for Elements Regtest.
338    fn sign_raw_transaction_with_key<R: RawTx>(
339        &self,
340        tx: R,
341        privkeys: &[bitcoin::PrivateKey],
342        prevtxs: Option<&[json::SignRawTransactionInput]>,
343        sighash_type: Option<btcjson::SigHashType>,
344    ) -> Result<json::SignRawTransactionResult> {
345        let mut args = [
346            tx.raw_hex().into(),
347            into_json(privkeys)?,
348            opt_into_json(prevtxs)?,
349            opt_into_json(sighash_type)?,
350        ];
351        let defaults = [empty(), null()];
352        self.call("signrawtransactionwithkey", handle_defaults(&mut args, &defaults))
353    }
354
355    fn send_raw_transaction<R: RawTx>(&self, tx: R) -> Result<sha256d::Hash> {
356        self.call("sendrawtransaction", handle_defaults(&mut [tx.raw_hex().into()], &[]))
357    }
358
359    fn list_unspent(
360        &self,
361        minconf: Option<usize>,
362        maxconf: Option<usize>,
363        addresses: Option<&[&str]>,
364        include_unsafe: Option<bool>,
365        query_options: Option<&json::ListUnspentQueryOptions>,
366    ) -> Result<Vec<json::ListUnspentResultEntry>> {
367        let mut args = [
368            opt_into_json(minconf)?,
369            opt_into_json(maxconf)?,
370            opt_into_json(addresses)?,
371            opt_into_json(include_unsafe)?,
372            opt_into_json(query_options)?,
373        ];
374        let defaults = [0.into(), 9999999.into(), empty(), true.into(), null()];
375        self.call("listunspent", handle_defaults(&mut args, &defaults))
376    }
377
378    fn list_transactions(
379        &self,
380        count: Option<usize>,
381        skip: Option<usize>,
382        include_watch_only: Option<bool>,
383    ) -> Result<Vec<json::ListTransactionsResultEntry>> {
384        let mut args = [
385            "*".into(),
386            opt_into_json(count)?,
387            opt_into_json(skip)?,
388            opt_into_json(include_watch_only)?,
389        ];
390        let defaults = [10.into(), 0.into(), null()];
391        self.call("listtransactions", handle_defaults(&mut args, &defaults))
392    }
393
394    fn list_since_block(
395        &self,
396        block_hash: Option<&sha256d::Hash>,
397        target_confirmations: Option<u32>,
398        include_watch_only: Option<bool>,
399        include_removed: Option<bool>,
400    ) -> Result<json::ListSinceBlockResult> {
401        let mut args = [
402            opt_into_json(block_hash)?,
403            opt_into_json(target_confirmations)?,
404            opt_into_json(include_watch_only)?,
405            opt_into_json(include_removed)?,
406        ];
407        let defaults = ["".into(), 1.into(), false.into(), null()];
408        self.call("listsinceblock", handle_defaults(&mut args, &defaults))
409    }
410
411    fn get_new_address(
412        &self,
413        label: Option<&str>,
414        address_type: Option<btcjson::AddressType>,
415    ) -> Result<String> {
416        self.call("getnewaddress", &[opt_into_json(label)?, opt_into_json(address_type)?])
417    }
418
419    fn get_raw_change_address(&self, address_type: Option<btcjson::AddressType>) -> Result<String> {
420        self.call("getrawchangeaddress", &[opt_into_json(address_type)?])
421    }
422
423    fn validate_address(&self, address: &str) -> Result<json::ValidateAddressResult> {
424        self.call("validateaddress", &[address.into()])
425    }
426
427    fn get_address_info(&self, address: &str) -> Result<json::GetAddressInfoResult> {
428        self.call("getaddressinfo", &[address.into()])
429    }
430
431    fn get_tx_out(
432        &self,
433        txid: &sha256d::Hash,
434        vout: u32,
435        include_mempool: Option<bool>,
436    ) -> Result<Option<json::GetTxOutResult>> {
437        let mut args = [into_json(txid)?, vout.into(), opt_into_json(include_mempool)?];
438        self.call("gettxout", handle_defaults(&mut args, &[null()])).and_then(opt_result)
439    }
440
441    fn get_balance(
442        &self,
443        min_confirmations: Option<u32>,
444        include_watch_only: Option<bool>,
445    ) -> Result<HashMap<String, Amount>> {
446        let mut args = [
447            "*".into(), // backwards compat dummy
448            opt_into_json(min_confirmations)?,
449            opt_into_json(include_watch_only)?,
450        ];
451        self.call("getbalance", handle_defaults(&mut args, &[0.into(), null()]))
452            .and_then(convert_balances)
453    }
454
455    fn get_balance_asset(
456        &self,
457        asset_label: &str,
458        min_confirmations: Option<u32>,
459        include_watch_only: Option<bool>,
460    ) -> Result<Amount> {
461        let mut args = [
462            "*".into(), // backwards compat dummy
463            opt_into_json(min_confirmations)?,
464            opt_into_json(include_watch_only)?,
465            opt_into_json(Some(asset_label))?,
466        ];
467        self.call("getbalance", handle_defaults(&mut args, &[0.into(), false.into(), null()]))
468            .and_then(deser_amount)
469    }
470
471    fn get_unconfirmed_balance(&self) -> Result<HashMap<String, Amount>> {
472        self.call("getunconfirmedbalance", handle_defaults(&mut [], &[])).and_then(convert_balances)
473    }
474
475    fn get_received_by_address(
476        &self,
477        address: &str,
478        min_confirmations: Option<u32>,
479    ) -> Result<HashMap<String, Amount>> {
480        let mut args = [address.into(), opt_into_json(min_confirmations)?];
481        self.call("getreceivedbyaddress", handle_defaults(&mut args, &[null()]))
482            .and_then(convert_balances)
483    }
484
485    fn get_received_by_address_asset(
486        &self,
487        address: &str,
488        asset_label: &str,
489        min_confirmations: Option<u32>,
490    ) -> Result<Amount> {
491        let mut args =
492            [address.into(), opt_into_json(min_confirmations)?, opt_into_json(Some(asset_label))?];
493        self.call("getreceivedbyaddress", handle_defaults(&mut args, &[0.into(), null()]))
494            .and_then(deser_amount)
495    }
496
497    // TODO(stevenroose)
498    // sendmany
499
500    // Liquid-only calls
501
502    fn get_sidechain_info(&self) -> Result<json::GetSidechainInfoResult> {
503        self.call("getsidechaininfo", &[])
504    }
505
506    fn get_pegin_address(&self) -> Result<json::GetPeginAddressResult> {
507        self.call("getpeginaddress", &[])
508    }
509
510    fn create_raw_pegin<R: bitcoincore_rpc::RawTx, B: AsRef<[u8]>>(
511        &self,
512        raw_bitcoin_tx: R,
513        txout_proof: B,
514        claim_script: Option<&Script>,
515    ) -> Result<json::CreateRawPeginResult> {
516        let mut args = [
517            raw_bitcoin_tx.raw_hex().into(),
518            into_json_hex(txout_proof)?,
519            opt_into_json_hex(claim_script.map(|s| s.as_bytes()))?,
520        ];
521        self.call("createrawpegin", handle_defaults(&mut args, &[null()]))
522    }
523
524    fn claim_pegin<R: bitcoincore_rpc::RawTx, B: AsRef<[u8]>>(
525        &self,
526        raw_bitcoin_tx: R,
527        txout_proof: B,
528        claim_script: Option<&Script>,
529    ) -> Result<sha256d::Hash> {
530        let mut args = [
531            raw_bitcoin_tx.raw_hex().into(),
532            into_json_hex(txout_proof)?,
533            opt_into_json_hex(claim_script.map(|s| s.as_bytes()))?,
534        ];
535        self.call("claimpegin", handle_defaults(&mut args, &[null()]))
536    }
537
538    fn init_pegout_wallet(
539        &self,
540        bitcoin_descriptor: &bip32::ExtendedPubKey,
541        bip32_counter: Option<bip32::ChildNumber>,
542        liquid_pak: Option<&str>,
543    ) -> Result<json::InitPegoutWalletResult> {
544        let mut args = [
545            "".into(), // compatibility dummy
546            bitcoin_descriptor.to_string().into(),
547            opt_into_json(bip32_counter)?,
548            opt_into_json(liquid_pak)?,
549        ];
550        self.call("initpegoutwallet", handle_defaults(&mut args, &[0.into(), null()]))
551    }
552
553    fn send_to_main_chain(
554        &self,
555        amount: Amount,
556        subtract_fee_from_amount: Option<bool>,
557    ) -> Result<json::SendToMainChainResult> {
558        let mut args = [
559            "".into(), // compatibility dummy
560            into_json(ser_amount(&amount))?,
561            opt_into_json(subtract_fee_from_amount)?,
562        ];
563        self.call("sendtomainchain", handle_defaults(&mut args, &[null()]))
564    }
565
566    fn get_wallet_pak_info(&self) -> Result<json::GetWalletPakInfoResult> {
567        self.call("getwalletpakinfo", &[])
568    }
569
570    fn get_pak_info(&self) -> Result<json::GetPakInfoResult> {
571        self.call("getpakinfo", &[])
572    }
573
574    fn tweak_fedpeg_script(&self, claim_script: &Script) -> Result<json::TweakFedpegScriptResult> {
575        self.call("tweakfedpegscript", &[into_json_hex(claim_script.as_bytes())?])
576    }
577
578    fn list_issuances(&self, asset: Option<AssetId>) -> Result<Vec<json::ListIssuancesResult>> {
579        let mut args = [opt_into_json(asset)?];
580        self.call("listissuances", handle_defaults(&mut args, &[null()]))
581    }
582
583    fn issue_asset(
584        &self,
585        asset_amount: Amount,
586        token_amount: Amount,
587        blind: Option<bool>,
588    ) -> Result<json::IssueAssetResult> {
589        let mut args = [
590            into_json(ser_amount(&asset_amount))?,
591            into_json(ser_amount(&token_amount))?,
592            opt_into_json(blind)?,
593        ];
594        self.call("issueasset", handle_defaults(&mut args, &[null()]))
595    }
596
597    fn reissue_asset(
598        &self,
599        asset: AssetId,
600        asset_amount: Amount,
601    ) -> Result<json::ReissueAssetResult> {
602        self.call("reissueasset", &[into_json(asset)?, into_json(ser_amount(&asset_amount))?])
603    }
604
605    fn raw_issue_asset<R: RawTx>(
606        &self,
607        raw_tx: R,
608        issuances: &[json::RawIssuanceDetails],
609    ) -> Result<json::IssueAssetResult> {
610        self.call("rawissueasset", &[raw_tx.raw_hex().into(), into_json(issuances)?])
611    }
612
613    fn raw_reissue_asset<R: RawTx>(
614        &self,
615        raw_tx: R,
616        issuances: &[json::RawReissuanceDetails],
617    ) -> Result<json::RawReissueAssetResult> {
618        self.call("rawreissueasset", &[raw_tx.raw_hex().into(), into_json(issuances)?])
619    }
620
621    fn dump_asset_labels(&self) -> Result<HashMap<String, AssetId>> {
622        self.call("dumpassetlabels", &[])
623    }
624
625    fn destroy_amount(
626        &self,
627        asset: AssetId,
628        amount: Amount,
629        comment: Option<&str>,
630    ) -> Result<sha256d::Hash> {
631        let mut args =
632            [into_json(asset)?, into_json(ser_amount(&amount))?, opt_into_json(comment)?];
633        self.call("destropamount", handle_defaults(&mut args, &[null()]))
634    }
635
636    fn blind_raw_transaction<R: RawTx, B: AsRef<[u8]>>(
637        &self,
638        raw_tx: R,
639        ignore_blind_fail: Option<bool>,
640        asset_commitments: Option<&[B]>,
641        blind_issuances: Option<bool>,
642    ) -> Result<elements::Transaction> {
643        let commitments = asset_commitments
644            .map(|v| {
645                let ret: Result<Vec<serde_json::Value>> = v.iter().map(into_json_hex).collect();
646                ret
647            })
648            .transpose()?;
649        let mut args = [
650            raw_tx.raw_hex().into(),
651            opt_into_json(ignore_blind_fail)?,
652            opt_into_json(commitments)?,
653            opt_into_json(blind_issuances)?,
654        ];
655        let hex: String = self.call(
656            "blindrawtransaction",
657            handle_defaults(&mut args, &[true.into(), empty(), null()]),
658        )?;
659        let bytes = Vec::<u8>::from_hex(&hex)?;
660        Ok(encode::deserialize(&bytes)?)
661    }
662
663    fn unblind_raw_transaction<R: RawTx>(
664        &self,
665        raw_tx: R,
666    ) -> Result<json::UnblindRawTransactionResult> {
667        self.call("unblindrawtransaction", &[raw_tx.raw_hex().into()])
668    }
669
670    fn raw_blind_raw_transaction<R: RawTx, B: AsRef<[u8]>>(
671        &self,
672        raw_tx: R,
673        input_amount_blinding_factors: &[B],
674        input_amounts: &[Amount],
675        input_assets: &[AssetId],
676        input_asset_blinding_factors: &[B],
677        ignore_blind_fail: Option<bool>,
678    ) -> Result<elements::Transaction> {
679        let amount_bfs: Result<Vec<serde_json::Value>> =
680            input_amount_blinding_factors.into_iter().map(into_json_hex).collect();
681        let amounts: Vec<serde_json::Value> = input_amounts.into_iter().map(ser_amount).collect();
682        let assets: Result<Vec<serde_json::Value>> =
683            input_assets.into_iter().map(into_json).collect();
684        let asset_bfs: Result<Vec<serde_json::Value>> =
685            input_asset_blinding_factors.into_iter().map(into_json_hex).collect();
686        let mut args = [
687            raw_tx.raw_hex().into(),
688            into_json(amount_bfs?)?,
689            into_json(amounts)?,
690            into_json(assets?)?,
691            into_json(asset_bfs?)?,
692            opt_into_json(ignore_blind_fail)?,
693        ];
694        let hex: String =
695            self.call("rawblindrawtransaction", handle_defaults(&mut args, &[null()]))?;
696        let bytes = Vec::<u8>::from_hex(&hex)?;
697        Ok(encode::deserialize(&bytes)?)
698    }
699
700    fn create_blinded_address(&self, address: &str, blinding_pubkey: &PublicKey) -> Result<String> {
701        let mut args = [
702            into_json_hex(address)?,
703            //TODO(stevenroose) use PublicKey's serde for rust-bitcoin > 0.18.0
704            blinding_pubkey.to_string().into(),
705        ];
706        self.call("createblindedaddress", handle_defaults(&mut args, &[]))
707    }
708
709    fn dump_blinding_key(&self, address: &str) -> Result<SecretKey> {
710        let hex: String = self.call("dumpblindingkey", &[into_json_hex(address)?])?;
711        let bytes = Vec::<u8>::from_hex(&hex)?;
712        Ok(SecretKey::from_slice(&bytes).map_err(Error::Secp256k1)?)
713    }
714
715    fn import_blinding_key(&self, address: &str, blinding_key: &SecretKey) -> Result<()> {
716        let args = [address.into(), blinding_key.to_string().into()];
717        self.call("importblindingkey", &args)
718    }
719
720    fn dump_master_blinding_key(&self) -> Result<SecretKey> {
721        let hex: String = self.call("dumpmasterblindingkey", &[])?;
722        let bytes = Vec::<u8>::from_hex(&hex)?;
723        Ok(SecretKey::from_slice(&bytes).map_err(Error::Secp256k1)?)
724    }
725
726    fn import_master_blinding_key(&self, master_blinding_key: &SecretKey) -> Result<()> {
727        self.call("importmasterblindingkey", &[master_blinding_key.to_string().into()])
728    }
729
730    fn dump_issuance_blinding_key(&self, txid: &sha256d::Hash, vin: u32) -> Result<SecretKey> {
731        let hex: String = self.call("dumpissuanceblindingkey", &[into_json(txid)?, vin.into()])?;
732        let bytes = Vec::<u8>::from_hex(&hex)?;
733        Ok(SecretKey::from_slice(&bytes).map_err(Error::Secp256k1)?)
734    }
735
736    fn import_issuance_blinding_key(
737        &self,
738        txid: &sha256d::Hash,
739        vin: u32,
740        blinding_key: &SecretKey,
741    ) -> Result<()> {
742        let args = [into_json(txid)?, vin.into(), blinding_key.to_string().into()];
743        self.call("importissuanceblindingkey", &args)
744    }
745
746    fn get_new_block(&self, min_tx_age_secs: Option<usize>) -> Result<elements::Block> {
747        let mut args = [opt_into_json(min_tx_age_secs)?];
748        let hex: String = self.call("getnewblockhex", handle_defaults(&mut args, &[null()]))?;
749        let bytes = Vec::<u8>::from_hex(&hex)?;
750        Ok(encode::deserialize(&bytes)?)
751    }
752
753    fn sign_block(&self, block: &elements::Block) -> Result<Vec<json::SignedBlockSignature>> {
754        self.call("signblock", &[into_json_hex(encode::serialize(block))?])
755    }
756
757    fn combine_block_signatures(
758        &self,
759        block: &elements::Block,
760        signatures: &[json::SignedBlockSignature],
761    ) -> Result<json::CombineBlockSigsResult> {
762        let args = [into_json_hex(encode::serialize(block))?, into_json(signatures)?];
763        self.call("combineblocksigs", &args)
764    }
765
766    fn test_proposed_block(
767        &self,
768        block: &elements::Block,
769        accept_non_standard: Option<bool>,
770    ) -> Result<()> {
771        let mut args =
772            [into_json_hex(encode::serialize(block))?, opt_into_json(accept_non_standard)?];
773        self.call("testproposedblock", handle_defaults(&mut args, &[null()]))
774    }
775
776    fn submit_block(&self, block: &elements::Block) -> Result<String> {
777        self.call("submitblock", &[into_json_hex(encode::serialize(block))?])
778    }
779
780    //TODO(stevenroose)
781    // Compact Blocks commands
782    // getcompactsketch
783    // consumecompactsketch
784    // finalizecompactblock
785}
786
787/// A Liquid RPC client.
788///
789/// This type implements both the [bitcoincore_rpc::RpcApi] trait as the
790/// [liquid_rpc::LiquidRpcApi] trait.  Methods that are shared between Liquid and
791/// Bitcoin Core can be used from the former and changed or new methods are
792/// provided by the latter.
793pub struct Client(pub bitcoincore_rpc::Client);
794
795impl Client {
796    /// Creates a client to a liquidd JSON-RPC server.
797    pub fn new(url: String, auth: Auth) -> Result<Self> {
798        bitcoincore_rpc::Client::new(url, auth).map(Client).map_err(From::from)
799    }
800
801    /// Create a new Client.
802    pub fn from_jsonrpc(client: jsonrpc::client::Client) -> Self {
803        Client(bitcoincore_rpc::Client::from_jsonrpc(client))
804    }
805}
806
807impl bitcoincore_rpc::RpcApi for Client {
808    fn call<T: for<'a> serde::de::Deserialize<'a>>(
809        &self,
810        cmd: &str,
811        args: &[serde_json::Value],
812    ) -> bitcoincore_rpc::Result<T> {
813        bitcoincore_rpc::RpcApi::call(&self.0, cmd, args)
814    }
815}
816
817impl LiquidRpcApi for Client {
818    fn call<T: for<'a> serde::de::Deserialize<'a>>(
819        &self,
820        cmd: &str,
821        args: &[serde_json::Value],
822    ) -> Result<T> {
823        bitcoincore_rpc::RpcApi::call(self, cmd, args).map_err(From::from)
824    }
825}