1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
4pub enum TxStatus {
5 Pending,
6 Mined,
7 Failed,
8 Replaced,
9}
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct PendingTransaction {
13 pub id: String,
14 pub to: String,
15 pub data: Vec<u8>,
16 pub nonce: u64,
17 pub gas_limit: String,
18 pub gas_price: String,
19 pub tx_hash: String,
20 pub first_sent_at: u64,
21 pub last_update_at: u64,
22 pub status: TxStatus,
23}
24
25#[cfg(test)]
26mod tests {
27 use super::*;
28
29 #[test]
30 fn test_tx_status_serialization_roundtrip() {
31 for status in [
32 TxStatus::Pending,
33 TxStatus::Mined,
34 TxStatus::Failed,
35 TxStatus::Replaced,
36 ] {
37 let json = serde_json::to_string(&status).unwrap();
38 let decoded: TxStatus = serde_json::from_str(&json).unwrap();
39 assert_eq!(status, decoded);
40 }
41 }
42
43 #[test]
44 fn test_pending_transaction_json_roundtrip() {
45 let tx = PendingTransaction {
46 id: "packet-abc123".to_string(),
47 to: "0xdeadbeef00000000000000000000000000000001".to_string(),
48 data: vec![1, 2, 3, 4],
49 nonce: 42,
50 gas_limit: "21000".to_string(),
51 gas_price: "1000000000".to_string(),
52 tx_hash: "0xabc".to_string(),
53 first_sent_at: 1_700_000_000,
54 last_update_at: 1_700_000_100,
55 status: TxStatus::Pending,
56 };
57
58 let json = serde_json::to_string(&tx).unwrap();
59 let decoded: PendingTransaction = serde_json::from_str(&json).unwrap();
60
61 assert_eq!(decoded.id, tx.id);
62 assert_eq!(decoded.nonce, tx.nonce);
63 assert_eq!(decoded.status, tx.status);
64 assert_eq!(decoded.data, tx.data);
65 }
66
67 #[test]
68 fn test_tx_status_all_variants_distinct() {
69 let statuses = [
70 TxStatus::Pending,
71 TxStatus::Mined,
72 TxStatus::Failed,
73 TxStatus::Replaced,
74 ];
75 for i in 0..statuses.len() {
77 for j in 0..statuses.len() {
78 if i != j {
79 assert_ne!(statuses[i], statuses[j]);
80 }
81 }
82 }
83 }
84}