openzeppelin_relayer/domain/transaction/
common.rs1use chrono::{DateTime, Duration, Utc};
8
9use crate::constants::FINAL_TRANSACTION_STATUSES;
10use crate::models::{TransactionError, TransactionRepoModel, TransactionStatus};
11
12pub fn is_final_state(tx_status: &TransactionStatus) -> bool {
26 FINAL_TRANSACTION_STATUSES.contains(tx_status)
27}
28
29pub fn is_pending_transaction(tx_status: &TransactionStatus) -> bool {
30 matches!(
31 tx_status,
32 TransactionStatus::Pending | TransactionStatus::Sent | TransactionStatus::Submitted
33 )
34}
35
36pub fn is_unsubmitted_transaction(tx_status: &TransactionStatus) -> bool {
37 matches!(
38 tx_status,
39 TransactionStatus::Pending | TransactionStatus::Sent
40 )
41}
42
43pub fn get_age_of_sent_at(tx: &TransactionRepoModel) -> Result<Duration, TransactionError> {
45 let now = Utc::now();
46 let sent_at_str = tx.sent_at.as_ref().ok_or_else(|| {
47 TransactionError::UnexpectedError("Transaction sent_at time is missing".to_string())
48 })?;
49 let sent_time = DateTime::parse_from_rfc3339(sent_at_str)
50 .map_err(|_| TransactionError::UnexpectedError("Error parsing sent_at time".to_string()))?
51 .with_timezone(&Utc);
52 Ok(now.signed_duration_since(sent_time))
53}
54
55#[cfg(test)]
56mod tests {
57 use crate::utils::mocks::mockutils::create_mock_transaction;
58
59 use super::*;
60
61 #[test]
62 fn test_is_final_state() {
63 assert!(is_final_state(&TransactionStatus::Confirmed));
65 assert!(is_final_state(&TransactionStatus::Failed));
66 assert!(is_final_state(&TransactionStatus::Expired));
67 assert!(is_final_state(&TransactionStatus::Canceled));
68
69 assert!(!is_final_state(&TransactionStatus::Pending));
71 assert!(!is_final_state(&TransactionStatus::Sent));
72 assert!(!is_final_state(&TransactionStatus::Submitted));
73 assert!(!is_final_state(&TransactionStatus::Mined));
74 }
75
76 #[test]
77 fn test_is_pending_transaction() {
78 assert!(is_pending_transaction(&TransactionStatus::Pending));
80
81 assert!(is_pending_transaction(&TransactionStatus::Sent));
83
84 assert!(is_pending_transaction(&TransactionStatus::Submitted));
86
87 assert!(!is_pending_transaction(&TransactionStatus::Confirmed));
89 assert!(!is_pending_transaction(&TransactionStatus::Failed));
90 assert!(!is_pending_transaction(&TransactionStatus::Canceled));
91 assert!(!is_pending_transaction(&TransactionStatus::Mined));
92 assert!(!is_pending_transaction(&TransactionStatus::Expired));
93 }
94
95 #[test]
96 fn test_is_unsubmitted_transaction() {
97 assert!(is_unsubmitted_transaction(&TransactionStatus::Pending));
99 assert!(is_unsubmitted_transaction(&TransactionStatus::Sent));
100
101 assert!(!is_unsubmitted_transaction(&TransactionStatus::Submitted));
103 assert!(!is_unsubmitted_transaction(&TransactionStatus::Mined));
104 assert!(!is_unsubmitted_transaction(&TransactionStatus::Confirmed));
105 assert!(!is_unsubmitted_transaction(&TransactionStatus::Failed));
106 assert!(!is_unsubmitted_transaction(&TransactionStatus::Canceled));
107 assert!(!is_unsubmitted_transaction(&TransactionStatus::Expired));
108 }
109
110 #[test]
111 fn test_get_age_of_sent_at() {
112 let now = Utc::now();
113
114 let sent_at_time = now - Duration::hours(1);
116 let mut tx = create_mock_transaction();
117 tx.sent_at = Some(sent_at_time.to_rfc3339());
118
119 let age_result = get_age_of_sent_at(&tx);
120 assert!(age_result.is_ok());
121 let age = age_result.unwrap();
122 assert!(age.num_minutes() >= 59 && age.num_minutes() <= 61);
124 }
125
126 #[test]
127 fn test_get_age_of_sent_at_missing_sent_at() {
128 let mut tx = create_mock_transaction();
129 tx.sent_at = None; let result = get_age_of_sent_at(&tx);
132 assert!(result.is_err());
133 match result.unwrap_err() {
134 TransactionError::UnexpectedError(msg) => {
135 assert!(msg.contains("sent_at time is missing"));
136 }
137 _ => panic!("Expected UnexpectedError for missing sent_at"),
138 }
139 }
140
141 #[test]
142 fn test_get_age_of_sent_at_invalid_timestamp() {
143 let mut tx = create_mock_transaction();
144 tx.sent_at = Some("invalid-timestamp".to_string()); let result = get_age_of_sent_at(&tx);
147 assert!(result.is_err());
148 match result.unwrap_err() {
149 TransactionError::UnexpectedError(msg) => {
150 assert!(msg.contains("Error parsing sent_at time"));
151 }
152 _ => panic!("Expected UnexpectedError for invalid timestamp"),
153 }
154 }
155}