Skip to content

Discussion: distribution channel & helper functions for money@1.0.0 reference data #187

Description

@mttrbrts

Spun out of #186 to keep that thread focused on the model. This issue is about how the org.accordproject.money@1.0.0 reference data (currency/token registries) is distributed and consumed, and what — if anything — we ship for arithmetic.

Background

money@1.0.0 moves the code → scale mapping out of the schema (no more hard-coded CurrencyCode enum / @DecimalPlaces decorator) and into reference data: validated instances of org.accordproject.money.reference@1.0.0.CurrencyRegistry, one per scheme (iso4217, erc20, slip44, …). See the draft data under data/ in #188.

PreciseAmount.unscaledValue is now an exact integer string (BigInteger), so amounts are exact at any scale (incl. 18-decimal tokens and aggregate balances). Consumers therefore need (a) the registry data and (b) an arithmetic story.

Arithmetic: reuse, don't build

The amount shape is integer mantissa + scale, which is exactly what mature arbitrary-precision money libraries already model — so we should not build or maintain a money math engine. A thin adapter is enough:

  • Dinero.js v2 (recommended) — near 1:1 mapping with the bigint calculator: Unitcurrency { code, base: 10, exponent: scale }, unscaledValueBigInt(amount). Gives exact add/subtract/allocate/compare and locale formatting for free. (Dinero v1 stores amount as a JS number → 2^53 limit, so v2 is required; note v2 is still alpha.)
  • big.js / bignumber.js / decimal.js — construct the exact decimal from mantissa + scale (via string, not lossy division); stable, tiny adapter.

So the Accord Project deliverable is registry data + a thin adapter + assertKnownUnit, not a bespoke library. Aligning Unit's field names (code, scale) with Dinero's (code, exponent) keeps the adapter trivial.

Illustrative adapter surface:

const toCurrency = u => ({ code: u.code, base: 10, exponent: u.scale });   // Unit -> Dinero currency
const toDinero   = a => dinero({ amount: BigInt(a.unscaledValue), currency: toCurrency(a.unit) });
const fromDinero = (d, unit) => ({ $class: '…PreciseAmount', unscaledValue: String(toSnapshot(d).amount), unit });
assertKnownUnit(amount);   // validate unit.scale against the registry for its scheme

Distribution options for the reference data

  1. HTTP alongside the models. The models repo already publishes src/*.cto to models.accordproject.org with CORS. Teach build.js to also copy data/*.json so registries are fetchable at e.g. https://models.accordproject.org/data/iso4217.json. Language-neutral, versioned with the model; but a runtime fetch and no types.
  2. npm helper package (e.g. @accordproject/money-units). Embeds the JSON + the Dinero adapter + assertKnownUnit. Best JS DX; separate publish lifecycle. Generated from the same data/ JSON so it can't drift.
  3. Bundle into an existing Cicero package (cicero-core / template-engine). Fewer moving parts for template authors; couples to the Cicero release cadence.

(Not mutually exclusive — e.g. HTTP as the canonical source + a generated npm/Cicero adapter for DX.)

Open questions

  1. Which channel(s) — HTTP canonical + a generated adapter, or fold into Cicero?
  2. If a package: standalone @accordproject/money-units, or inside cicero-core / template-engine?
  3. Do we bless Dinero.js v2 as the recommended adapter and ship it, given v2 is still alpha — or stay library-agnostic and only document big.js/decimal.js adapters too?
  4. Codegen targets that can't represent an integer-string cleanly — anything to do for consumers there? (BigInteger is a String scalar, so it maps to string uniformly, which is the easy case.)
  5. How is the reference data kept current (ISO 4217 revisions, new tokens)? Manual PRs, or generated from an upstream source?

Resolved since this was opened

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions