defuse_core/engine/state/
mod.rs

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