smplx_sdk/provider/rpc/
elements.rs1use std::str::FromStr;
2
3use electrsd::bitcoind::bitcoincore_rpc::{Auth, Client, RpcApi};
4
5use serde_json::Value;
6
7use simplicityhl::elements::{Address, AssetId, Txid};
8use simplicityhl::simplicity::bitcoin;
9
10use super::error::RpcError;
11
12use crate::utils::sat2btc;
13
14#[derive(Debug)]
16pub struct ElementsRpc {
17 pub inner: Client,
19 pub auth: Auth,
21 pub url: String,
23}
24
25impl ElementsRpc {
26 pub fn new(url: String, auth: Auth) -> Result<Self, RpcError> {
31 let inner = Client::new(url.as_str(), auth.clone())?;
32 inner.ping()?;
33
34 Ok(Self { inner, auth, url })
35 }
36
37 pub fn get_new_address(&self, label: &str) -> Result<Address, RpcError> {
45 const METHOD: &str = "getnewaddress";
46
47 let addr: Value = self.inner.call(METHOD, &[label.into(), "bech32".to_string().into()])?;
48
49 Ok(Address::from_str(addr.as_str().unwrap()).unwrap())
50 }
51
52 pub fn send_to_address(&self, address: &Address, satoshi: u64, asset: Option<AssetId>) -> Result<Txid, RpcError> {
61 const METHOD: &str = "sendtoaddress";
62
63 let btc = sat2btc(satoshi);
64 let btc = bitcoin::amount::Amount::from_btc(btc)
65 .unwrap()
66 .to_string_in(bitcoin::amount::Denomination::Bitcoin);
67
68 let r = match asset {
69 Some(asset) => self.inner.call::<Value>(
70 METHOD,
71 &[
72 address.to_string().into(),
73 btc.into(),
74 "".into(),
75 "".into(),
76 false.into(),
77 false.into(),
78 1.into(),
79 "UNSET".into(),
80 false.into(),
81 asset.to_string().into(),
82 ],
83 )?,
84 None => self
85 .inner
86 .call::<Value>(METHOD, &[address.to_string().into(), btc.into()])?,
87 };
88
89 Ok(Txid::from_str(r.as_str().unwrap()).unwrap())
90 }
91
92 pub fn rescan_blockchain(&self, start: Option<u64>, stop: Option<u64>) -> Result<(), RpcError> {
97 const METHOD: &str = "rescanblockchain";
98
99 let mut args = Vec::with_capacity(2);
100
101 if start.is_some() {
102 args.push(start.into());
103 }
104
105 if stop.is_some() {
106 args.push(stop.into());
107 }
108
109 self.inner.call::<Value>(METHOD, &args)?;
110
111 Ok(())
112 }
113
114 pub fn generate_blocks(&self, block_num: u64) -> Result<(), RpcError> {
119 const METHOD: &str = "generatetoaddress";
120
121 let address = self.get_new_address("")?.to_string();
122 self.inner.call::<Value>(METHOD, &[block_num.into(), address.into()])?;
123
124 Ok(())
125 }
126
127 pub fn sweep_initialfreecoins(&self) -> Result<(), RpcError> {
132 const METHOD: &str = "sendtoaddress";
133
134 let address = self.get_new_address("")?;
135 self.inner.call::<Value>(
136 METHOD,
137 &[
138 address.to_string().into(),
139 "21".into(),
140 "".into(),
141 "".into(),
142 true.into(),
143 ],
144 )?;
145
146 Ok(())
147 }
148
149 pub fn height(&self) -> Result<u64, RpcError> {
154 const METHOD: &str = "getblockcount";
155
156 self.inner
157 .call::<serde_json::Value>(METHOD, &[])?
158 .as_u64()
159 .ok_or_else(|| RpcError::ElementsRpcUnexpectedReturn(METHOD.into()))
160 }
161}