Skip to content

feat: introduce AssetAmount wrapper type#2658

Open
giwaov wants to merge 1 commit into0xMiden:nextfrom
giwaov:feat/asset-amount-wrapper-type
Open

feat: introduce AssetAmount wrapper type#2658
giwaov wants to merge 1 commit into0xMiden:nextfrom
giwaov:feat/asset-amount-wrapper-type

Conversation

@giwaov
Copy link
Copy Markdown

@giwaov giwaov commented Mar 22, 2026

Summary

Introduces a new AssetAmount newtype wrapper over u64 that enforces the MAX = 2^63 - 2^31 invariant at construction time, as described in #2532.

Motivation

Currently, FungibleAsset stores its amount as a raw u64 and validates the range only during construction. This means any internal code that manipulates the amount directly could accidentally create invalid values. By introducing AssetAmount as a validated wrapper type, the type system enforces correctness at all construction points.

Changes

New type: AssetAmount (crates/miden-protocol/src/asset/asset_amount.rs)

  • Newtype AssetAmount(u64) with MAX and ZERO constants
  • Validated constructor new(u64) -> Result<Self, AssetError>
  • inner() -> u64 accessor for when the raw value is needed
  • new_unchecked(u64) (crate-visible) for cases where validity is already guaranteed (e.g., subtraction of two valid amounts)
  • From<u8>, From<u16>, From<u32> (infallible, always in range)
  • TryFrom<u64> and From<AssetAmount> for u64
  • Display, Serializable, Deserializable
  • Derives: Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash
  • Comprehensive test suite (9 unit tests)

Integration into FungibleAsset

  • Field: amount: u64 -> amount: AssetAmount
  • amount(): now returns AssetAmount instead of u64
  • new(): still accepts u64 for ergonomic construction, validates internally via AssetAmount::new()
  • MAX_AMOUNT: retained as pub const MAX_AMOUNT: u64 for backward compatibility, delegates to AssetAmount::MAX.inner()
  • add()/sub(): operate on inner values, construct validated AssetAmount for results

Updated callers

All call sites across 3 crates updated to use .inner() where a raw u64 is needed:

  • miden-protocol: delta/vault.rs, vault/mod.rs, kernel/mod.rs
  • miden-tx: exec_host.rs, mod.rs
  • miden-testing: test files across test_account.rs, test_account_delta.rs, test_epilogue.rs, test_fee.rs, bridge_in.rs, multisig.rs, multisig_psm.rs, hybrid_multisig.rs, faucet.rs, fee.rs, p2id.rs

Design Decisions

  1. Name: AssetAmount per @bobbinth's suggestion in Introduce wrapper type for asset amounts #2532 (concise, since it's only used for fungible assets)
  2. FungibleAsset::new() signature unchanged: Keeps u64 parameter to avoid breaking all callers validates internally
  3. MAX_AMOUNT retained: Backward-compatible u64 constant for existing comparisons
  4. new_unchecked is pub(crate): Needed internally (e.g., subtraction results are guaranteed valid) but not exposed publicly

Closes #2532

Introduces a new AssetAmount newtype that wraps u64 and enforces
the MAX = 2^63 - 2^31 invariant at construction time, closing the
gap where invalid amounts could be created via direct u64 manipulation.

Key changes:
- Add AssetAmount with validated new(), From<u8/u16/u32>, TryFrom<u64>
- Update FungibleAsset::amount() to return AssetAmount instead of u64
- Keep FungibleAsset::new() accepting u64 for ergonomic construction
- Retain MAX_AMOUNT constant for backward compatibility
- Update all callers across miden-protocol, miden-tx, and miden-testing

Closes 0xMiden#2532
@giwaov giwaov force-pushed the feat/asset-amount-wrapper-type branch from 7afa99c to 5fed54c Compare March 23, 2026 09:57
@giwaov
Copy link
Copy Markdown
Author

giwaov commented Mar 27, 2026

Hi @bobbinth just checking in. All CI checks are passing. Happy to address any feedback. Thanks!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Introduce wrapper type for asset amounts

1 participant