Skip to content

feat: adapt the layout of Assets to the double word representation#2437

Open
PhilippGackstatter wants to merge 39 commits intopgackst-user-asset-key-valuefrom
pgackst-asset-layout
Open

feat: adapt the layout of Assets to the double word representation#2437
PhilippGackstatter wants to merge 39 commits intopgackst-user-asset-key-valuefrom
pgackst-asset-layout

Conversation

@PhilippGackstatter
Copy link
Contributor

@PhilippGackstatter PhilippGackstatter commented Feb 12, 2026

Refactors the layout of fungible and non-fungible assets. The main benefit for now is that non-fungible assets include the full account ID. The other good news is that this PR removes the last unsafe code from miden base 😅.

Layout Changes

For direct comparison, the previous layout was:

  • Fungible asset value: [amount, 0, faucet_id_suffix, faucet_id_prefix].
  • Fungible asset key: [0, 0, faucet_id_suffix, faucet_id_prefix].
  • Non-fungible asset value: [hash0, hash1, hash2, faucet_id_prefix].
  • Non-fungible asset key: [faucet_id_prefix, hash1, hash2, hash0'].

The new layout is:

  • Fungible asset value: [amount, 0, 0, 0].
  • Fungible asset key: [0, 0, faucet_id_suffix, faucet_id_prefix].
  • Non-fungible asset value: [hash0, hash1, hash2, hash3].
  • Non-fungible asset key: [hash0, hash1, faucet_id_suffix, faucet_id_prefix].

The most notable change is that non-fungible assets now contain the full AccountId instead of just the AccountIdPrefix. I believe this removes the last reason we had that account ID prefixes needed to be unique in the account tree. So, we could now consider lifting this restriction.

Account Delta

The account delta is impacted by the layout change, namely that non-fungible asset's were previously committed to by hashing their value. Because the value doesn't contain the faucet ID anymore, the delta also doesn't commit to the asset's issuer anymore and so the delta format needed to be changed to commit to the faucet ID. This means the asset key of the non-fungible asset is now included.

For security, the faucet ID prefix (specifically the bit in the account ID that determines the faucet type) must be at the same position in the layout to avoid introducing an ambiguity in the delta format. So, the layout of the fungible asset's delta elements was adapted as well. Overall it is now:

Fungible Assets

  • [domain = 1, was_added, faucet_id_suffix, faucet_id_prefix]
  • [amount_delta, 0, 0, 0]

Non-Fungible Assets

  • [domain = 1, was_added, faucet_id_suffix, faucet_id_prefix]
  • [hash0, hash1, hash2, hash3] (= ASSET_VALUE)

See docs of AccountDelta::to_commitment for all the details.

This change included updates to the delta commitment computation as well as how non-fungible assets are tracked in the delta.

Note that the NonFungibleAssetDelta's internal representation is a bit ugly, but a larger refactors doesn't make sense at this point since this may change more fundamentally when generalizing assets.

Asset Key Ordering

AssetVaultKey implements Ord and PartialOrd based on LexicographicWord for use in the delta. Not strictly necessary, but convenient. I also added implementations for Asset that delegate to AssetVaultKey, but these are currently unused.

Asset Modules

This PR commits further to the fungible_asset and now non_fungible_asset module in the kernel for implementing their respective logic. If we move this logic elsewhere later, this should make this process easier.

Transaction Outputs

Since the fee asset is a fungible asset, and it is represented as a double word, the FEE_ASSET_VALUE tx output needed to be adapted, as it would now only contain the amount, but not the faucet ID. The new approach is to output the individual required elements from the fungible asset, i.e. its faucet ID limbs and the amount. This also happens to make room for a full word on the output stack.

Tests

Fixes a couple of tests where asset key and value were incorrectly ordered but the test didn't fail before, presumably due to the similar layout of key and value.

Migration

  • miden::protocol::active_account::has_non_fungible_asset now takes an ASSET_KEY as an input.
  • miden::protocol::asset::create_non_fungible_asset now takes the full account ID as an input.
  • The previous asset to/from word conversions were removed, since an asset is now represented as a double word. The replacements are the to_key_word and to_value_word methods, and from_key_value and from_key_value_words constructors.
  • NonFungibleAssetDelta::new's signature has changed.
  • FungibleAsset::new and Asset::is_(non_)fungible are no longer const (I'm not sure these can realistically be used in a const context and it restricts future non-breaking internal changes).
  • {Asset, NonFungibleAsset, FungibleAsset}::faucet_id_prefix was removed.
  • NonFungibleAsset's and NonFungibleAssetDetails' structure has changed. They both contain the full AccountId now.
  • AssetVaultKey::{new_unchecked, faucet_id_prefix, as_word} were removed. Use new, faucet_id and to_word instead.
  • AssetVaultKey::from_account_id renamed to new_fungible since non-fungible asset vault keys cannot be created from just a faucet ID.

Follow-Up

  • We should come up with a different name for "native asset ID" (= the faucet ID of the "fee asset"), since AssetId now is its own thing.
  • Fungible asset and non-fungible asset's display impl should be adapted at some point. It currently delegates to the Debug implementation which is not a stable representation (could change with non-breaking changes) and it also shouldn't be used for error messages.
  • The asset vault key must be hashed before using it as the key in the asset vault SMT (reason).

closes #2328

@PhilippGackstatter PhilippGackstatter linked an issue Feb 12, 2026 that may be closed by this pull request
@igamigo igamigo added the pr-from-maintainers PRs that come from internal contributors or integration partners. They should be given priority label Feb 12, 2026
/// # Fungible assets
///
/// - A fungible asset's data layout is: `[amount, 0, faucet_id_suffix, faucet_id_prefix]`.
/// - A fungible asset's value layout is: `[amount, 0, 0, 0]`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
/// - A fungible asset's value layout is: `[amount, 0, 0, 0]`.
/// - A fungible asset's value layout is: `[amount, 0, 0, 0]`.

Comment on lines +209 to 213
impl Ord for Asset {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.vault_key().cmp(&other.vault_key())
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this fine? A fungible pair ofAsset can be != since it's compared by value (it derives Eq and PartialEq) but it would evaluate to Ordering::Equal becuase it's based on the asset's vault key, which I think is not desired since Eq and Ord are expected to be consistent. Maybe the amount should break the tie in the case of fungible assets? Although not sure what the expected use of this is; maybe documenting it better is enough.

/// removed. If the final amount of the asset is zero, the asset is removed from the vault.
///
/// # Errors
/// - The asset is not found in the vault.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not seem to be the case with the latest changes. Should it be? It might be better in order to have more precise error messages.

@@ -108,57 +114,33 @@ impl NonFungibleAsset {
/// asset and a fungible asset, as the former's vault key always has the fungible bit set to `0`
/// and the latter's vault key always has the bit set to `1`.
pub fn vault_key(&self) -> AssetVaultKey {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this might require new docs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-from-maintainers PRs that come from internal contributors or integration partners. They should be given priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expand asset layout from one to two words

2 participants