Skip to main content

defuse_core/nonce/
expirable.rs

1use borsh::{BorshDeserialize, BorshSerialize};
2use defuse_borsh_utils::As;
3use defuse_time::{Timestamp, borsh::TimestampNanoSeconds};
4
5/// Expirable nonces contain deadline which is 8 bytes of timestamp in nanoseconds
6#[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}