Assets, Vault & Faucet
Assets are now represented as two words (ASSET_KEY + ASSET_VALUE) instead of a single ASSET word. This is the largest MASM-level change in v0.14 and affects every procedure that creates, inspects, adds, removes, or burns assets.
ASSET to ASSET_KEY + ASSET_VALUE
Summary
The single 4-felt ASSET word has been split into two words:
ASSET_KEY=[asset_id_suffix, asset_id_prefix, (faucet_id_suffix << 8) | callbacks_enabled, faucet_id_prefix]ASSET_VALUE=[amount, 0, 0, 0]for fungible assets, orDATA_HASHfor non-fungible assets.
Every kernel procedure and standard-library helper that previously accepted or returned ASSET now works with the ASSET_KEY, ASSET_VALUE pair.
Affected Code
MASM (native_account::add_asset):
# Before (0.13): stack = [ASSET, pad(12)]
exec.native_account::add_asset
# -> [ASSET, pad(12)]
# After (0.14): stack = [ASSET_KEY, ASSET_VALUE, pad(8)]
exec.native_account::add_asset
# -> [ASSET_KEY, ASSET_VALUE, pad(8)]
Rust:
// Before (0.13)
let word: Word = fungible_asset.into();
// After (0.14)
let key: Word = fungible_asset.to_key_word();
let value: Word = fungible_asset.to_value_word();
// Reconstructing from key/value
let asset = FungibleAsset::from_key_value_words(key, value)?;
Migration Steps
- Find every MASM site that pushes an
ASSETword onto the stack before a kernel call. Replace the single word withASSET_KEY, ASSET_VALUEand adjust padding from 12 to 8. - In Rust, replace
.into()conversions toWordwith.to_key_word()and.to_value_word(). - Replace any
Asset::from(word)withAsset::from_key_value_words(key, value). - Update stack comments throughout your MASM to reflect the new two-word layout.
Common Errors
| Error Message | Cause | Solution |
|---|---|---|
FailedAssertion at add_asset / remove_asset | Single ASSET word pushed instead of key+value pair | Split into ASSET_KEY and ASSET_VALUE. |
no method named into found for FungibleAsset (when targeting Word) | Direct Word conversion removed | Use to_key_word() and to_value_word(). |
| Stack underflow in asset procedures | Padding not adjusted from 12 to 8 | Reduce padding to account for the extra word. |
build_asset Renamed to create_asset
Summary
The asset::build_fungible_asset and asset::build_non_fungible_asset procedures have been renamed to create_fungible_asset and create_non_fungible_asset. They also accept a new enable_callbacks flag and return the two-word ASSET_KEY, ASSET_VALUE pair.
Affected Code
MASM (fungible asset creation):
# Before (0.13): stack = [faucet_id_prefix, faucet_id_suffix, amount, ...]
exec.asset::build_fungible_asset
# -> [ASSET, ...]
# After (0.14): stack = [enable_callbacks, faucet_id_suffix, faucet_id_prefix, amount, ...]
exec.asset::create_fungible_asset
# -> [ASSET_KEY, ASSET_VALUE, ...]
Rust:
// Before (0.13)
let asset = FungibleAsset::new(faucet_id, amount)?;
// After (0.14) — Rust API may vary; consult crate docs for exact constructor
let asset = FungibleAsset::new(faucet_id, amount)?;
// The MASM-level rename is the primary change; Rust constructors
// now produce assets compatible with the two-word representation.
Migration Steps
- Rename all
exec.asset::build_fungible_assetcalls toexec.asset::create_fungible_asset. - Rename all
exec.asset::build_non_fungible_assetcalls toexec.asset::create_non_fungible_asset. - Add the
enable_callbacksflag as the new top-of-stack element. - Note the changed argument order:
[enable_callbacks, faucet_id_suffix, faucet_id_prefix, amount]. - Update consumers to expect
[ASSET_KEY, ASSET_VALUE]on the stack instead of a single[ASSET].
Common Errors
| Error Message | Cause | Solution |
|---|---|---|
unknown procedure asset::build_fungible_asset | Procedure renamed | Use asset::create_fungible_asset. |
unknown procedure asset::build_non_fungible_asset | Procedure renamed | Use asset::create_non_fungible_asset. |
FailedAssertion in create_fungible_asset | Missing enable_callbacks flag or wrong argument order | Push [enable_callbacks, faucet_id_suffix, faucet_id_prefix, amount]. |
get_balance / has_non_fungible_asset Removed
Summary
The kernel no longer exposes get_balance or has_non_fungible_asset. Instead, a single get_asset procedure handles both fungible and non-fungible lookups. It takes an ASSET_KEY and returns the corresponding ASSET_VALUE.
Affected Code
MASM (fungible balance check):
# Before (0.13): stack = [faucet_id, ...]
exec.native_account::get_balance
# -> [balance, ...]
# After (0.14): stack = [ASSET_KEY, pad(12)]
exec.native_account::get_asset
# -> [ASSET_VALUE, pad(12)]
# balance is ASSET_VALUE[0] (top of ASSET_VALUE word)
MASM (non-fungible existence check):
# Before (0.13): stack = [ASSET, pad(12)]
exec.native_account::has_non_fungible_asset
# -> [has_asset, pad(15)]
# After (0.14): stack = [ASSET_KEY, pad(12)]
exec.native_account::get_asset
# -> [ASSET_VALUE, pad(12)]
# If the asset exists, ASSET_VALUE will be the DATA_HASH;
# if not, ASSET_VALUE will be [0, 0, 0, 0].
Rust:
// Before (0.13)
let balance = account.vault().get_balance(faucet_id)?;
let has_nft = account.vault().has_non_fungible_asset(&asset)?;
// After (0.14)
let asset_value = account.vault().get_asset(asset_key)?;
// For fungible: amount = asset_value[0]
// For non-fungible: check if asset_value != [0, 0, 0, 0]
Migration Steps
- Replace every
exec.native_account::get_balancewithexec.native_account::get_asset. Construct theASSET_KEYfor the fungible faucet and read the amount from the first element of the returnedASSET_VALUE. - Replace every
exec.native_account::has_non_fungible_assetwithexec.native_account::get_asset. Construct theASSET_KEYand compare the returnedASSET_VALUEagainst[0, 0, 0, 0]to determine existence. - The same pattern applies to
get_initial_asset(for checking assets at transaction start).
Common Errors
| Error Message | Cause | Solution |
|---|---|---|
unknown procedure native_account::get_balance | Procedure removed | Use native_account::get_asset with the asset key. |
unknown procedure native_account::has_non_fungible_asset | Procedure removed | Use native_account::get_asset and check for zero value. |
| Wrong balance value | Reading wrong element from ASSET_VALUE | The amount is in ASSET_VALUE[0] (top of stack after the call). |
AssetVault::remove_asset Returns Remaining Asset
Summary
In Rust, AssetVault::remove_asset previously returned Result<Asset> (the removed asset). It now returns Result<Option<Asset>> where the value is the remaining asset in the vault after partial removal. For non-fungible assets, the return is always None (the entire asset is removed).
Affected Code
Rust:
// Before (0.13)
let removed: Asset = vault.remove_asset(asset)?;
// After (0.14)
let remaining: Option<Asset> = vault.remove_asset(asset)?;
// remaining = Some(fungible_asset) if fungible with leftover balance
// remaining = None if the vault entry was fully consumed (or non-fungible)
Migration Steps
- Update all call sites of
AssetVault::remove_assetto handleOption<Asset>instead ofAsset. - If you previously used the return value as "the asset that was removed", note that the semantics have changed to "the asset remaining in the vault".
- For non-fungible assets, expect
None— the asset is either fully present or fully removed.
Common Errors
| Error Message | Cause | Solution |
|---|---|---|
expected Asset, found Option<Asset> | Return type changed | Unwrap or pattern-match the Option. |
| Logic error: treating return as "removed" amount | Semantics changed from removed to remaining | Adjust logic to interpret the value as remaining balance. |
faucet::burn and native_account::remove_asset Stack Effects
Summary
Both faucet::burn and native_account::remove_asset have updated stack effects to match the two-word asset representation. Notably, faucet::burn no longer returns the asset on the stack.
Affected Code
MASM (faucet::burn):
# Before (0.13): stack = [ASSET, ...] -> [ASSET, ...]
exec.faucet::burn
# After (0.14): stack = [ASSET_KEY, ASSET_VALUE, ...] -> [...]
exec.faucet::burn
# Stack is consumed — nothing is returned for the burned asset.
MASM (native_account::remove_asset):
# Before (0.13): stack = [ASSET, pad(12)] -> [ASSET, pad(12)]
exec.native_account::remove_asset
# After (0.14): stack = [ASSET_KEY, ASSET_VALUE, pad(8)] -> [REMAINING_ASSET_VALUE, pad(12)]
exec.native_account::remove_asset
# Returns the REMAINING asset value in the vault (not the removed one).
Migration Steps
- For
faucet::burn: remove any code that reads the return value from the stack. The procedure now consumes[ASSET_KEY, ASSET_VALUE]and leaves nothing. - For
native_account::remove_asset: update stack expectations. The output is[REMAINING_ASSET_VALUE, pad(12)], not the removed asset. - If you need the removed amount, compute it before calling
remove_asset(e.g., subtract the remaining value from the original).
Common Errors
| Error Message | Cause | Solution |
|---|---|---|
Stack underflow after faucet::burn | Code tries to read a return value that no longer exists | burn now returns nothing; remove post-call reads. |
Wrong amount after remove_asset | Return value is remaining, not removed | Compute removed amount separately if needed. |
FailedAssertion in burn or remove_asset | Single ASSET word passed instead of key+value | Pass [ASSET_KEY, ASSET_VALUE] with correct padding. |
TokenSymbol Changes
Summary
The TokenSymbol type has several breaking changes:
to_string()is now available via theDisplaytrait (infallible). Previously it could fail.default()has been removed — there is no zero-value token symbol.TryFrom<Felt>now rejects values belowMIN_ENCODED_VALUE.MAX_SYMBOL_LENGTHincreased from 6 to 12 characters.
Affected Code
Rust:
// Before (0.13)
let symbol = TokenSymbol::default(); // zero-value placeholder
let s = symbol.to_string()?; // fallible conversion
let sym = TokenSymbol::try_from(felt)?; // accepted any felt
// After (0.14)
// TokenSymbol::default() is removed — use a real symbol
let s = format!("{}", symbol); // Display trait, infallible
let sym = TokenSymbol::try_from(felt)?; // rejects below MIN_ENCODED_VALUE
// Symbols can now be up to 12 characters (was 6)
Migration Steps
- Remove any calls to
TokenSymbol::default(). Replace with an explicit symbol viaTokenSymbol::new("TOKEN")or equivalent constructor. - Replace fallible
to_string()calls withformat!("{}", symbol)or.to_string()(now infallible viaDisplay). - If you validate token symbol length, update the upper bound from 6 to 12.
- If you construct
TokenSymbolfrom aFelt, ensure the value is at or aboveMIN_ENCODED_VALUE.
Common Errors
| Error Message | Cause | Solution |
|---|---|---|
no function or associated item named default found for TokenSymbol | default() removed | Use an explicit symbol value. |
encoded value below minimum / InvalidTokenSymbol | TryFrom<Felt> now rejects small values | Ensure the felt is at or above MIN_ENCODED_VALUE. |
Compilation warning about unused Result on to_string() | Now returns String directly via Display | Remove error handling around to_string(). |