Skip to main content

miden_base_sys/bindings/
active_account.rs

1use miden_stdlib_sys::{Felt, Word, WordAligned};
2
3use super::types::{AccountId, Nonce, RawAccountId};
4
5#[allow(improper_ctypes)]
6unsafe extern "C" {
7    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
8    #[link_name = "miden::protocol::active_account::get_id"]
9    fn extern_active_account_get_id(ptr: *mut RawAccountId);
10    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
11    #[link_name = "miden::protocol::active_account::get_nonce"]
12    fn extern_active_account_get_nonce() -> Felt;
13    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
14    #[link_name = "miden::protocol::active_account::compute_commitment"]
15    fn extern_active_account_compute_commitment(ptr: *mut Word);
16    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
17    #[link_name = "miden::protocol::active_account::get_code_commitment"]
18    fn extern_active_account_get_code_commitment(ptr: *mut Word);
19    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
20    #[link_name = "miden::protocol::active_account::compute_storage_commitment"]
21    fn extern_active_account_compute_storage_commitment(ptr: *mut Word);
22    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
23    #[link_name = "miden::protocol::active_account::get_asset"]
24    fn extern_active_account_get_asset(
25        asset_key_0: Felt,
26        asset_key_1: Felt,
27        asset_key_2: Felt,
28        asset_key_3: Felt,
29        ptr: *mut Word,
30    );
31    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
32    #[link_name = "miden::protocol::active_account::has_asset"]
33    fn extern_active_account_has_asset(
34        asset_id_0: Felt,
35        asset_id_1: Felt,
36        asset_id_2: Felt,
37        asset_id_3: Felt,
38    ) -> Felt;
39    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
40    #[link_name = "miden::protocol::active_account::get_vault_root"]
41    fn extern_active_account_get_vault_root(ptr: *mut Word);
42    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
43    #[link_name = "miden::protocol::active_account::get_num_procedures"]
44    fn extern_active_account_get_num_procedures() -> Felt;
45    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
46    #[link_name = "miden::protocol::active_account::get_procedure_root"]
47    fn extern_active_account_get_procedure_root(index: Felt, ptr: *mut Word);
48    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
49    #[link_name = "miden::protocol::active_account::has_procedure"]
50    fn extern_active_account_has_procedure(
51        proc_root_0: Felt,
52        proc_root_1: Felt,
53        proc_root_2: Felt,
54        proc_root_3: Felt,
55    ) -> Felt;
56}
57
58/// Returns the account ID of the active account.
59pub fn get_id() -> AccountId {
60    unsafe {
61        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<RawAccountId>::uninit());
62        extern_active_account_get_id(ret_area.as_mut_ptr());
63        ret_area.into_inner().assume_init().into_account_id()
64    }
65}
66
67/// Returns the nonce of the active account.
68#[inline]
69pub fn get_nonce() -> Nonce {
70    Nonce {
71        inner: unsafe { extern_active_account_get_nonce() },
72    }
73}
74
75/// Computes and returns the commitment of the current account data.
76#[inline]
77pub fn compute_commitment() -> Word {
78    unsafe {
79        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Word>::uninit());
80        extern_active_account_compute_commitment(ret_area.as_mut_ptr());
81        ret_area.into_inner().assume_init()
82    }
83}
84
85/// Returns the code commitment of the active account.
86#[inline]
87pub fn get_code_commitment() -> Word {
88    unsafe {
89        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Word>::uninit());
90        extern_active_account_get_code_commitment(ret_area.as_mut_ptr());
91        ret_area.into_inner().assume_init()
92    }
93}
94
95/// Computes the latest storage commitment of the active account.
96#[inline]
97pub fn compute_storage_commitment() -> Word {
98    unsafe {
99        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Word>::uninit());
100        extern_active_account_compute_storage_commitment(ret_area.as_mut_ptr());
101        ret_area.into_inner().assume_init()
102    }
103}
104
105/// Returns the current value stored under the specified `asset_key` in the active account vault.
106pub fn get_asset(asset_key: Word) -> Word {
107    unsafe {
108        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Word>::uninit());
109        extern_active_account_get_asset(
110            asset_key[0],
111            asset_key[1],
112            asset_key[2],
113            asset_key[3],
114            ret_area.as_mut_ptr(),
115        );
116        ret_area.into_inner().assume_init()
117    }
118}
119
120/// Returns `true` if the active account vault currently contains an asset with the specified asset
121/// id.
122#[inline]
123pub fn has_asset(asset_id: Word) -> bool {
124    unsafe {
125        extern_active_account_has_asset(asset_id[0], asset_id[1], asset_id[2], asset_id[3])
126            != Felt::new(0).unwrap()
127    }
128}
129
130/// Returns the current vault root of the active account.
131#[inline]
132pub fn get_vault_root() -> Word {
133    unsafe {
134        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Word>::uninit());
135        extern_active_account_get_vault_root(ret_area.as_mut_ptr());
136        ret_area.into_inner().assume_init()
137    }
138}
139
140/// Returns the number of procedures exported by the active account.
141#[inline]
142pub fn get_num_procedures() -> u32 {
143    // The transaction kernel guarantees procedure counts fit in a u32.
144    let count = unsafe { extern_active_account_get_num_procedures() };
145    count.as_canonical_u64() as u32
146}
147
148/// Returns the procedure root for the procedure at `index`.
149#[inline]
150pub fn get_procedure_root(index: u32) -> Word {
151    unsafe {
152        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Word>::uninit());
153        extern_active_account_get_procedure_root(Felt::from_u32(index), ret_area.as_mut_ptr());
154        ret_area.into_inner().assume_init()
155    }
156}
157
158/// Returns `true` if the procedure identified by `proc_root` exists on the active account.
159#[inline]
160pub fn has_procedure(proc_root: Word) -> bool {
161    unsafe {
162        extern_active_account_has_procedure(proc_root[0], proc_root[1], proc_root[2], proc_root[3])
163            != Felt::new(0).unwrap()
164    }
165}
166
167/// Trait that provides active account operations for components.
168///
169/// This trait is automatically implemented for the storage struct marked with the
170/// `#[component_storage]` macro.
171///
172/// A `#[account(...)]` component method that shares a name with one of these built-ins does not
173/// shadow it: both live on traits, so the call is disambiguated with
174/// `<Wallet as ActiveAccount>::get_id(account)` or `<Wallet as Interface>::get_id(account)`.
175pub trait ActiveAccount {
176    /// Guard hook invoked by every active-account operation before it runs.
177    ///
178    /// The default implementation is a no-op. Types that can also represent a *foreign* account
179    /// (for example the struct generated by the `#[account(...)]` macro) override this to reject
180    /// calls made on a foreign binding, because the active-account operations always target the
181    /// transaction's active account rather than the foreign one.
182    #[doc(hidden)]
183    #[inline]
184    fn __assert_active_account(&self) {}
185
186    /// Returns the account ID of the active account.
187    #[inline]
188    fn get_id(&self) -> AccountId {
189        self.__assert_active_account();
190        get_id()
191    }
192
193    /// Returns the nonce of the active account.
194    #[inline]
195    fn get_nonce(&self) -> Nonce {
196        self.__assert_active_account();
197        get_nonce()
198    }
199
200    /// Computes and returns the commitment of the current account data.
201    #[inline]
202    fn compute_commitment(&self) -> Word {
203        self.__assert_active_account();
204        compute_commitment()
205    }
206
207    /// Returns the code commitment of the active account.
208    #[inline]
209    fn get_code_commitment(&self) -> Word {
210        self.__assert_active_account();
211        get_code_commitment()
212    }
213
214    /// Computes the latest storage commitment of the active account.
215    #[inline]
216    fn compute_storage_commitment(&self) -> Word {
217        self.__assert_active_account();
218        compute_storage_commitment()
219    }
220
221    /// Returns the current value stored under the specified `asset_key` in the active account
222    /// vault.
223    #[inline]
224    fn get_asset(&self, asset_key: Word) -> Word {
225        self.__assert_active_account();
226        get_asset(asset_key)
227    }
228
229    /// Returns `true` if the active account vault currently contains an asset with the specified
230    /// asset id.
231    #[inline]
232    fn has_asset(&self, asset_id: Word) -> bool {
233        self.__assert_active_account();
234        has_asset(asset_id)
235    }
236
237    /// Returns the current vault root of the active account.
238    #[inline]
239    fn get_vault_root(&self) -> Word {
240        self.__assert_active_account();
241        get_vault_root()
242    }
243
244    /// Returns the number of procedures exported by the active account.
245    #[inline]
246    fn get_num_procedures(&self) -> u32 {
247        self.__assert_active_account();
248        get_num_procedures()
249    }
250
251    /// Returns the procedure root for the procedure at `index`.
252    #[inline]
253    fn get_procedure_root(&self, index: u32) -> Word {
254        self.__assert_active_account();
255        get_procedure_root(index)
256    }
257
258    /// Returns `true` if the procedure identified by `proc_root` exists on the active account.
259    #[inline]
260    fn has_procedure(&self, proc_root: Word) -> bool {
261        self.__assert_active_account();
262        has_procedure(proc_root)
263    }
264}
265
266/// Marker trait for account API wrapper types.
267///
268/// The `#[note]` and `#[tx_script]` macros instantiate their entrypoint account parameter
269/// through this trait, so that parameter must be a type implementing it. The `ActiveAccount`
270/// supertrait guarantees that parameter is usable as the transaction's active account and keeps
271/// unrelated `Default` types from satisfying the bound. The `#[account(...)]` macro implements
272/// both automatically; it is not a sealed capability boundary, so manual implementations are
273/// possible but normally unnecessary.
274#[diagnostic::on_unimplemented(
275    message = "`{Self}` is not an account wrapper generated by `#[account(...)]`",
276    note = "define a struct with `#[account(...)]` and use it as the entrypoint account parameter"
277)]
278pub trait AccountWrapper: ActiveAccount + Default {
279    /// Creates a binding to the transaction's active account.
280    ///
281    /// This is the account the transaction executes against, as opposed to a foreign account
282    /// reached through FPI (created with `new`).
283    #[inline(always)]
284    fn active() -> Self {
285        Self::default()
286    }
287}
288
289/// Exposes which account a generated `#[account(...)]` wrapper binds to.
290///
291/// The component traits generated by `#[account(...)]` dispatch every call between the
292/// transaction's active account and a foreign account reached through FPI. They read the binding
293/// target through this trait — a supertrait of each generated component trait — so the dispatch
294/// works without access to the wrapper's private `foreign_account_id` field.
295///
296/// This is an internal dispatch hook implemented by the `#[account(...)]` macro; it is not meant to
297/// be implemented or called directly.
298#[doc(hidden)]
299pub trait AccountBinding {
300    /// Returns `Some(id)` when the wrapper targets a foreign account reached through FPI, or `None`
301    /// when it targets the transaction's active account.
302    fn foreign_account_id(&self) -> Option<AccountId>;
303}