Skip to main content

smplx_sdk/provider/rpc/
elements.rs

1use std::str::FromStr;
2
3use electrsd::bitcoind::bitcoincore_rpc::{Auth, Client, RpcApi};
4
5use serde_json::Value;
6
7use simplicityhl::elements::{Address, AssetId, BlockHash, Txid};
8
9use super::error::RpcError;
10
11use crate::utils::sat2btc;
12
13pub struct ElementsRpc {
14    pub inner: Client,
15    pub auth: Auth,
16    pub url: String,
17}
18
19impl ElementsRpc {
20    pub fn new(url: String, auth: Auth) -> Result<Self, RpcError> {
21        let inner = Client::new(url.as_str(), auth.clone())?;
22        inner.ping()?;
23
24        Ok(Self {
25            inner: inner,
26            auth: auth,
27            url: url,
28        })
29    }
30
31    pub fn height(&self) -> Result<u64, RpcError> {
32        const METHOD: &str = "getblockcount";
33
34        self.inner
35            .call::<serde_json::Value>(METHOD, &[])?
36            .as_u64()
37            .ok_or_else(|| RpcError::ElementsRpcUnexpectedReturn(METHOD.into()))
38    }
39
40    pub fn block_hash(&self, height: u64) -> Result<BlockHash, RpcError> {
41        const METHOD: &str = "getblockhash";
42
43        let raw: Value = self.inner.call(METHOD, &[height.into()])?;
44
45        Ok(BlockHash::from_str(raw.as_str().unwrap())?)
46    }
47
48    pub fn sendtoaddress(&self, address: &Address, satoshi: u64, asset: Option<AssetId>) -> Result<Txid, RpcError> {
49        const METHOD: &str = "sendtoaddress";
50
51        let btc = sat2btc(satoshi);
52        let r = match asset {
53            Some(asset) => self.inner.call::<Value>(
54                METHOD,
55                &[
56                    address.to_string().into(),
57                    btc.into(),
58                    "".into(),
59                    "".into(),
60                    false.into(),
61                    false.into(),
62                    1.into(),
63                    "UNSET".into(),
64                    false.into(),
65                    asset.to_string().into(),
66                ],
67            )?,
68            None => self
69                .inner
70                .call::<Value>(METHOD, &[address.to_string().into(), btc.into()])?,
71        };
72
73        Ok(Txid::from_str(r.as_str().unwrap()).unwrap())
74    }
75
76    pub fn rescanblockchain(&self, start: Option<u64>, stop: Option<u64>) -> Result<(), RpcError> {
77        const METHOD: &str = "rescanblockchain";
78
79        let mut args = Vec::with_capacity(2);
80
81        if start.is_some() {
82            args.push(start.into());
83        }
84
85        if stop.is_some() {
86            args.push(stop.into());
87        }
88
89        self.inner.call::<Value>(METHOD, &args)?;
90
91        Ok(())
92    }
93
94    pub fn getnewaddress(&self, label: &str) -> Result<Address, RpcError> {
95        const METHOD: &str = "getnewaddress";
96
97        let addr: Value = self.inner.call(METHOD, &[label.into(), "bech32".to_string().into()])?;
98
99        Ok(Address::from_str(addr.as_str().unwrap()).unwrap())
100    }
101
102    pub fn generate_blocks(&self, block_num: u32) -> Result<(), RpcError> {
103        const METHOD: &str = "generatetoaddress";
104
105        let address = self.getnewaddress("")?.to_string();
106        self.inner.call::<Value>(METHOD, &[block_num.into(), address.into()])?;
107
108        Ok(())
109    }
110
111    pub fn sweep_initialfreecoins(&self) -> Result<(), RpcError> {
112        const METHOD: &str = "sendtoaddress";
113
114        let address = self.getnewaddress("")?;
115        self.inner.call::<Value>(
116            METHOD,
117            &[
118                address.to_string().into(),
119                "21".into(),
120                "".into(),
121                "".into(),
122                true.into(),
123            ],
124        )?;
125
126        Ok(())
127    }
128}