Skip to main content

cougr_core/accounts/
replay.rs

1use soroban_sdk::{Address, Env, Symbol};
2
3use super::error::AccountError;
4
5const ACCOUNT_NONCE_PREFIX: &str = "acct_nonce";
6
7/// Persistent nonce tracking for replay protection.
8pub struct ReplayProtection;
9
10impl ReplayProtection {
11    pub fn next_account_nonce(env: &Env, account: &Address) -> u64 {
12        let key = Self::storage_key(env, account);
13        env.storage().persistent().get(&key).unwrap_or(0)
14    }
15
16    pub fn verify_and_consume_account_nonce(
17        env: &Env,
18        account: &Address,
19        nonce: u64,
20    ) -> Result<u64, AccountError> {
21        let expected = Self::next_account_nonce(env, account);
22        if nonce != expected {
23            return Err(AccountError::NonceMismatch);
24        }
25        env.storage()
26            .persistent()
27            .set(&Self::storage_key(env, account), &(expected + 1));
28        Ok(expected)
29    }
30
31    fn storage_key(env: &Env, account: &Address) -> (Symbol, Address) {
32        (Symbol::new(env, ACCOUNT_NONCE_PREFIX), account.clone())
33    }
34}