1use std::collections::HashMap;
2
3use super::{sdk_address::SdkAddress, vm::CallType};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
8#[serde(rename_all = "camelCase")]
9pub struct Transaction {
10 pub nonce: u64,
11 pub value: String,
12 pub receiver: SdkAddress,
13 pub sender: SdkAddress,
14 pub gas_price: u64,
15 pub gas_limit: u64,
16 #[serde(skip_serializing_if = "Option::is_none")]
17 pub data: Option<String>,
18 #[serde(skip_serializing_if = "Option::is_none")]
19 pub signature: Option<String>,
20 #[serde(rename = "chainID")]
21 pub chain_id: String,
22 pub version: u32,
23 #[serde(skip_serializing_if = "is_zero")]
24 pub options: u32,
25}
26
27#[allow(clippy::trivially_copy_pass_by_ref)]
29fn is_zero(num: &u32) -> bool {
30 *num == 0
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
35#[serde(rename_all = "camelCase")]
36pub struct TxCostResponseData {
37 pub tx_gas_units: u64,
38 pub return_message: String,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
43#[serde(rename_all = "camelCase")]
44pub struct ResponseTxCost {
45 pub data: Option<TxCostResponseData>,
46 pub error: String,
47 pub code: String,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize, Default)]
52#[serde(rename_all = "camelCase")]
53pub struct TransactionOnNetwork {
54 #[serde(rename = "type")]
55 pub kind: String,
56 pub hash: Option<String>,
57 pub nonce: u64,
58 pub round: u64,
59 pub epoch: u64,
60 pub value: String,
61 pub receiver: SdkAddress,
62 pub sender: SdkAddress,
63 pub gas_price: u64,
64 pub gas_limit: u64,
65 #[serde(default)]
66 pub gas_used: u64,
67 #[serde(default)]
68 pub signature: String,
69 pub source_shard: u32,
70 pub destination_shard: u32,
71 pub block_nonce: u64,
72 pub block_hash: String,
73 pub notarized_at_source_in_meta_nonce: Option<u64>,
74 #[serde(rename = "NotarizedAtSourceInMetaHash")]
75 pub notarized_at_source_in_meta_hash: Option<String>,
76 pub notarized_at_destination_in_meta_nonce: Option<u64>,
77 pub notarized_at_destination_in_meta_hash: Option<String>,
78 pub processing_type_on_destination: String,
79 pub miniblock_type: String,
80 pub miniblock_hash: String,
81 pub timestamp: u64,
82 pub data: Option<String>,
83 pub status: String,
84 pub hyperblock_nonce: Option<u64>,
85 pub hyperblock_hash: Option<String>,
86 #[serde(default)]
87 pub smart_contract_results: Vec<ApiSmartContractResult>,
88 pub logs: Option<ApiLogs>,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
93#[serde(rename_all = "camelCase")]
94pub struct Events {
95 pub address: SdkAddress,
96 pub identifier: String,
97 pub topics: Option<Vec<String>>,
98 #[serde(default)]
99 pub data: LogData,
100}
101
102#[derive(Default, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
103#[serde(untagged)]
104pub enum LogData {
105 #[default]
106 Empty,
107 String(String),
108 Vec(Vec<String>),
109}
110
111impl LogData {
112 pub fn for_each<F: FnMut(&String)>(&self, mut f: F) {
113 match self {
114 LogData::Empty => {},
115 LogData::String(s) => f(s),
116 LogData::Vec(v) => v.iter().for_each(f),
117 }
118 }
119}
120
121#[derive(Debug, Clone, Serialize, Deserialize)]
123#[serde(rename_all = "camelCase")]
124pub struct ApiLogs {
125 pub address: SdkAddress,
126 pub events: Vec<Events>,
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize)]
130#[serde(rename_all = "camelCase")]
131pub struct ApiSmartContractResult {
132 pub hash: String,
133 pub nonce: u64,
134 pub value: u64,
135 pub receiver: SdkAddress,
136 pub sender: SdkAddress,
137 #[serde(default)]
138 pub data: String,
139 pub prev_tx_hash: String,
140 pub original_tx_hash: String,
141 pub gas_limit: u64,
142 pub gas_price: u64,
143 pub call_type: CallType,
144 pub relayer_address: Option<String>,
145 pub relayed_value: Option<String>,
146 pub code: Option<String>,
147 pub code_metadata: Option<String>,
148 pub return_message: Option<String>,
149 pub original_sender: Option<String>,
150}
151
152#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct TransactionInfoData {
154 pub transaction: TransactionOnNetwork,
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize)]
159pub struct TransactionInfo {
160 #[serde(default)]
161 pub error: String,
162 pub code: String,
163 pub data: Option<TransactionInfoData>,
164}
165
166#[derive(Debug, Clone, Serialize, Deserialize)]
167pub struct TransactionStatusData {
168 pub status: String,
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
173pub struct TransactionStatus {
174 pub error: String,
175 pub code: String,
176 pub data: Option<TransactionStatusData>,
177}
178
179#[derive(Debug, Clone, Serialize, Deserialize)]
180pub struct TransactionProcessStatusData {
181 pub reason: String,
182 pub status: String,
183}
184
185#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct TransactionProcessStatus {
188 pub error: String,
189 pub code: String,
190 pub data: Option<TransactionProcessStatusData>,
191}
192
193#[derive(Debug, Clone, Serialize, Deserialize)]
195pub struct ArgCreateTransaction {
196 pub nonce: u64,
197 pub value: String,
198 pub rcv_addr: SdkAddress,
199 pub snd_addr: SdkAddress,
200 pub gas_price: u64,
201 pub gas_limit: u64,
202 pub data: Option<String>,
203 pub signature: String,
204 pub chain_id: String,
205 pub version: u32,
206 pub options: u32,
207 pub available_balance: String,
208}
209
210#[derive(Debug, Clone, Serialize, Deserialize)]
211#[serde(rename_all = "camelCase")]
212pub struct SendTransactionData {
213 pub tx_hash: String,
214}
215
216#[derive(Debug, Clone, Serialize, Deserialize)]
218pub struct SendTransactionResponse {
219 pub error: String,
220 pub code: String,
221 pub data: Option<SendTransactionData>,
222}
223
224#[derive(Debug, Clone, Serialize, Deserialize)]
225#[serde(rename_all = "camelCase")]
226pub struct SendTransactionsResponseData {
227 pub num_of_sent_txs: i32,
228 pub txs_hashes: HashMap<i32, String>,
229}
230
231#[derive(Debug, Clone, Serialize, Deserialize)]
233pub struct SendTransactionsResponse {
234 pub error: String,
235 pub code: String,
236 pub data: Option<SendTransactionsResponseData>,
237}
238
239#[cfg(test)]
240mod test {
241 use super::*;
242
243 #[test]
244 fn parse_event_log_0() {
245 let data = r#"
246{
247 "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv",
248 "identifier": "completedTxEvent",
249 "topics": [],
250 "data": null,
251 "additionalData": null
252}
253 "#;
254
255 let event_log = serde_json::from_str::<Events>(data).unwrap();
256 assert_eq!(event_log.data, LogData::Empty);
257 }
258
259 #[test]
260 fn parse_event_log_1() {
261 let data = r#"
262{
263 "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv",
264 "identifier": "completedTxEvent",
265 "topics": [],
266 "data": "data-string",
267 "additionalData": null
268}
269 "#;
270
271 let event_log = serde_json::from_str::<Events>(data).unwrap();
272 assert_eq!(event_log.data, LogData::String("data-string".to_owned()));
273 }
274
275 #[test]
276 fn parse_event_log_2() {
277 let data = r#"
278{
279 "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv",
280 "identifier": "completedTxEvent",
281 "topics": [],
282 "data": [
283 "data1",
284 "data2"
285 ],
286 "additionalData": null
287}
288 "#;
289
290 let event_log = serde_json::from_str::<Events>(data).unwrap();
291 assert_eq!(
292 event_log.data,
293 LogData::Vec(vec!["data1".to_owned(), "data2".to_owned()])
294 );
295 }
296
297 #[test]
298 fn parse_transaction_info_no_signature() {
299 let data = r#"
300{
301 "data": {
302 "transaction": {
303 "type": "unsigned",
304 "processingTypeOnSource": "SCInvoking",
305 "processingTypeOnDestination": "SCInvoking",
306 "hash": "34cd9c6d0f68c0975971352ed4dcaacc1acd9a2dbd8f5840a2866d09b1d72298",
307 "nonce": 0,
308 "round": 5616535,
309 "epoch": 2314,
310 "value": "0",
311 "receiver": "erd1qqqqqqqqqqqqqpgq0mhy244pyr9pzdhahvvyze4rw3xl29q4kklszyzq72",
312 "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u",
313 "gasPrice": 1000000000,
314 "gasLimit": 25411165,
315 "gasUsed": 1197500,
316 "data": "",
317 "previousTransactionHash": "6c105dc2bb6ca8b89cfcac910a46310812b51312a281837096fc94dd771bb652",
318 "originalTransactionHash": "100d1edd0434938ec39e6cb5059601b4618a1ca25b91c38e5be9e75444b3c4f5",
319 "originalSender": "erd1wavgcxq9tfyrw49k3s3h34085mayu82wqvpd4h6akyh8559pkklsknwhwh",
320 "sourceShard": 4294967295,
321 "destinationShard": 1,
322 "blockNonce": 5547876,
323 "blockHash": "0d7caaf8f2bf46e913f91867527d44cd1c77453c9aee50d91a10739bd272d00c",
324 "notarizedAtSourceInMetaNonce": 5551265,
325 "NotarizedAtSourceInMetaHash": "4c87bc5161925a3902e43a7f9f186e63f21f827ef1129ad0e609a0d45dca016a",
326 "notarizedAtDestinationInMetaNonce": 5551269,
327 "notarizedAtDestinationInMetaHash": "83bfa8463558ee6d2c90b34ee03782619b699fea667acfb98924227bacbba93d",
328 "miniblockType": "SmartContractResultBlock",
329 "miniblockHash": "c12693db88e3b69b68d5279fd8939ec75b7f0d8e529e7fd950c83b5716a436bd",
330 "hyperblockNonce": 5551269,
331 "hyperblockHash": "83bfa8463558ee6d2c90b34ee03782619b699fea667acfb98924227bacbba93d",
332 "timestamp": 1727699210,
333 "logs": {
334 "address": "erd1qqqqqqqqqqqqqpgq0mhy244pyr9pzdhahvvyze4rw3xl29q4kklszyzq72",
335 "events": [
336 {
337 "address": "erd1qqqqqqqqqqqqqpgq0mhy244pyr9pzdhahvvyze4rw3xl29q4kklszyzq72",
338 "identifier": "transferValueOnly",
339 "topics": [
340 "I4byb8EAAA==",
341 "AAAAAAAAAAAFAMMiO8pDAH5z5hUCqfc+N03C7UI6tb8="
342 ],
343 "data": "RXhlY3V0ZU9uRGVzdENvbnRleHQ=",
344 "additionalData": [
345 "RXhlY3V0ZU9uRGVzdENvbnRleHQ=",
346 "ZGVwbG95SW50ZXJjaGFpblRva2Vu",
347 "GeLN3wLxaJKDPbaxdmqkIh0pFNi1l8WJeqy9TofeG40=",
348 "YXZhbGFuY2hlLWZ1amk=",
349 "SVRTVGVzdFRva2Vu",
350 "SVRTVFQ=",
351 "Bg==",
352 "d1iMGAVaSDdUtowjeNXnpvpOHU4DAtrfXbEuelChtb8="
353 ]
354 }
355 ]
356 },
357 "status": "success",
358 "operation": "transfer",
359 "fee": "0",
360 "callType": "asynchronousCallBack",
361 "options": 0
362 }
363 },
364 "error": "",
365 "code": "successful"
366}
367 "#;
368
369 let transaction = serde_json::from_str::<TransactionInfo>(data).unwrap();
370 assert_eq!(
371 transaction.data.unwrap().transaction.hash.unwrap(),
372 "34cd9c6d0f68c0975971352ed4dcaacc1acd9a2dbd8f5840a2866d09b1d72298"
373 );
374 }
375}