ergo_node_interface/
transactions.rs1use std::convert::TryFrom;
2
3use crate::node_interface::{NodeError, NodeInterface, Result};
4use crate::JsonString;
5use ergo_lib::chain::transaction::unsigned::UnsignedTransaction;
6use ergo_lib::chain::transaction::{Transaction, TxId};
7use ergo_lib::ergo_chain_types::Digest32;
8use ergo_lib::ergotree_ir::chain::ergo_box::ErgoBox;
9use ergo_lib::ergotree_ir::serialization::{SigmaSerializable, SigmaSerializationError};
10use ergo_lib::wallet::signing::TransactionContext;
11use json::JsonValue;
12use serde_json::json;
13
14impl NodeInterface {
15 pub fn submit_json_transaction(&self, signed_tx_json: &JsonString) -> Result<TxId> {
18 let endpoint = "/transactions";
19 let res_json = self.use_json_endpoint_and_check_errors(endpoint, signed_tx_json)?;
20 let tx_id = parse_tx_id_unsafe(res_json);
21 Ok(tx_id)
22 }
23
24 pub fn sign_json_transaction(&self, unsigned_tx_string: &JsonString) -> Result<JsonValue> {
26 let endpoint = "/wallet/transaction/sign";
27 let unsigned_tx_json = json::parse(unsigned_tx_string)
28 .map_err(|_| NodeError::FailedParsingNodeResponse(unsigned_tx_string.to_string()))?;
29
30 let prepared_body = object! {
31 tx: unsigned_tx_json
32 };
33
34 let res_json = self.use_json_endpoint_and_check_errors(endpoint, &prepared_body.dump())?;
35
36 Ok(res_json)
37 }
38
39 pub fn sign_and_submit_json_transaction(
42 &self,
43 unsigned_tx_string: &JsonString,
44 ) -> Result<TxId> {
45 let signed_tx = self.sign_json_transaction(unsigned_tx_string)?;
46 let signed_tx_json = json::stringify(signed_tx);
47
48 self.submit_json_transaction(&signed_tx_json)
49 }
50
51 pub fn submit_transaction(&self, signed_tx: &Transaction) -> Result<TxId> {
54 let signed_tx_json = &serde_json::to_string(&signed_tx)
55 .map_err(|_| NodeError::Other("Failed Converting `Transaction` to json".to_string()))?;
56 let tx_id = self.submit_json_transaction(signed_tx_json)?;
57 assert_eq!(tx_id, signed_tx.id());
58 Ok(tx_id)
59 }
60
61 pub fn sign_transaction(
66 &self,
67 unsigned_tx: &UnsignedTransaction,
68 boxes_to_spend: Option<Vec<ErgoBox>>,
69 data_input_boxes: Option<Vec<ErgoBox>>,
70 ) -> Result<Transaction> {
71 if let Some(ref boxes_to_spend) = boxes_to_spend {
72 if let Err(e) = TransactionContext::new(
74 unsigned_tx.clone(),
75 boxes_to_spend.clone(),
76 data_input_boxes.clone().unwrap_or_default(),
77 ) {
78 return Err(NodeError::Other(e.to_string()));
79 };
80 }
81
82 let endpoint = "/wallet/transaction/sign";
83
84 fn encode_boxes(
85 maybe_boxes: Option<Vec<ErgoBox>>,
86 ) -> std::result::Result<Option<Vec<String>>, NodeError> {
87 match maybe_boxes.map(|boxes| {
88 boxes
89 .iter()
90 .map(|b| {
91 b.sigma_serialize_bytes()
92 .map(|bytes| base16::encode_lower(&bytes))
93 })
94 .collect::<std::result::Result<Vec<String>, SigmaSerializationError>>()
95 }) {
96 Some(Ok(base16_boxes)) => Ok(Some(base16_boxes)),
97 Some(Err(e)) => Err(NodeError::Other(e.to_string())),
98 None => Ok(None),
99 }
100 }
101
102 let input_boxes_base16 = encode_boxes(boxes_to_spend)?;
103 let data_input_boxes_base16 = encode_boxes(data_input_boxes)?;
104
105 let prepared_body = json!({
106 "tx": unsigned_tx,
107 "inputsRaw": input_boxes_base16,
108 "dataInputsRaw": data_input_boxes_base16,
109 });
110
111 let json_signed_tx =
112 self.use_json_endpoint_and_check_errors(endpoint, &prepared_body.to_string())?;
113
114 serde_json::from_str(&json_signed_tx.dump())
115 .map_err(|_| NodeError::Other("Failed Converting `Transaction` to json".to_string()))
116 }
117
118 pub fn sign_and_submit_transaction(&self, unsigned_tx: &UnsignedTransaction) -> Result<TxId> {
120 let signed_tx = self.sign_transaction(unsigned_tx, None, None)?;
121 self.submit_transaction(&signed_tx)
122 }
123
124 pub fn generate_and_submit_transaction(&self, tx_request_json: &JsonString) -> Result<TxId> {
129 let endpoint = "/wallet/transaction/send";
130 let res_json = self.use_json_endpoint_and_check_errors(endpoint, tx_request_json)?;
131 let tx_id = parse_tx_id_unsafe(res_json);
132 Ok(tx_id)
133 }
134
135 pub fn generate_json_transaction(&self, tx_request_json: &JsonString) -> Result<JsonValue> {
139 let endpoint = "/wallet/transaction/generate";
140 let res_json = self.use_json_endpoint_and_check_errors(endpoint, tx_request_json)?;
141
142 Ok(res_json)
143 }
144
145 pub fn get_recommended_fee(&self, bytes: u64, wait_time: u64) -> Result<u64> {
149 let endpoint = format!(
150 "/transactions/getFee?bytes={}&waitTime={}",
151 bytes, wait_time
152 );
153 let res = self.send_get_req(&endpoint);
154 let res_json = self.parse_response_to_json(res);
155 let fee = res_json?.as_u64().unwrap();
156 Ok(fee)
157 }
158}
159
160fn parse_tx_id_unsafe(mut res_json: JsonValue) -> TxId {
161 let tx_id_str = res_json.take_string().unwrap();
163 TxId(Digest32::try_from(tx_id_str).unwrap())
164}