defuse_core/nonce/
expirable.rs1use borsh::{BorshDeserialize, BorshSerialize};
2use defuse_borsh_utils::As;
3use defuse_time::{Timestamp, borsh::TimestampNanoSeconds};
4
5#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
7pub struct ExpirableNonce<T>
8where
9 T: BorshSerialize + BorshDeserialize,
10{
11 #[borsh(
12 serialize_with = "As::<TimestampNanoSeconds<i64>>::serialize",
13 deserialize_with = "As::<TimestampNanoSeconds<i64>>::deserialize"
14 )]
15 pub deadline: Timestamp,
16 pub nonce: T,
17}
18
19impl<T> ExpirableNonce<T>
20where
21 T: BorshSerialize + BorshDeserialize,
22{
23 pub const fn new(deadline: Timestamp, nonce: T) -> Self {
24 Self { deadline, nonce }
25 }
26
27 #[inline]
28 pub fn has_expired(&self) -> bool {
29 self.deadline < Timestamp::now()
30 }
31}
32
33#[cfg(test)]
34mod tests {
35 use std::time::Duration;
36
37 use super::*;
38
39 use defuse_test_utils::random::random_bytes;
40 use rstest::rstest;
41
42 #[rstest]
43 fn expirable_test(random_bytes: Vec<u8>) {
44 let mut u = arbitrary::Unstructured::new(&random_bytes);
45 let nonce: [u8; 24] = u.arbitrary().unwrap();
46
47 let expired = ExpirableNonce::new(Timestamp::now() - Duration::from_hours(24), nonce);
48 assert!(expired.has_expired());
49
50 let not_expired = ExpirableNonce::new(Timestamp::now() + Duration::from_hours(24), nonce);
51 assert!(!not_expired.has_expired());
52 }
53}