use std::collections::HashMap;
use super::{sdk_address::SdkAddress, vm::CallType};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Transaction {
pub nonce: u64,
pub value: String,
pub receiver: SdkAddress,
pub sender: SdkAddress,
pub gas_price: u64,
pub gas_limit: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub signature: Option<String>,
#[serde(rename = "chainID")]
pub chain_id: String,
pub version: u32,
#[serde(skip_serializing_if = "is_zero")]
pub options: u32,
}
#[allow(clippy::trivially_copy_pass_by_ref)]
fn is_zero(num: &u32) -> bool {
*num == 0
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TxCostResponseData {
pub tx_gas_units: u64,
pub return_message: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ResponseTxCost {
pub data: Option<TxCostResponseData>,
pub error: String,
pub code: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct TransactionOnNetwork {
#[serde(rename = "type")]
pub kind: String,
pub hash: Option<String>,
pub nonce: u64,
pub round: u64,
pub epoch: u64,
pub value: String,
pub receiver: SdkAddress,
pub sender: SdkAddress,
pub gas_price: u64,
pub gas_limit: u64,
#[serde(default)]
pub gas_used: u64,
#[serde(default)]
pub signature: String,
pub source_shard: u32,
pub destination_shard: u32,
pub block_nonce: u64,
pub block_hash: String,
pub notarized_at_source_in_meta_nonce: Option<u64>,
#[serde(rename = "NotarizedAtSourceInMetaHash")]
pub notarized_at_source_in_meta_hash: Option<String>,
pub notarized_at_destination_in_meta_nonce: Option<u64>,
pub notarized_at_destination_in_meta_hash: Option<String>,
pub processing_type_on_destination: String,
pub miniblock_type: String,
pub miniblock_hash: String,
pub timestamp: u64,
pub data: Option<String>,
pub status: String,
pub hyperblock_nonce: Option<u64>,
pub hyperblock_hash: Option<String>,
#[serde(default)]
pub smart_contract_results: Vec<ApiSmartContractResult>,
pub logs: Option<ApiLogs>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Events {
pub address: SdkAddress,
pub identifier: String,
pub topics: Option<Vec<String>>,
#[serde(default)]
pub data: LogData,
}
#[derive(Default, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(untagged)]
pub enum LogData {
#[default]
Empty,
String(String),
Vec(Vec<String>),
}
impl LogData {
pub fn for_each<F: FnMut(&String)>(&self, mut f: F) {
match self {
LogData::Empty => {},
LogData::String(s) => f(s),
LogData::Vec(v) => v.iter().for_each(f),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ApiLogs {
pub address: SdkAddress,
pub events: Vec<Events>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ApiSmartContractResult {
pub hash: String,
pub nonce: u64,
pub value: u64,
pub receiver: SdkAddress,
pub sender: SdkAddress,
#[serde(default)]
pub data: String,
pub prev_tx_hash: String,
pub original_tx_hash: String,
pub gas_limit: u64,
pub gas_price: u64,
pub call_type: CallType,
pub relayer_address: Option<String>,
pub relayed_value: Option<String>,
pub code: Option<String>,
pub code_metadata: Option<String>,
pub return_message: Option<String>,
pub original_sender: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionInfoData {
pub transaction: TransactionOnNetwork,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionInfo {
#[serde(default)]
pub error: String,
pub code: String,
pub data: Option<TransactionInfoData>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionStatusData {
pub status: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionStatus {
pub error: String,
pub code: String,
pub data: Option<TransactionStatusData>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionProcessStatusData {
pub reason: String,
pub status: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionProcessStatus {
pub error: String,
pub code: String,
pub data: Option<TransactionProcessStatusData>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ArgCreateTransaction {
pub nonce: u64,
pub value: String,
pub rcv_addr: SdkAddress,
pub snd_addr: SdkAddress,
pub gas_price: u64,
pub gas_limit: u64,
pub data: Option<String>,
pub signature: String,
pub chain_id: String,
pub version: u32,
pub options: u32,
pub available_balance: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SendTransactionData {
pub tx_hash: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SendTransactionResponse {
pub error: String,
pub code: String,
pub data: Option<SendTransactionData>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SendTransactionsResponseData {
pub num_of_sent_txs: i32,
pub txs_hashes: HashMap<i32, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SendTransactionsResponse {
pub error: String,
pub code: String,
pub data: Option<SendTransactionsResponseData>,
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn parse_event_log_0() {
let data = r#"
{
"address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv",
"identifier": "completedTxEvent",
"topics": [],
"data": null,
"additionalData": null
}
"#;
let event_log = serde_json::from_str::<Events>(data).unwrap();
assert_eq!(event_log.data, LogData::Empty);
}
#[test]
fn parse_event_log_1() {
let data = r#"
{
"address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv",
"identifier": "completedTxEvent",
"topics": [],
"data": "data-string",
"additionalData": null
}
"#;
let event_log = serde_json::from_str::<Events>(data).unwrap();
assert_eq!(event_log.data, LogData::String("data-string".to_owned()));
}
#[test]
fn parse_event_log_2() {
let data = r#"
{
"address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv",
"identifier": "completedTxEvent",
"topics": [],
"data": [
"data1",
"data2"
],
"additionalData": null
}
"#;
let event_log = serde_json::from_str::<Events>(data).unwrap();
assert_eq!(
event_log.data,
LogData::Vec(vec!["data1".to_owned(), "data2".to_owned()])
);
}
#[test]
fn parse_transaction_info_no_signature() {
let data = r#"
{
"data": {
"transaction": {
"type": "unsigned",
"processingTypeOnSource": "SCInvoking",
"processingTypeOnDestination": "SCInvoking",
"hash": "34cd9c6d0f68c0975971352ed4dcaacc1acd9a2dbd8f5840a2866d09b1d72298",
"nonce": 0,
"round": 5616535,
"epoch": 2314,
"value": "0",
"receiver": "erd1qqqqqqqqqqqqqpgq0mhy244pyr9pzdhahvvyze4rw3xl29q4kklszyzq72",
"sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u",
"gasPrice": 1000000000,
"gasLimit": 25411165,
"gasUsed": 1197500,
"data": "",
"previousTransactionHash": "6c105dc2bb6ca8b89cfcac910a46310812b51312a281837096fc94dd771bb652",
"originalTransactionHash": "100d1edd0434938ec39e6cb5059601b4618a1ca25b91c38e5be9e75444b3c4f5",
"originalSender": "erd1wavgcxq9tfyrw49k3s3h34085mayu82wqvpd4h6akyh8559pkklsknwhwh",
"sourceShard": 4294967295,
"destinationShard": 1,
"blockNonce": 5547876,
"blockHash": "0d7caaf8f2bf46e913f91867527d44cd1c77453c9aee50d91a10739bd272d00c",
"notarizedAtSourceInMetaNonce": 5551265,
"NotarizedAtSourceInMetaHash": "4c87bc5161925a3902e43a7f9f186e63f21f827ef1129ad0e609a0d45dca016a",
"notarizedAtDestinationInMetaNonce": 5551269,
"notarizedAtDestinationInMetaHash": "83bfa8463558ee6d2c90b34ee03782619b699fea667acfb98924227bacbba93d",
"miniblockType": "SmartContractResultBlock",
"miniblockHash": "c12693db88e3b69b68d5279fd8939ec75b7f0d8e529e7fd950c83b5716a436bd",
"hyperblockNonce": 5551269,
"hyperblockHash": "83bfa8463558ee6d2c90b34ee03782619b699fea667acfb98924227bacbba93d",
"timestamp": 1727699210,
"logs": {
"address": "erd1qqqqqqqqqqqqqpgq0mhy244pyr9pzdhahvvyze4rw3xl29q4kklszyzq72",
"events": [
{
"address": "erd1qqqqqqqqqqqqqpgq0mhy244pyr9pzdhahvvyze4rw3xl29q4kklszyzq72",
"identifier": "transferValueOnly",
"topics": [
"I4byb8EAAA==",
"AAAAAAAAAAAFAMMiO8pDAH5z5hUCqfc+N03C7UI6tb8="
],
"data": "RXhlY3V0ZU9uRGVzdENvbnRleHQ=",
"additionalData": [
"RXhlY3V0ZU9uRGVzdENvbnRleHQ=",
"ZGVwbG95SW50ZXJjaGFpblRva2Vu",
"GeLN3wLxaJKDPbaxdmqkIh0pFNi1l8WJeqy9TofeG40=",
"YXZhbGFuY2hlLWZ1amk=",
"SVRTVGVzdFRva2Vu",
"SVRTVFQ=",
"Bg==",
"d1iMGAVaSDdUtowjeNXnpvpOHU4DAtrfXbEuelChtb8="
]
}
]
},
"status": "success",
"operation": "transfer",
"fee": "0",
"callType": "asynchronousCallBack",
"options": 0
}
},
"error": "",
"code": "successful"
}
"#;
let transaction = serde_json::from_str::<TransactionInfo>(data).unwrap();
assert_eq!(
transaction.data.unwrap().transaction.hash.unwrap(),
"34cd9c6d0f68c0975971352ed4dcaacc1acd9a2dbd8f5840a2866d09b1d72298"
);
}
}