From 0ea63621ba22fec11e8573061ce3dbdaf9972024 Mon Sep 17 00:00:00 2001 From: Bhargava Sri Sai Date: Thu, 1 Oct 2026 17:41:51 +0530 Subject: [PATCH] docs: explain money representation --- README.md | 5 +++++ docs/MONEY.md | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 docs/MONEY.md diff --git a/README.md b/README.md index 482d636..bc49bc2 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,11 @@ See [docs/INDEXER.md](./docs/INDEXER.md) for a full table of which on-chain events the indexer handles, which tables each one writes, and how the checkpoint and out-of-window recovery work. +## Data representation + +See [docs/MONEY.md](./docs/MONEY.md) for why stream ids and token amounts are +serialized as strings at the API boundary. + ## Notification events When `NOTIFY_WEBHOOK_URL` is set, the indexer POSTs a JSON body to that URL diff --git a/docs/MONEY.md b/docs/MONEY.md new file mode 100644 index 0000000..a885223 --- /dev/null +++ b/docs/MONEY.md @@ -0,0 +1,39 @@ +# IDs and monetary amounts + +The database and API keep on-chain values in representations that do not lose +precision in JavaScript. + +## Stream IDs + +The donation-vault contract assigns each stream an integer `onChainId`. Prisma +maps that field to PostgreSQL/JavaScript `BigInt`, not a JavaScript `number`. +The stream routes serialize it explicitly with `toString()` before returning a +JSON response, because JSON does not have a built-in `BigInt` representation. +Clients should therefore treat `onChainId` as a decimal string: + +```json +{ + "onChainId": "1234" +} +``` + +The database primary keys and cursor values used by the API are UUID strings; +they are separate from the contract's `onChainId`. + +## Token amounts + +The contract's `i128` values are stored in the `Stream` model as decimal +strings: `rate`, `lastRate`, `balance`, and `withdrawn`. These values are in +the stream token's base units. The API keeps them as strings for the same +reason—converting a large integer to a JavaScript `number` can silently lose +precision. + +Notification payloads and aggregate fields such as `totalCommitted` and +`totalWithdrawn` also use decimal strings. Parse them with an arbitrary- +precision decimal/integer implementation when doing arithmetic; do not use +`Number` for token amounts. + +For active streams, the committed amount is `balance + withdrawn`. For +cancelled streams, `balance` has been refunded and zeroed by the contract, so +only `withdrawn` represents funds delivered to the NGO. See the API's stats +semantics for the corresponding aggregate rules.