1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use anyhow::Result;
use reqwest::blocking::{Client, Response};
use serde_json::Value;
pub mod utils;
use ergo_lib::ergotree_ir::chain::ergo_box::ErgoBox;
use ergo_chain_types::Header;
use ergo_lib::chain::ergo_state_context::Headers;
use crate::utils::consts::{MAINNET_EXPLORER_API_BASE_URL, MAINNET_NODE_URL};
use crate::utils::format::remove_quotes;
fn request_unspent_boxes_for_address(address: &str, explorer_url: &Option<String>) -> Result<Value> {
let base_url: String = match explorer_url {
Some(url) => url.to_string(),
None => MAINNET_EXPLORER_API_BASE_URL.to_string(),
};
let url: String = format!("{}/api/v1/boxes/unspent/byAddress/{}", base_url, address);
let response: String = reqwest::blocking::get(&url)?.text()?;
let json: Value = serde_json::from_str(&response)?;
Ok(json)
}
pub fn get_unspent_boxes_for_address(address: &str, explorer_url: &Option<String>) -> Option<Vec<ErgoBox>> {
let json: Value = request_unspent_boxes_for_address(address, explorer_url).unwrap();
let total: u64 = json["total"].as_u64().unwrap();
if total == 0 {
return None;
}
let boxes: &Vec<Value> = json["items"].as_array().unwrap();
let mut box_vec: Vec<ErgoBox> = Vec::new();
for b in boxes {
let ergobox: ErgoBox = serde_json::from_value(b.clone()).unwrap();
box_vec.push(ergobox);
}
Some(box_vec)
}
fn request_current_height(explorer_url: &Option<String>) -> Result<Value> {
let base_url: String = match explorer_url {
Some(url) => url.to_string(),
None => MAINNET_EXPLORER_API_BASE_URL.to_string(),
};
let url: String = format!("{}/api/v1/blocks?limit=1", base_url);
let response: String = reqwest::blocking::get(&url)?.text()?;
let json: Value = serde_json::from_str(&response)?;
Ok(json)
}
pub fn get_current_height(explorer_url: &Option<String>) -> u64 {
let json: Value = request_current_height(explorer_url).unwrap();
let height: u64 = json["total"].as_u64().unwrap();
height
}
pub fn get_last_10_headers(explorer_url: &Option<String>, node_url: &Option<String>) -> Headers {
let height: u32 = get_current_height(explorer_url) as u32;
let mut headers_vec: Vec<Header> = Vec::new();
for i in 0..10 {
let height: u32 = height - i;
let header_id: String = get_header_id_by_height(height, &node_url).unwrap();
let header: Header = get_header_by_header_id(header_id, &node_url);
headers_vec.push(header);
}
let headers: Headers = [headers_vec.get(0).unwrap().to_owned(), headers_vec.get(1).unwrap().to_owned(), headers_vec.get(2).unwrap().to_owned(), headers_vec.get(3).unwrap().to_owned(), headers_vec.get(4).unwrap().to_owned(), headers_vec.get(5).unwrap().to_owned(), headers_vec.get(6).unwrap().to_owned(), headers_vec.get(7).unwrap().to_owned(), headers_vec.get(8).unwrap().to_owned(), headers_vec.get(9).unwrap().to_owned()];
headers
}
fn get_header_by_header_id(header_id: String, node_url: &Option<String>) -> Header {
let base_url: String = match node_url {
Some(url) => url.to_string(),
None => MAINNET_NODE_URL.to_string(),
};
let url: String = format!("{}/blocks/{}/header", base_url, header_id);
let resp: String = reqwest::blocking::get(url).unwrap().text().unwrap();
let data: Value = serde_json::from_str(&resp).unwrap();
let header: Header = serde_json::from_value(data).unwrap();
header
}
fn get_header_id_by_height(height: u32, node_url: &Option<String>) -> Result<String> {
let base_url: String = match node_url {
Some(url) => url.to_string(),
None => MAINNET_NODE_URL.to_string(),
};
let url: String = format!("{}/blocks/at/{}", base_url, height);
let resp: String = reqwest::blocking::get(url)?.text()?;
let data: Value = serde_json::from_str(&resp)?;
let header_id: String = remove_quotes(data[0].to_string());
Ok(header_id)
}
pub fn submit(transaction_json: String, node_url: &Option<String>) -> Result<String> {
let base_url: String = match node_url {
Some(url) => url.to_string(),
None => MAINNET_NODE_URL.to_string(),
};
let url: String = format!("{}/transactions", base_url);
let client: Client = reqwest::blocking::Client::new();
let response: Response = client.post(url)
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.header("mode", "cors")
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
.body(transaction_json)
.send()?;
let response_body: String = response.text()?;
Ok(response_body)
}