Skip to main content

miden_base_sys/bindings/
active_account.rs

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