Skip to content

Conversation

@thesimplekid
Copy link
Collaborator

@thesimplekid thesimplekid commented Dec 28, 2025

Description


The Cashu protocol supports multiple currency units (Sat, Msat, Usd, Eur, etc.), but the previous Amount type was a simple u64 wrapper with no awareness of units. This created a subtle but dangerous class of bugs: nothing prevented code from accidentally adding 1000 satoshis to 500 millisatoshis, producing a nonsensical result of 1500 in an undefined unit. These bugs are especially insidious because the code compiles and runs without error—the incorrect math only manifests as wrong balances or failed payments in production.

This change makes unit mismatches impossible by encoding the currency unit into the type system. Amount now carries its unit at the type level, and arithmetic operations verify unit compatibility before proceeding. The compiler catches many mistakes statically, and runtime checks catch the rest with a clear UnitMismatch error rather than silent corruption.

The refactor maintains backwards compatibility by using Amount<()> (untyped) at serialization boundaries where the wire protocol expects a plain integer, while internal mint logic now uses Amount to get the safety guarantees. The with_unit() method provides a clear conversion point at the boundary between protocol parsing and application logic, making it explicit where unit context is being added.

This is particularly important for the mint's quote handling, where amounts flow between payment backends (which may use different units internally) and the core mint logic. By making MintQuote.amount_paid, MeltQuote.fee_reserve, and payment response types carry their units, we ensure that fee calculations, balance checks, and unit conversions are always performed correctly.

closes: #1463

Notes to the reviewers


Suggested CHANGELOG Updates

CHANGED

ADDED

REMOVED

FIXED


Checklist

@thesimplekid thesimplekid changed the title lGeneric unit on amount feat: Generic unit on amount Dec 28, 2025
@thesimplekid thesimplekid added this to CDK Dec 28, 2025
@thesimplekid thesimplekid moved this to In progress in CDK Dec 28, 2025
@thesimplekid thesimplekid force-pushed the generic_unit_on_amount branch 2 times, most recently from b74f425 to 61278d2 Compare December 29, 2025 09:29
@thesimplekid thesimplekid added this to the 0.15.0 milestone Dec 29, 2025
@thesimplekid thesimplekid force-pushed the generic_unit_on_amount branch 2 times, most recently from 948a5fa to 13faadb Compare December 29, 2025 10:27
@thesimplekid thesimplekid marked this pull request as ready for review December 29, 2025 10:36
@thesimplekid thesimplekid force-pushed the generic_unit_on_amount branch from bd212c5 to 4218b3f Compare December 29, 2025 21:52
crodas
crodas previously approved these changes Dec 29, 2025
The Cashu protocol supports multiple currency units (Sat, Msat, Usd, Eur, etc.), but the previous Amount type was a simple u64 wrapper with no awareness of units. This created a subtle but dangerous class of bugs: nothing prevented code from accidentally adding 1000 satoshis to 500 millisatoshis, producing a nonsensical result of 1500 in an undefined unit. These bugs are especially insidious because the code compiles and runs without error—the incorrect math only manifests as wrong balances or failed payments in production.

This change makes unit mismatches impossible by encoding the currency unit into the type system. Amount<CurrencyUnit> now carries its unit at the type level, and arithmetic operations verify unit compatibility before proceeding. The compiler catches many mistakes statically, and runtime checks catch the rest with a clear UnitMismatch error rather than silent corruption.

The refactor maintains backwards compatibility by using Amount<()> (untyped) at serialization boundaries where the wire protocol expects a plain integer, while internal mint logic now uses Amount<CurrencyUnit> to get the safety guarantees. The with_unit() method provides a clear conversion point at the boundary between protocol parsing and application logic, making it explicit where unit context is being added.

This is particularly important for the mint's quote handling, where amounts flow between payment backends (which may use different units internally) and the core mint logic. By making MintQuote.amount_paid, MeltQuote.fee_reserve, and payment response types carry their units, we ensure that fee calculations, balance checks, and unit conversions are always performed correctly.
@thesimplekid thesimplekid force-pushed the generic_unit_on_amount branch from 641dbcc to 6a7e395 Compare December 29, 2025 22:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

Add currency unit to the Amount type

3 participants