Feature Request ποΈ
Propose a stable 1.0.0 release of org.accordproject.money, addressing three long-standing concerns: removal of digital currency types, correct handling of non-decimal currency denominations, and an optional precision-safe fixed-point representation.
Opening this for community discussion before any code changes land.
Use Case
The current model (org.accordproject.money@0.3.0) has a few limitations that surface in real contracts:
DigitalMonetaryAmount / DigitalCurrencyCode mix cryptocurrency concerns into the core money model. These belong in a separate, specialised namespace.
Double doubleValue is ambiguous across currencies with different minor-unit conventions β JPY (0 decimals), USD (2 decimals), KWD (3 decimals) all share the same field type but require different interpretation.
- No precision-safe option exists for contracts that need exact arithmetic (banking, settlement, regulated financial reporting). Floating-point rounding errors are unsuitable for these domains.
CurrencyCode enum should be refreshed against the latest ISO 4217 active list (e.g., VES for the Venezuelan BolΓvar Soberano).
Possible Solution
A dual-representation v1.0.0 model that:
- Removes
DigitalMonetaryAmount and DigitalCurrencyCode
- Keeps
MonetaryAmount (with doubleValue + currencyCode) backwards-compatible with v0.3.0
- Adds
FixedPointMonetaryAmount for precision-safe arithmetic
- Annotates each
CurrencyCode enum value with a @DecimalPlaces decorator carrying its ISO 4217 minor-unit count
- Refreshes
CurrencyCode against ISO 4217 as of 2026
Draft money@1.0.0.cto
concerto version "^3.0.0"
namespace org.accordproject.money@1.0.0
/**
* Declares the @DecimalPlaces decorator.
* Carries the ISO 4217 minor-unit count for each currency.
*/
declaration DecimalPlaces {
o Integer value range=[0,4]
}
/**
* ISO 4217 currency codes (active codes as of 2026), each annotated
* with its standard minor-unit count via @DecimalPlaces.
*
* 0 decimals: BIF, CLP, DJF, GNF, ISK, JPY, KMF, KRW, PYG, RWF,
* UGX, VND, VUV, XAF, XOF, XPF
* 2 decimals: most currencies (USD, EUR, GBP, AUD, CAD, β¦)
* 3 decimals: BHD, BOV, COU, IQD, JOD, KWD, LYD, OMR, TND, UYI,
* XAU, XAG, XPT, XPD, XBA, XBB, XBC, XBD
*/
enum CurrencyCode {
@DecimalPlaces(2) o AED
@DecimalPlaces(2) o AFN
// ... full ISO 4217 list ...
@DecimalPlaces(3) o BHD
@DecimalPlaces(0) o BIF
// ...
@DecimalPlaces(0) o JPY
// ...
@DecimalPlaces(3) o KWD
// ...
@DecimalPlaces(2) o USD
// ...
@DecimalPlaces(2) o VES // NEW: Venezuelan BolΓvar Soberano
@DecimalPlaces(2) o ZWL
}
/**
* Abstract base for monetary amounts. All representations share a currency code.
*/
abstract concept Amount {
o CurrencyCode currencyCode
}
/**
* Decimal-based monetary amount (v0.3.0 compatible).
*
* Use when: legacy contracts, display values, estimates where
* floating-point precision loss is acceptable.
*
* Example: { doubleValue: 10.50, currencyCode: "USD" }
*/
concept MonetaryAmount extends Amount {
o Double doubleValue
}
/**
* Fixed-point monetary amount (v1.0 precision-safe).
*
* Represents: value = mantissa Γ 10^(-scale)
*
* Use when: financial calculations requiring exact arithmetic,
* currencies with non-decimal denominations, audit trails,
* regulated reporting.
*
* The scale should match the currency's @DecimalPlaces decorator value.
*
* Examples:
* { mantissa: 1050, scale: 2, currencyCode: "USD" } = $10.50
* { mantissa: 10050, scale: 0, currencyCode: "JPY" } = Β₯10,050
* { mantissa: 100500, scale: 3, currencyCode: "KWD" } = 100.500 KWD
*/
concept FixedPointMonetaryAmount extends Amount {
o Long mantissa
o Integer scale default=2
}
/**
* Currency exchange rate (decimal).
*/
concept CurrencyConversion {
o CurrencyCode from
o CurrencyCode to
o Double rate
}
Why decorators instead of a CurrencyDecimalPlaces concept
Earlier drafts of this proposal carried a separate CurrencyDecimalPlaces concept as reference data. Decorators are strictly better:
- Single source of truth β metadata lives on the enum value itself; no risk of drift between two collections
- Idiomatic Concerto β decorators are the language's intended mechanism for static metadata
- Smaller surface β eliminates a concept from the model
- Tooling-friendly β code generators, validators, and introspection APIs can access the value via
getDecorator('DecimalPlaces')
Tradeoff: decorators are not part of the wire format, so consumers need access to the model (not just the instance) to resolve the scale. This is fine for any caller that already loads the CTO via a ModelManager.
Conversion semantics
The two amount representations are interconvertible by reading the decorator off the enum value:
MonetaryAmount β FixedPointMonetaryAmount
Input: { doubleValue: 10.50, currencyCode: "USD" }
Lookup: CurrencyCode.USD.@DecimalPlaces = 2
Output: { mantissa: 1050, scale: 2, currencyCode: "USD" }
FixedPointMonetaryAmount β MonetaryAmount
Input: { mantissa: 1050, scale: 2, currencyCode: "USD" }
Output: { doubleValue: 10.50, currencyCode: "USD" }
JavaScript helper sketch:
function getDecimalPlaces(modelManager, currencyCode) {
const enumDecl = modelManager.getType('org.accordproject.money@1.0.0.CurrencyCode');
const enumValue = enumDecl.getOwnProperty(currencyCode);
return enumValue.getDecorator('DecimalPlaces').getArguments()[0];
}
Decimal places reference (ISO 4217)
| Decimals |
Count |
Currencies |
| 0 |
16 |
BIF, CLP, DJF, GNF, ISK, JPY, KMF, KRW, PYG, RWF, UGX, VND, VUV, XAF, XOF, XPF |
| 2 |
~137 |
AED, AUD, CAD, CHF, CNY, EUR, GBP, USD, β¦ (most currencies) |
| 3 |
18 |
BHD, BOV, COU, IQD, JOD, KWD, LYD, OMR, TND, UYI, XAU, XAG, XPT, XPD, XBA, XBB, XBC, XBD |
Context
This proposal came out of a discussion about modelling monetary amounts in Cicero contracts. The driving questions were:
- Can a JPY amount be represented unambiguously without out-of-band knowledge?
- Can a contract that settles money use a representation that doesn't introduce floating-point drift?
- Is the digital-currency concept still earning its place in the core money model, or should it move out?
The dual-representation approach lets template authors choose: keep MonetaryAmount for human-readable / display / legacy use, opt into FixedPointMonetaryAmount for precision-critical work, and convert between them when integrating systems with different expectations.
Detailed Description
Use case guidance
| Scenario |
Recommended type |
| Legacy contracts (v0.3.0 migration) |
MonetaryAmount |
| Display values, UI bindings |
MonetaryAmount |
| Banking, settlement, ledgers |
FixedPointMonetaryAmount |
| Tax computations, accruals |
FixedPointMonetaryAmount |
| Regulated financial reporting |
FixedPointMonetaryAmount |
| Cross-currency arithmetic |
FixedPointMonetaryAmount |
| Estimated / approximate values |
MonetaryAmount |
Breaking changes
- Removal of
DigitalMonetaryAmount and DigitalCurrencyCode. Contracts using these would migrate to either:
- A new dedicated namespace (e.g.
org.accordproject.crypto@1.0.0), or
- Continue using
@0.3.0 in parallel (Concerto supports multi-version imports), or
- Switch to fiat
MonetaryAmount where appropriate.
Non-breaking additions
FixedPointMonetaryAmount β new concept
Amount β new abstract base (existing MonetaryAmount extends it)
@DecimalPlaces decorator on each CurrencyCode value
- New
CurrencyCode enum entries (e.g. VES)
Design alternatives considered
- Generic
FixedPoint<S> type β rejected: Concerto doesn't have generics and adding them for one type is too invasive.
- Replace
Double doubleValue with Long mantissa outright β rejected: breaks every v0.3.0 contract.
- Single concept with optional
mantissa + scale alongside doubleValue β rejected: dual-state in one concept invites consistency bugs; clearer to model as two related concepts sharing Amount.
- Separate
CurrencyDecimalPlaces reference concept β rejected in favour of @DecimalPlaces decorator; metadata co-located with the enum is harder to desynchronise.
- String-based decimal representation β rejected: loses type information, requires parsing on every operation.
The dual-concept approach with a shared Amount base and decorator-annotated enum felt most idiomatic for Concerto.
Open questions for the community
- Is the abstract
Amount base useful, or does it add ceremony without payoff?
- Are there code-generation targets in
concerto-codegen that strip decorators? If so, what's the mitigation for consumers in those languages?
- Should we also add
FixedPointCurrencyConversion for precision-safe FX rates?
- Are there contracts in the wild that still rely on
DigitalMonetaryAmount / DigitalCurrencyCode? If so, what's the migration story?
- Should we add Concerto validation constraints (e.g.,
scale range [0, 4]) on FixedPointMonetaryAmount, or leave that to applications?
Happy to iterate on this β feedback welcome before any PR.
Feature Request ποΈ
Propose a stable 1.0.0 release of
org.accordproject.money, addressing three long-standing concerns: removal of digital currency types, correct handling of non-decimal currency denominations, and an optional precision-safe fixed-point representation.Opening this for community discussion before any code changes land.
Use Case
The current model (
org.accordproject.money@0.3.0) has a few limitations that surface in real contracts:DigitalMonetaryAmount/DigitalCurrencyCodemix cryptocurrency concerns into the core money model. These belong in a separate, specialised namespace.Double doubleValueis ambiguous across currencies with different minor-unit conventions β JPY (0 decimals), USD (2 decimals), KWD (3 decimals) all share the same field type but require different interpretation.CurrencyCodeenum should be refreshed against the latest ISO 4217 active list (e.g.,VESfor the Venezuelan BolΓvar Soberano).Possible Solution
A dual-representation v1.0.0 model that:
DigitalMonetaryAmountandDigitalCurrencyCodeMonetaryAmount(withdoubleValue+currencyCode) backwards-compatible with v0.3.0FixedPointMonetaryAmountfor precision-safe arithmeticCurrencyCodeenum value with a@DecimalPlacesdecorator carrying its ISO 4217 minor-unit countCurrencyCodeagainst ISO 4217 as of 2026Draft
money@1.0.0.ctoWhy decorators instead of a
CurrencyDecimalPlacesconceptEarlier drafts of this proposal carried a separate
CurrencyDecimalPlacesconcept as reference data. Decorators are strictly better:getDecorator('DecimalPlaces')Tradeoff: decorators are not part of the wire format, so consumers need access to the model (not just the instance) to resolve the scale. This is fine for any caller that already loads the CTO via a
ModelManager.Conversion semantics
The two amount representations are interconvertible by reading the decorator off the enum value:
JavaScript helper sketch:
Decimal places reference (ISO 4217)
Context
This proposal came out of a discussion about modelling monetary amounts in Cicero contracts. The driving questions were:
The dual-representation approach lets template authors choose: keep
MonetaryAmountfor human-readable / display / legacy use, opt intoFixedPointMonetaryAmountfor precision-critical work, and convert between them when integrating systems with different expectations.Detailed Description
Use case guidance
MonetaryAmountMonetaryAmountFixedPointMonetaryAmountFixedPointMonetaryAmountFixedPointMonetaryAmountFixedPointMonetaryAmountMonetaryAmountBreaking changes
DigitalMonetaryAmountandDigitalCurrencyCode. Contracts using these would migrate to either:org.accordproject.crypto@1.0.0), or@0.3.0in parallel (Concerto supports multi-version imports), orMonetaryAmountwhere appropriate.Non-breaking additions
FixedPointMonetaryAmountβ new conceptAmountβ new abstract base (existingMonetaryAmountextends it)@DecimalPlacesdecorator on eachCurrencyCodevalueCurrencyCodeenum entries (e.g.VES)Design alternatives considered
FixedPoint<S>type β rejected: Concerto doesn't have generics and adding them for one type is too invasive.Double doubleValuewithLong mantissaoutright β rejected: breaks every v0.3.0 contract.mantissa+scalealongsidedoubleValueβ rejected: dual-state in one concept invites consistency bugs; clearer to model as two related concepts sharingAmount.CurrencyDecimalPlacesreference concept β rejected in favour of@DecimalPlacesdecorator; metadata co-located with the enum is harder to desynchronise.The dual-concept approach with a shared
Amountbase and decorator-annotated enum felt most idiomatic for Concerto.Open questions for the community
Amountbase useful, or does it add ceremony without payoff?concerto-codegenthat strip decorators? If so, what's the mitigation for consumers in those languages?FixedPointCurrencyConversionfor precision-safe FX rates?DigitalMonetaryAmount/DigitalCurrencyCode? If so, what's the migration story?scalerange[0, 4]) onFixedPointMonetaryAmount, or leave that to applications?Happy to iterate on this β feedback welcome before any PR.