defuse/contract/
garbage_collector.rs

1use defuse_core::{ExpirableNonce, Nonce, SaltedNonce, VersionedNonce, engine::State};
2use defuse_serde_utils::base64::AsBase64;
3use near_plugins::{AccessControllable, access_control_any};
4use near_sdk::{AccountId, assert_one_yocto, near};
5
6use super::{Contract, ContractExt, Role};
7use crate::{garbage_collector::GarbageCollector, salts::SaltManager};
8
9#[near]
10impl GarbageCollector for Contract {
11    #[access_control_any(roles(Role::DAO, Role::GarbageCollector))]
12    #[payable]
13    fn cleanup_nonces(&mut self, nonces: Vec<(AccountId, Vec<AsBase64<Nonce>>)>) {
14        assert_one_yocto();
15
16        for (account_id, nonces) in nonces {
17            for nonce in nonces.into_iter().map(AsBase64::into_inner) {
18                if !self.is_nonce_cleanable(nonce) {
19                    continue;
20                }
21
22                // NOTE: all errors are omitted
23                let [prefix @ .., _] = nonce;
24                let _ = State::cleanup_nonce_by_prefix(self, &account_id, prefix);
25            }
26        }
27    }
28}
29
30impl Contract {
31    #[inline]
32    fn is_nonce_cleanable(&self, nonce: Nonce) -> bool {
33        let Some(versioned_nonce) = VersionedNonce::maybe_from(nonce) else {
34            return false;
35        };
36
37        match versioned_nonce {
38            VersionedNonce::V1(SaltedNonce {
39                salt,
40                nonce: ExpirableNonce { deadline, .. },
41            }) => deadline.has_expired() || !self.is_valid_salt(salt),
42        }
43    }
44}