use std::convert::TryFrom;
use crate::node_interface::{NodeError, NodeInterface, Result};
use crate::JsonString;
use ergo_lib::chain::transaction::unsigned::UnsignedTransaction;
use ergo_lib::chain::transaction::{Transaction, TxId};
use ergo_lib::ergo_chain_types::Digest32;
use ergo_lib::ergotree_ir::chain::ergo_box::ErgoBox;
use ergo_lib::ergotree_ir::serialization::{SigmaSerializable, SigmaSerializationError};
use ergo_lib::wallet::signing::TransactionContext;
use json::JsonValue;
use serde_json::json;
impl NodeInterface {
pub fn submit_json_transaction(&self, signed_tx_json: &JsonString) -> Result<TxId> {
let endpoint = "/transactions";
let res_json = self.use_json_endpoint_and_check_errors(endpoint, signed_tx_json)?;
let tx_id = parse_tx_id_unsafe(res_json);
Ok(tx_id)
}
pub fn sign_json_transaction(&self, unsigned_tx_string: &JsonString) -> Result<JsonValue> {
let endpoint = "/wallet/transaction/sign";
let unsigned_tx_json = json::parse(unsigned_tx_string)
.map_err(|_| NodeError::FailedParsingNodeResponse(unsigned_tx_string.to_string()))?;
let prepared_body = object! {
tx: unsigned_tx_json
};
let res_json = self.use_json_endpoint_and_check_errors(endpoint, &prepared_body.dump())?;
Ok(res_json)
}
pub fn sign_and_submit_json_transaction(
&self,
unsigned_tx_string: &JsonString,
) -> Result<TxId> {
let signed_tx = self.sign_json_transaction(unsigned_tx_string)?;
let signed_tx_json = json::stringify(signed_tx);
self.submit_json_transaction(&signed_tx_json)
}
pub fn submit_transaction(&self, signed_tx: &Transaction) -> Result<TxId> {
let signed_tx_json = &serde_json::to_string(&signed_tx)
.map_err(|_| NodeError::Other("Failed Converting `Transaction` to json".to_string()))?;
let tx_id = self.submit_json_transaction(signed_tx_json)?;
assert_eq!(tx_id, signed_tx.id());
Ok(tx_id)
}
pub fn sign_transaction(
&self,
unsigned_tx: &UnsignedTransaction,
boxes_to_spend: Option<Vec<ErgoBox>>,
data_input_boxes: Option<Vec<ErgoBox>>,
) -> Result<Transaction> {
if let Some(ref boxes_to_spend) = boxes_to_spend {
if let Err(e) = TransactionContext::new(
unsigned_tx.clone(),
boxes_to_spend.clone(),
data_input_boxes.clone().unwrap_or_default(),
) {
return Err(NodeError::Other(e.to_string()));
};
}
let endpoint = "/wallet/transaction/sign";
fn encode_boxes(
maybe_boxes: Option<Vec<ErgoBox>>,
) -> std::result::Result<Option<Vec<String>>, NodeError> {
match maybe_boxes.map(|boxes| {
boxes
.iter()
.map(|b| {
b.sigma_serialize_bytes()
.map(|bytes| base16::encode_lower(&bytes))
})
.collect::<std::result::Result<Vec<String>, SigmaSerializationError>>()
}) {
Some(Ok(base16_boxes)) => Ok(Some(base16_boxes)),
Some(Err(e)) => Err(NodeError::Other(e.to_string())),
None => Ok(None),
}
}
let input_boxes_base16 = encode_boxes(boxes_to_spend)?;
let data_input_boxes_base16 = encode_boxes(data_input_boxes)?;
let prepared_body = json!({
"tx": unsigned_tx,
"inputsRaw": input_boxes_base16,
"dataInputsRaw": data_input_boxes_base16,
});
let json_signed_tx =
self.use_json_endpoint_and_check_errors(endpoint, &prepared_body.to_string())?;
serde_json::from_str(&json_signed_tx.dump())
.map_err(|_| NodeError::Other("Failed Converting `Transaction` to json".to_string()))
}
pub fn sign_and_submit_transaction(&self, unsigned_tx: &UnsignedTransaction) -> Result<TxId> {
let signed_tx = self.sign_transaction(unsigned_tx, None, None)?;
self.submit_transaction(&signed_tx)
}
pub fn generate_and_submit_transaction(&self, tx_request_json: &JsonString) -> Result<TxId> {
let endpoint = "/wallet/transaction/send";
let res_json = self.use_json_endpoint_and_check_errors(endpoint, tx_request_json)?;
let tx_id = parse_tx_id_unsafe(res_json);
Ok(tx_id)
}
pub fn generate_json_transaction(&self, tx_request_json: &JsonString) -> Result<JsonValue> {
let endpoint = "/wallet/transaction/generate";
let res_json = self.use_json_endpoint_and_check_errors(endpoint, tx_request_json)?;
Ok(res_json)
}
pub fn get_recommended_fee(&self, bytes: u64, wait_time: u64) -> Result<u64> {
let endpoint = format!(
"/transactions/getFee?bytes={}&waitTime={}",
bytes, wait_time
);
let res = self.send_get_req(&endpoint);
let res_json = self.parse_response_to_json(res);
let fee = res_json?.as_u64().unwrap();
Ok(fee)
}
}
fn parse_tx_id_unsafe(mut res_json: JsonValue) -> TxId {
let tx_id_str = res_json.take_string().unwrap();
TxId(Digest32::try_from(tx_id_str).unwrap())
}