icon_sdk/
transaction_builder.rs1use chrono::Utc;
2use hex::{decode, encode};
3use rust_decimal::Decimal;
4use secp256k1::{Message, Secp256k1, SecretKey};
5use serde::{Deserialize, Serialize};
6use serde_json::{json, Map, Value};
7use std::str::FromStr;
8use base64::{Engine as _, engine::{general_purpose as base64_encoder}};
9use hex::FromHex;
10use crate::icon_service::IconService;
11use crate::transaction::Transaction;
12use crate::utils::helpers::icx_to_hex;
13use crate::utils::serializer::Serializer;
14
15#[derive(Default, Serialize, Deserialize)]
16pub struct TransactionBuilder {
17 transaction: Transaction,
18}
19
20impl TransactionBuilder {
21 pub fn new(icon_service: &IconService) -> Self {
22 Self {
23 transaction: Transaction::new(icon_service),
24 }
25 }
26
27 pub fn method(mut self, method: &str) -> Self {
28 if let Some(obj) = self.transaction.data.as_object_mut() {
30 obj.insert("method".to_string(), json!(method));
32 }
33 self
34 }
35
36 pub fn set_params(mut self, params: &Map<String, Value>) -> Self {
37 let data_obj = self.transaction.data.as_object_mut().expect("data is not an object");
39 let params_obj = data_obj.entry("params").or_insert_with(|| json!({})).as_object_mut().unwrap();
40
41 for (key, value) in params {
43 params_obj.insert(key.clone(), value.clone());
44 }
45
46 self
47 }
48
49 pub fn block_height(self, block_height: &str) -> Self {
50 let mut params = Map::new();
51 params.insert("height".to_string(), json!(block_height));
52
53 self.set_params(¶ms)
54 }
55
56 pub fn block_hash(self, block_hash: &str) -> Self {
57 let mut params = Map::new();
58 params.insert("hash".to_string(), json!(block_hash));
59
60 self.set_params(¶ms)
61 }
62
63 pub fn address(self, address: &str) -> Self {
64 let mut params = Map::new();
65 params.insert("address".to_string(), json!(address));
66
67 self.set_params(¶ms)
68 }
69
70 pub fn tx_hash(self, tx_hash: &str) -> Self {
71 let mut params = Map::new();
72 params.insert("txHash".to_string(), json!(tx_hash));
73
74 self.set_params(¶ms)
75 }
76
77 pub fn from(self, from: &str) -> Self {
78 let mut params = Map::new();
79 params.insert("from".to_string(), json!(from));
80
81 self.set_params(¶ms)
82 }
83
84 pub fn to(self, to: &str) -> Self {
85 let mut params = Map::new();
86 params.insert("to".to_string(), json!(to));
87
88 self.set_params(¶ms)
89 }
90
91 pub fn value(self, value: &str) -> Self {
92 let mut params = Map::new();
93 let mut parsed_value = value.to_string();
94
95 if !parsed_value.starts_with("0x") {
96 match icx_to_hex(Decimal::from_str(value).expect("Invalid value")) {
97 Some(v) => {
98 parsed_value = v;
99 }
100 None => panic!("Failed to convert value to hex"),
101 }
102 }
103
104 params.insert("value".to_string(), json!(parsed_value));
105
106
107 self.set_params(¶ms)
108 }
109
110 pub fn version(self, version: &str) -> Self {
111 let mut params = Map::new();
112 params.insert("version".to_string(), json!(version));
113
114 self.set_params(¶ms)
115 }
116
117 pub fn nid(self, nid: &str) -> Self {
118 let mut params = Map::new();
119 params.insert("nid".to_string(), json!(nid));
120
121 self.set_params(¶ms)
122 }
123
124 pub fn nonce(self, nonce: &str) -> Self {
125 let mut params = Map::new();
126 params.insert("nonce".to_string(), json!(nonce));
127
128 self.set_params(¶ms)
129 }
130
131 pub fn step_limit(self, step_limit: &str) -> Self {
132 let mut params = Map::new();
133 params.insert("stepLimit".to_string(), json!(step_limit));
134
135 self.set_params(¶ms)
136 }
137
138 pub fn timestamp(self) -> Self {
139 let now = Utc::now();
140 let timestamp_in_micros = now.timestamp_micros();
141 let hex_timestamp = format!("0x{:x}", timestamp_in_micros);
142
143 let mut params = Map::new();
144 params.insert("timestamp".to_string(), json!(hex_timestamp.to_string()));
145
146 self.set_params(¶ms)
147 }
148
149 pub fn message(self, message: &str) -> Self {
150 let mut params = Map::new();
151 params.insert("dataType".to_string(), json!("message"));
152 params.insert("data".to_string(), json!(format!("0x{}", encode(message))));
153
154
155 self.set_params(¶ms)
156 }
157
158 pub fn call(self, call_params: Value) -> Self {
159 let mut params = Map::new();
160 params.insert("dataType".to_string(), json!("call"));
161 params.insert("data".to_string(), json!(call_params));
162
163 self.set_params(¶ms)
164 }
165
166 pub fn sign(self, private_key: &str) -> Self {
167 let serialized_transaction = Serializer::serialize_transaction(&self.transaction.data["params"], true);
168 let serialized_transaction_bytes = Vec::from_hex(serialized_transaction).expect("Invalid hex string");
169
170 let secp = Secp256k1::new();
171 let secret_key = SecretKey::from_slice(&decode(private_key).expect("Invalid private key")).expect("Failed to create secret key");
172
173 let message = Message::from_digest_slice(serialized_transaction_bytes.as_slice()).expect("Failed to create message");
174 let sig = secp.sign_ecdsa_recoverable(&message, &secret_key);
175
176 let (rec_id, sig_bytes) = sig.serialize_compact();
177 let signature = format!("{}{:02x}", encode(sig_bytes), rec_id.to_i32());
179
180 let signature_bytes = decode(signature).expect("Failed to decode hex");
181 let transaction_signature = base64_encoder::STANDARD.encode(signature_bytes);
182
183 let mut params = Map::new();
184 params.insert("signature".to_string(), json!(transaction_signature));
185
186 self.set_params(¶ms)
187 }
188
189 pub fn build(self) -> Transaction {
190 self.transaction
191 }
192}