> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zerodash.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Amounts and currencies

> Decimals on the wire, 64-bit integers in storage, and exactly how much precision each asset gets.

<Card title="The one rule" icon="circle-exclamation" horizontal>
  **Callbacks always exchange the decimal value.** `12.45`, never `1245`. Zero-Dash converts to and from integer storage internally; you never see minor units on the wire.
</Card>

## How Zero-Dash stores money

Internally every monetary value is a **64-bit integer**. Each currency carries a `decimal_places` value that converts between that integer and the decimal exchanged in callbacks.

```mermaid theme={null}
flowchart LR
    A["Callback payload<br/><b>12.45 USD</b>"] -->|"× 10^decimal_places"| B["Internal storage<br/><b>1245</b>"]
    B -->|"÷ 10^decimal_places"| A
```

This matters to you for one reason: it fixes the precision each currency gets, and anything beyond it is truncated.

## Fiat

Fiat values are stored in **cents** — `decimal_places = 2`.

| Stored value | Decimal | On the wire |
| ------------ | ------- | ----------- |
| `1`          | 0.01    | `0.01`      |
| `100`        | 1.00    | `1.00`      |
| `250`        | 2.50    | `2.50`      |

<Warning>
  Currencies whose ISO definition has 0 or 3 decimals — JPY, TND and others — are **nonetheless** stored and exchanged with 2 decimal places. `1 JPY` is 100 internal units and travels as `1.00`, not `1`.

  If your platform stores JPY as whole yen, convert at the boundary. Sending `1` where `1.00` is expected is the same number; sending whole yen where the decimal is expected is not.
</Warning>

## Crypto

Every crypto asset is capped at **8 decimal places**, even when the chain supports more.

| Currency | Zero-Dash precision | Real precision |
| -------- | :-----------------: | :------------: |
| BTC      |          8          |        8       |
| ETH      |          8          |       18       |
| BNB      |          8          |       18       |
| DOGE     |          8          |        8       |
| ADA      |          6          |        6       |
| XRP      |          6          |        6       |
| LTC      |          8          |        8       |
| TRX      |          6          |        6       |
| SOL      |          8          |        9       |
| BCH      |          8          |        8       |
| USDT     |          6          |        6       |
| USDC     |          6          |        6       |

Worked examples of the internal representation:

```plain theme={null}
1      — "ETH"  = 0.00000001 ETH
10,000 — "USDC" = 0.010000 USDC
```

<Warning>
  ETH, BNB and SOL have more decimals on-chain than Zero-Dash carries. Any value you send **or receive** must fit within the precision in the table above. Sending `0.000000000000000001 ETH` does not produce a tiny bet — it produces a value that truncates to zero.
</Warning>

## Precision on your side

<Steps>
  <Step title="Use a decimal type, never a float" icon="calculator">
    `BigDecimal`, `decimal.Decimal`, `shopspring/decimal`, `Prisma.Decimal` — anything exact. IEEE-754 binary floats cannot represent `0.1`, and rounding errors in a wallet turn into reconciliation tickets.
  </Step>

  <Step title="Parse JSON numbers as strings" icon="quote-left">
    Most JSON parsers hand you a `double` before you can intervene. Configure the parser to keep raw numbers — `json.Number` in Go, `parse_float=Decimal` in Python, `JsonNumberHandling` in .NET — then build your decimal from the text.
  </Step>

  <Step title="Round only at the boundary" icon="ruler">
    Compute in full precision; truncate to the currency's places only when writing the value out.
  </Step>
</Steps>

<Tip>
  Where a value could be ambiguous, sending it as a **JSON string** is accepted. [Create free rounds campaign](/api-reference/customer/create-campaign) documents this explicitly for `amount`: send `"2.50"` if your language cannot emit `2.5` faithfully. Zero-Dash parses both as a decimal.
</Tip>

## Currency codes

Codes follow **ISO-4217** — `EUR`, `USD`, `BTC`, `ETH` — and crypto uses the same convention.

<Note>
  `FUN` is the virtual currency used by [free-to-play](/launch/free-to-play) sessions. It never reaches your wallet: demo sessions produce no callbacks at all.
</Note>

## Currency consistency

One currency is fixed for the entire life of an [account ID](/wallet/account-id). It must be the same value across:

<CardGroup cols={2}>
  <Card title="Launch" icon="rocket">
    The `currency` parameter you pass to [Obtain game launch URL](/api-reference/customer/game-launch-url).
  </Card>

  <Card title="Authorization" icon="user-check">
    `balance.currency` returned by [Player authorization](/api-reference/callbacks/player).
  </Card>

  <Card title="Every movement" icon="right-left">
    `stake.currency` and `payout.currency` in each debit, credit and rollback.
  </Card>

  <Card title="Free rounds" icon="gift">
    `currencyCode` on both the campaign and the bonus code.
  </Card>
</CardGroup>

A mismatch anywhere in that chain is rejected. There is no conversion step in the middle.

## Balance semantics

The `balance` you return is the balance **after** the operation was applied.

| Callback    | Return                                     |
| ----------- | ------------------------------------------ |
| `/player`   | Current balance                            |
| `/debit`    | Balance **after** the stake was subtracted |
| `/credit`   | Balance **after** the payout was added     |
| `/rollback` | Balance **after** the stake was returned   |

<Warning>
  Games display this value to the player immediately. Returning the pre-movement balance shows a number that is one transaction stale, and players notice within a single round.
</Warning>
