use {ACCOUNT_ADD_ASSET_OFFSET, ACCOUNT_COMPUTE_DELTA_COMMITMENT_OFFSET, ACCOUNT_GET_ID_OFFSET, ACCOUNT_GET_INITIAL_ASSET_OFFSET, ACCOUNT_GET_INITIAL_COMMITMENT_OFFSET, ACCOUNT_GET_INITIAL_ITEM_OFFSET, ACCOUNT_GET_INITIAL_MAP_ITEM_OFFSET, ACCOUNT_GET_INITIAL_STORAGE_COMMITMENT_OFFSET, ACCOUNT_GET_INITIAL_VAULT_ROOT_OFFSET, ACCOUNT_INCR_NONCE_OFFSET, ACCOUNT_REMOVE_ASSET_OFFSET, ACCOUNT_SET_ITEM_OFFSET, ACCOUNT_SET_MAP_ITEM_OFFSET, ACCOUNT_UPGRADE_OFFSET, ACCOUNT_WAS_PROCEDURE_CALLED_OFFSET}
from miden::protocol::kernel_proc_offsets
use miden::core::word
use {AccountId, AccountProcedureRoot, Asset, AssetId, AssetValue, Bool, StorageMapKey, StorageSlotId}
from miden::protocol::types
# NATIVE ACCOUNT PROCEDURES
# =================================================================================================
# ID AND NONCE
# -------------------------------------------------------------------------------------------------
#! Returns the ID of the native account of the transaction.
#!
#! Inputs: []
#! Outputs: [account_id_suffix, account_id_prefix]
#!
#! Where:
#! - account_id_{suffix,prefix} are the suffix and prefix felts of the native account ID of the
#! transaction.
#!
#! Invocation: exec
pub proc get_id() -> AccountId
# pad the stack
padw padw padw push.0.0
# => [pad(14)]
# push the flag indicating that the ID of the native account was requested
push.1
# => [is_native = 1, pad(14)]
push.ACCOUNT_GET_ID_OFFSET
# => [offset, is_native = 1, pad(14)]
syscall.exec_kernel_proc
# => [account_id_suffix, account_id_prefix, pad(14)]
# clean the stack
swapdw dropw dropw swapw dropw movdn.3 movdn.3 drop drop
# => [account_id_suffix, account_id_prefix]
end
#! Increments the nonce of the native account by one and returns the new nonce.
#!
#! Inputs: []
#! Outputs: [final_nonce]
#!
#! Where:
#! - final_nonce is the new nonce of the account. Since it cannot be incremented again, this will
#! also be the final nonce of the account after transaction execution.
#!
#! Panics if:
#! - the invocation of this procedure does not originate from the native account.
#! - the invocation of this procedure does not originate from the authentication procedure
#! of the account.
#! - the nonce has already been incremented.
#!
#! Invocation: exec
pub proc incr_nonce() -> felt
# pad the stack
padw padw padw push.0.0.0
# => [pad(15)]
push.ACCOUNT_INCR_NONCE_OFFSET
# => [offset, pad(15)]
syscall.exec_kernel_proc
# => [final_nonce, pad(15)]
swap.15 dropw dropw dropw drop drop drop
# => [final_nonce]
end
# COMMITMENTS
# -------------------------------------------------------------------------------------------------
#! Computes the commitment to the native account's delta.
#!
#! This procedure must be invoked from the account context. Additionally, if the account state has
#! changed, the nonce must be incremented before it is called, otherwise it will panic; since only
#! auth procedures are allowed to increment the nonce, a non-empty delta can only be computed from
#! the auth procedure.
#!
#! The commitment to an empty delta is defined as the empty word.
#!
#! During an account-creating transaction (when the initial nonce is 0), this procedure will not
#! return the empty word even if the initial storage commitment and the current storage commitment
#! are identical (storage hasn't changed). This is because the delta for a new account must
#! represent its entire newly created state, and the initial storage in a transaction is initialized
#! to the storage that the account ID commits to, which may be non-empty. This does not have any
#! consequences other than being inconsistent in this edge case.
#!
#! Inputs: []
#! Outputs: [DELTA_COMMITMENT]
#!
#! Where:
#! - DELTA_COMMITMENT is the commitment to the account delta.
#!
#! Panics if:
#! - the invocation of this procedure does not originate from the native account.
#! - the invocation of this procedure does not originate from the account context.
#! - the vault or storage patch is not empty but the nonce increment is zero.
pub proc compute_delta_commitment() -> word
# pad the stack
padw padw padw push.0.0.0
# => [pad(15)]
push.ACCOUNT_COMPUTE_DELTA_COMMITMENT_OFFSET
# => [offset, pad(15)]
syscall.exec_kernel_proc
# => [DELTA_COMMITMENT, pad(12)]
# clean the stack
swapdw dropw dropw swapw dropw
# => [DELTA_COMMITMENT]
end
#! Records the commitments describing an upgrade of the native account's code and storage.
#!
#! This procedure is currently a no-op beyond storing the two commitments in kernel memory; the
#! actual application of the upgrade is not yet implemented, and the commitment formats are not yet
#! defined.
#!
#! Inputs: [CODE_UPGRADE_COMMITMENT, STORAGE_UPGRADE_COMMITMENT]
#! Outputs: []
#!
#! Where:
#! - CODE_UPGRADE_COMMITMENT is the commitment to the account code upgrade.
#! - STORAGE_UPGRADE_COMMITMENT is the commitment to the account storage upgrade.
#!
#! Panics if:
#! - the invocation of this procedure does not originate from the native account.
#!
#! Invocation: exec
pub proc upgrade(code_upgrade_commitment: word, storage_upgrade_commitment: word)
# pad the stack
padw push.0.0.0 push.ACCOUNT_UPGRADE_OFFSET
swapdw
# => [CODE_UPGRADE_COMMITMENT, STORAGE_UPGRADE_COMMITMENT, offset, pad(7)]
movup.8
# => [offset, CODE_UPGRADE_COMMITMENT, STORAGE_UPGRADE_COMMITMENT, pad(7)]
syscall.exec_kernel_proc
# => [pad(16)]
# clean the stack
dropw dropw dropw dropw
end
#! Returns the commitment of the native account at the beginning of the transaction.
#!
#! Inputs: []
#! Outputs: [INIT_COMMITMENT]
#!
#! Where:
#! - INIT_COMMITMENT is the initial account commitment.
#!
#! Panics if:
#! - the invocation of this procedure does not originate from the native account.
#!
#! Invocation: exec
pub proc get_initial_commitment() -> word
# pad the stack
padw padw padw push.0.0.0
# => [pad(15)]
push.ACCOUNT_GET_INITIAL_COMMITMENT_OFFSET
# => [offset, pad(15)]
syscall.exec_kernel_proc
# => [INIT_COMMITMENT, pad(12)]
# clean the stack
swapdw dropw dropw swapw dropw
# => [INIT_COMMITMENT]
end
#! Returns the storage commitment of the native account at the beginning of the transaction.
#!
#! During an account-creating transaction (when the initial nonce is 0), this procedure and
#! active_account::compute_storage_commitment will return the same value at the beginning of the
#! transaction (before any note or transaction scripts were executed). Despite that, the account
#! delta may not be empty. See compute_delta_commitment for more.
#!
#! Inputs: []
#! Outputs: [INIT_STORAGE_COMMITMENT]
#!
#! Where:
#! - INIT_STORAGE_COMMITMENT is the initial account storage commitment.
#!
#! Panics if:
#! - the invocation of this procedure does not originate from the native account.
#!
#! Invocation: exec
pub proc get_initial_storage_commitment() -> word
# pad the stack
padw padw padw push.0.0.0
# => [pad(15)]
push.ACCOUNT_GET_INITIAL_STORAGE_COMMITMENT_OFFSET
# => [offset, pad(15)]
syscall.exec_kernel_proc
# => [INIT_STORAGE_COMMITMENT, pad(12)]
# clean the stack
swapdw dropw dropw swapw dropw
# => [INIT_STORAGE_COMMITMENT]
end
#! Returns the vault root of the native account at the beginning of the transaction.
#!
#! Inputs: []
#! Outputs: [INIT_VAULT_ROOT]
#!
#! Where:
#! - INIT_VAULT_ROOT is the initial account vault root.
#!
#! Panics if:
#! - the invocation of this procedure does not originate from the native account.
#!
#! Invocation: exec
pub proc get_initial_vault_root() -> word
# pad the stack
padw padw padw push.0.0.0
# => [pad(15)]
push.ACCOUNT_GET_INITIAL_VAULT_ROOT_OFFSET
# => [offset, pad(15)]
syscall.exec_kernel_proc
# => [INIT_VAULT_ROOT, pad(12)]
# clean the stack
swapdw dropw dropw swapw dropw
# => [INIT_VAULT_ROOT]
end
# STORAGE
# -------------------------------------------------------------------------------------------------
#! Sets an item in the native account storage.
#!
#! Inputs: [slot_id_suffix, slot_id_prefix, VALUE]
#! Outputs: [OLD_VALUE]
#!
#! Where:
#! - slot_id_{suffix, prefix} are the suffix and prefix felts of the slot identifier, which are
#! the first two felts of the hashed slot name.
#! - VALUE is the value to set.
#! - OLD_VALUE is the previous value of the item.
#!
#! Panics if:
#! - a slot with the provided slot ID does not exist in account storage.
#! - the invocation of this procedure does not originate from the native account.
#!
#! Invocation: exec
pub proc set_item(slot_id: StorageSlotId, value: word) -> word
push.ACCOUNT_SET_ITEM_OFFSET
# => [offset, slot_id_suffix, slot_id_prefix, VALUE]
# pad the stack
push.0 movdn.7 padw padw swapdw
# => [offset, slot_id_suffix, slot_id_prefix, VALUE, pad(9)]
syscall.exec_kernel_proc
# => [OLD_VALUE, pad(12)]
# clean the stack
swapw.3 dropw dropw dropw
# => [OLD_VALUE]
end
#! Sets a map item in the native account storage.
#!
#! Inputs: [slot_id_suffix, slot_id_prefix, KEY, VALUE]
#! Outputs: [OLD_VALUE]
#!
#! Where:
#! - slot_id_{suffix, prefix} are the suffix and prefix felts of the slot identifier, which are
#! the first two felts of the hashed slot name.
#! - the slot must point to the root of the storage map.
#! - KEY is the key to set at VALUE.
#! - VALUE is the value to set at KEY.
#! - OLD_VALUE is the old value at KEY.
#!
#! Panics if:
#! - a slot with the provided slot ID does not exist in account storage.
#! - the requested storage slot type is not map.
#! - the procedure is called from a non-account context.
#! - the invocation of this procedure does not originate from the native account.
#!
#! Invocation: exec
pub proc set_map_item(slot_id: StorageSlotId, key: StorageMapKey, value: word) -> word
push.ACCOUNT_SET_MAP_ITEM_OFFSET
# => [offset, slot_id_suffix, slot_id_prefix, KEY, VALUE]
# pad the stack
push.0 padw
# => [pad(4), 0, offset, slot_id_suffix, slot_id_prefix, KEY, VALUE]
movdnw.3
# => [0, offset, slot_id_suffix, slot_id_prefix, KEY, VALUE, pad(4)]
movdn.11
# => [offset, slot_id_suffix, slot_id_prefix, KEY, VALUE, pad(5)]
syscall.exec_kernel_proc
# => [OLD_VALUE, pad(12)]
# drop pad(12)
movdnw.3 dropw dropw dropw
# => [OLD_VALUE]
end
#! Gets the initial item from the native account storage slot as it was at the beginning of the
#! transaction.
#!
#! Inputs: [slot_id_suffix, slot_id_prefix]
#! Outputs: [INIT_VALUE]
#!
#! Where:
#! - slot_id_{suffix, prefix} are the suffix and prefix felts of the slot identifier, which are
#! the first two felts of the hashed slot name.
#! - INIT_VALUE is the initial value of the item at the beginning of the transaction.
#!
#! Panics if:
#! - a slot with the provided slot ID does not exist in account storage.
#! - the invocation of this procedure does not originate from the native account.
#!
#! Invocation: exec
pub proc get_initial_item(slot_id: StorageSlotId) -> word
push.0 movdn.2
# => [slot_id_suffix, slot_id_prefix, 0]
push.ACCOUNT_GET_INITIAL_ITEM_OFFSET
# => [offset, slot_id_suffix, slot_id_prefix, 0]
# pad the stack
padw swapw padw padw swapdw
# => [offset, slot_id_suffix, slot_id_prefix, pad(13)]
syscall.exec_kernel_proc
# => [INIT_VALUE, pad(12)]
# clean the stack
swapdw dropw dropw swapw dropw
# => [INIT_VALUE]
end
#! Gets the initial VALUE from the native account storage map as it was at the beginning of the
#! transaction.
#!
#! Inputs: [slot_id_suffix, slot_id_prefix, KEY]
#! Outputs: [INIT_VALUE]
#!
#! Where:
#! - slot_id_{suffix, prefix} are the suffix and prefix felts of the slot identifier, which are
#! the first two felts of the hashed slot name.
#! - KEY is the key of the item to get.
#! - INIT_VALUE is the initial value of the item at the beginning of the transaction.
#!
#! Panics if:
#! - a slot with the provided slot ID does not exist in account storage.
#! - the slot item at index is not a map.
#! - the invocation of this procedure does not originate from the native account.
#!
#! Invocation: exec
pub proc get_initial_map_item(slot_id: StorageSlotId, key: StorageMapKey) -> word
push.ACCOUNT_GET_INITIAL_MAP_ITEM_OFFSET
# => [offset, slot_id_suffix, slot_id_prefix, KEY]
push.0 movdn.7 padw padw swapdw
# => [offset, slot_id_suffix, slot_id_prefix, KEY, pad(9)]
syscall.exec_kernel_proc
# => [INIT_VALUE, pad(12)]
# clean the stack
swapdw dropw dropw swapw dropw
# => [INIT_VALUE]
end
# VAULT
# -------------------------------------------------------------------------------------------------
#! Add the specified asset to the vault.
#!
#! Inputs: [ASSET_ID, ASSET_VALUE]
#! Outputs: [FINAL_ASSET_VALUE]
#!
#! Where:
#! - ASSET_ID is the asset ID of the asset that is added to the vault.
#! - ASSET_VALUE is the value of the asset to add to the vault.
#! - FINAL_ASSET_VALUE is the asset in the account vault after the operation, defined as follows:
#! - If ASSET_VALUE is a non-fungible asset, then FINAL_ASSET_VALUE is the same as ASSET_VALUE.
#! - If ASSET_VALUE is a fungible asset, then FINAL_ASSET_VALUE is the total fungible asset in the account vault
#! after ASSET_VALUE was added to it.
#!
#! Panics if:
#! - the asset is not valid.
#! - the total value of two fungible assets is greater than or equal to 2^63.
#! - the vault already contains the same non-fungible asset.
#!
#! Invocation: exec
pub proc add_asset(asset: Asset) -> AssetValue
# pad the stack
padw padw swapdw movup.8 drop
# => [ASSET_ID, ASSET_VALUE, pad(7)]
push.ACCOUNT_ADD_ASSET_OFFSET
# => [offset, ASSET_ID, ASSET_VALUE, pad(7)]
syscall.exec_kernel_proc
# => [FINAL_ASSET_VALUE, pad(12)]
# clean the stack
swapdw dropw dropw swapw dropw
# => [FINAL_ASSET_VALUE]
end
#! Remove the specified asset from the vault and return the remaining asset value.
#!
#! Inputs: [ASSET_ID, ASSET_VALUE]
#! Outputs: [FINAL_ASSET_VALUE]
#!
#! Where:
#! - ASSET_ID is the asset ID of the asset to remove from the vault.
#! - ASSET_VALUE is the value of the asset to remove from the vault.
#! - FINAL_ASSET_VALUE is the value of the asset remaining in the vault after removal which may
#! be the empty word if nothing remains (e.g. if a non-fungible asset is removed).
#!
#! Panics if:
#! - the fungible asset is not found in the vault.
#! - the amount of the fungible asset in the vault is less than the amount to be removed.
#! - the non-fungible asset is not found in the vault.
#!
#! Invocation: exec
pub proc remove_asset(asset: Asset) -> AssetValue
# pad the stack
padw padw swapdw movup.8 drop
# => [ASSET_ID, ASSET_VALUE, pad(7)]
push.ACCOUNT_REMOVE_ASSET_OFFSET
# => [offset, ASSET_ID, ASSET_VALUE, pad(7)]
syscall.exec_kernel_proc
# => [FINAL_ASSET_VALUE, pad(12)]
# clean the stack
swapdw dropw dropw swapw dropw
# => [FINAL_ASSET_VALUE]
end
#! Returns the asset associated with the provided asset ID in the native account's vault at
#! the beginning of the transaction.
#!
#! Inputs: [ASSET_ID]
#! Outputs: [ASSET_VALUE]
#!
#! Where:
#! - ASSET_ID is the asset ID of the asset to fetch.
#! - ASSET_VALUE is the value of the asset from the vault, which can be the EMPTY_WORD if it isn't
#! present.
#!
#! Panics if:
#! - the invocation of this procedure does not originate from the native account.
#!
#! Invocation: exec
pub proc get_initial_asset(asset_id: AssetId) -> AssetValue
push.ACCOUNT_GET_INITIAL_ASSET_OFFSET
# => [offset, ASSET_ID]
# pad the stack
push.0 movdn.5 push.0 movdn.5 push.0 movdn.5
padw padw swapdw
# => [offset, ASSET_ID, pad(11)]
syscall.exec_kernel_proc
# => [ASSET_VALUE, pad(12)]
# clean the stack
swapdw dropw dropw swapw dropw
# => [ASSET_VALUE]
end
#! Returns a boolean indicating whether the native account's vault contained an asset with the
#! provided asset ID at the beginning of the transaction.
#!
#! Inputs: [ASSET_ID]
#! Outputs: [has_asset]
#!
#! Where:
#! - ASSET_ID is the asset ID of the asset to check.
#! - has_asset is a boolean indicating whether the account vault had the asset.
#!
#! Panics if:
#! - the invocation of this procedure does not originate from the native account.
#!
#! Invocation: exec
pub proc has_initial_asset(asset_id: AssetId) -> Bool
exec.get_initial_asset
# => [ASSET_VALUE]
# compare with EMPTY_WORD to assess if the asset existed in the vault
exec.word::eqz not
# => [has_asset]
end
# CODE
# -------------------------------------------------------------------------------------------------
#! Returns 1 if a native account procedure was called during transaction execution, and 0 otherwise.
#!
#! Note: This returns 1 only if the procedure invoked account-restricted kernel APIs (e.g.,
#! `exec.faucet::mint`) which trigger `authenticate_and_track_procedure`. Procedures that execute
#! only local MASM instructions will return 0 even if they were executed.
#!
#! Inputs: [PROC_ROOT]
#! Outputs: [was_called]
#!
#! Where:
#! - PROC_ROOT is the hash of the procedure to check.
#! - was_called is 1 if the procedure was called, 0 otherwise.
#!
#! Panics if:
#! - the invocation of this procedure does not originate from the account context.
#!
#! Invocation: exec
pub proc was_procedure_called(proc_root: AccountProcedureRoot) -> Bool
push.ACCOUNT_WAS_PROCEDURE_CALLED_OFFSET
# => [offset, PROC_ROOT]
# pad the stack
push.0.0.0 movdn.7 movdn.7 movdn.7 padw padw swapdw
# => [offset, PROC_ROOT, pad(11)]
syscall.exec_kernel_proc
# => [was_called, pad(15)]
# clean the stack
swapw.3 dropw dropw dropw movdn.3 drop drop drop
# => [was_called]
end