Skip to main content

defuse_core/engine/state/
mod.rs

1pub mod cached;
2pub mod deltas;
3
4use crate::{
5    AccountId, AccountIdRef, Nonce, NoncePrefix, Result, Salt,
6    amounts::Amounts,
7    fees::Pips,
8    intents::{
9        auth::AuthCall,
10        tokens::{
11            FtWithdraw, MtWithdraw, NativeWithdraw, NftWithdraw, NotifyOnTransfer, StorageDeposit,
12        },
13    },
14    public_key::PublicKey,
15    token_id::{TokenId, nep141::Nep141TokenId},
16};
17use cached::CachedState;
18use impl_tools::autoimpl;
19use std::borrow::Cow;
20
21#[cfg(feature = "imt")]
22use crate::{
23    DefuseError,
24    tokens::{MT_ON_TRANSFER_GAS_DEFAULT, MT_ON_TRANSFER_GAS_MIN, imt::ImtTokens},
25};
26
27#[autoimpl(for<T: trait + ?Sized> &T, &mut T, Box<T>)]
28pub trait StateView {
29    fn verifying_contract(&self) -> Cow<'_, AccountIdRef>;
30    fn wnear_id(&self) -> Cow<'_, AccountIdRef>;
31    fn wnear_token_id(&self) -> TokenId {
32        Nep141TokenId::new(self.wnear_id().into_owned()).into()
33    }
34
35    fn fee(&self) -> Pips;
36    fn fee_collector(&self) -> Cow<'_, AccountIdRef>;
37
38    #[must_use]
39    fn has_public_key(&self, account_id: &AccountIdRef, public_key: &PublicKey) -> bool;
40    fn iter_public_keys(&self, account_id: &AccountIdRef) -> impl Iterator<Item = PublicKey> + '_;
41
42    #[must_use]
43    fn is_nonce_used(&self, account_id: &AccountIdRef, nonce: Nonce) -> bool;
44
45    #[must_use]
46    fn balance_of(&self, account_id: &AccountIdRef, token_id: &TokenId) -> u128;
47
48    fn is_account_locked(&self, account_id: &AccountIdRef) -> bool;
49
50    /// Returns whether authentication by `PREDECESSOR_ID` is enabled.
51    fn is_auth_by_predecessor_id_enabled(&self, account_id: &AccountIdRef) -> bool;
52
53    /// Returns whether salt in nonce is valid
54    fn is_valid_salt(&self, salt: Salt) -> bool;
55
56    #[inline]
57    fn cached(self) -> CachedState<Self>
58    where
59        Self: Sized,
60    {
61        CachedState::new(self)
62    }
63}
64
65#[autoimpl(for<T: trait + ?Sized> &mut T, Box<T>)]
66pub trait State: StateView {
67    fn add_public_key(&mut self, account_id: AccountId, public_key: PublicKey) -> Result<()>;
68
69    fn remove_public_key(&mut self, account_id: AccountId, public_key: PublicKey) -> Result<()>;
70
71    fn commit_nonce(&mut self, account_id: AccountId, nonce: Nonce) -> Result<()>;
72
73    fn cleanup_nonce_by_prefix(
74        &mut self,
75        account_id: &AccountIdRef,
76        prefix: NoncePrefix,
77    ) -> Result<bool>;
78
79    fn internal_add_balance(
80        &mut self,
81        owner_id: AccountId,
82        tokens: impl IntoIterator<Item = (TokenId, u128)>,
83    ) -> Result<()>;
84
85    fn internal_sub_balance(
86        &mut self,
87        owner_id: &AccountIdRef,
88        tokens: impl IntoIterator<Item = (TokenId, u128)>,
89    ) -> Result<()>;
90
91    fn internal_apply_deltas(
92        &mut self,
93        owner_id: &AccountIdRef,
94        tokens: impl IntoIterator<Item = (TokenId, i128)>,
95    ) -> Result<()> {
96        for (token_id, delta) in tokens {
97            let tokens = [(token_id, delta.unsigned_abs())];
98            if delta.is_negative() {
99                self.internal_sub_balance(owner_id, tokens)?;
100            } else {
101                self.internal_add_balance(owner_id.to_owned(), tokens)?;
102            }
103        }
104        Ok(())
105    }
106
107    fn ft_withdraw(&mut self, owner_id: &AccountIdRef, withdraw: FtWithdraw) -> Result<()>;
108
109    fn nft_withdraw(&mut self, owner_id: &AccountIdRef, withdraw: NftWithdraw) -> Result<()>;
110
111    fn mt_withdraw(&mut self, owner_id: &AccountIdRef, withdraw: MtWithdraw) -> Result<()>;
112
113    fn native_withdraw(&mut self, owner_id: &AccountIdRef, withdraw: NativeWithdraw) -> Result<()>;
114
115    fn notify_on_transfer(
116        &self,
117        sender_id: &AccountIdRef,
118        receiver_id: AccountId,
119        tokens: Amounts,
120        notification: NotifyOnTransfer,
121    );
122
123    fn storage_deposit(
124        &mut self,
125        owner_id: &AccountIdRef,
126        storage_deposit: StorageDeposit,
127    ) -> Result<()>;
128
129    /// Sets whether authentication by `PREDECESSOR_ID` is enabled.
130    /// Returns whether authentication by `PREDECESSOR_ID` was toggled.
131    fn set_auth_by_predecessor_id(&mut self, account_id: AccountId, enable: bool) -> Result<bool>;
132
133    fn auth_call(&mut self, signer_id: &AccountIdRef, auth_call: AuthCall) -> Result<()>;
134
135    fn mint(&mut self, owner_id: AccountId, tokens: Amounts, memo: Option<String>) -> Result<()>;
136
137    fn burn(
138        &mut self,
139        owner_id: &AccountIdRef,
140        tokens: Amounts,
141        memo: Option<String>,
142    ) -> Result<()>;
143
144    #[cfg(feature = "imt")]
145    fn imt_mint(
146        &mut self,
147        minter_id: &AccountIdRef,
148        receiver_id: AccountId,
149        tokens: ImtTokens,
150        memo: Option<String>,
151        notification: Option<NotifyOnTransfer>,
152    ) -> Result<()> {
153        if tokens.is_empty() {
154            return Err(DefuseError::InvalidIntent);
155        }
156
157        let tokens = tokens.into_generic_tokens(minter_id)?;
158        self.mint(receiver_id.clone(), tokens.clone(), memo)?;
159
160        if let Some(mut notification) = notification {
161            notification.min_gas = Some(
162                notification
163                    .min_gas
164                    .unwrap_or(MT_ON_TRANSFER_GAS_DEFAULT)
165                    .max(MT_ON_TRANSFER_GAS_MIN),
166            );
167
168            self.notify_on_transfer(minter_id, receiver_id, tokens, notification);
169        }
170
171        Ok(())
172    }
173
174    #[cfg(feature = "imt")]
175    fn imt_burn(
176        &mut self,
177        owner_id: &AccountIdRef,
178        minter_id: &AccountIdRef,
179        tokens: ImtTokens,
180        memo: Option<String>,
181    ) -> Result<()> {
182        if tokens.is_empty() {
183            return Err(crate::DefuseError::InvalidIntent);
184        }
185
186        let tokens = tokens.into_generic_tokens(minter_id)?;
187
188        self.burn(owner_id, tokens, memo)
189    }
190}