defuse_core/engine/state/
mod.rs1pub 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 fn is_auth_by_predecessor_id_enabled(&self, account_id: &AccountIdRef) -> bool;
53
54 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 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}