defuse/contract/
garbage_collector.rs1use 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 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}