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

# Data Formats & Precision

> Decimals, BigInt, and rounding conventions across Kimia programs.

All Kimia math is **fixed-point integer**. There is no floating-point anywhere
in the programs, and client code should follow the same convention.

## Precision scales

| Quantity                      | Decimals | Constant (Rust)                     | JS type  |
| ----------------------------- | -------- | ----------------------------------- | -------- |
| **Base** (SOL)                | 9        | `BASE_PRECISION = 1_000_000_000`    | `bigint` |
| **Quote / collateral** (USDC) | 6        | `QUOTE_PRECISION = 1_000_000`       | `bigint` |
| **Price**                     | 6        | `PRICE_PRECISION = 1_000_000`       | `bigint` |
| **Funding rate**              | 9        | `FUNDING_PRECISION = 1_000_000_000` | `bigint` |
| **Fixed-point (yield math)**  | 9        | `ONE = 1_000_000_000`               | `bigint` |
| **BPS / margin ratio**        | 4        | `BPS_PRECISION = 10_000`            | `number` |

## Converting in and out

```ts theme={null}
// USDC user input → on-chain
const usdcAmount = BigInt(Math.round(userInput * 1e6));

// Base (SOL) user input → on-chain
const baseAmount = BigInt(Math.round(userInput * 1e9));

// Price user input → on-chain
const price = BigInt(Math.round(userInputUsd * 1e6));

// On-chain value → display
const humanUsdc = Number(amount) / 1e6;
const humanBase = Number(amount) / 1e9;
```

<Warning>
  Never multiply then divide through `Number`. Use `bigint` arithmetic end to
  end if any intermediate exceeds `Number.MAX_SAFE_INTEGER` (2^53 − 1).
</Warning>

## Rounding convention

**Everything rounds down in the user's favor** (i.e. against the trader on the
protocol's side). This is how the Rust crates do it:

```rust theme={null}
pub fn mul_div_down(a: u128, b: u128, denom: u128) -> Option<u64> {
    // floor((a * b) / denom) with u128 intermediate
}
```

In TS, replicate via integer `bigint` math:

```ts theme={null}
function mulDivDown(a: bigint, b: bigint, denom: bigint): bigint {
  return (a * b) / denom;   // '/' is floor for positive bigints
}

function mulDivUp(a: bigint, b: bigint, denom: bigint): bigint {
  return (a * b + denom - 1n) / denom;
}
```

## Unrealized PnL example

```
base_amount  = +1_000_000_000      (1 SOL long)
quote_entry  = -130_000_000        (entered at $130)
mark_price   = 140_000_000         ($140)

pnl = base_amount × mark_price / BASE_PRECISION + quote_entry
    = 1e9 × 140e6 / 1e9 + (-130e6)
    = 140_000_000 + (-130_000_000)
    = +10_000_000
    = +$10.00 USDC
```

Note: `quote_entry` is **negative for longs** and positive for shorts. Signs
capture direction.

## Funding rate precision

Funding rates are 9-decimal signed `i128`. A rate of `5_000_000` ≈ 0.005
\= 0.5% per period. Over a year of hourly periods, that's ≈4,380%, an extreme
but expressible bound.

Cumulative rates live in two separate `i128` accumulators
(`cumulative_funding_rate_long`, `_short`) to preserve V2 asymmetric-funding
headroom.

## Time

* Unix seconds everywhere.
* Stored as `i64` for consistency with Solana's `Clock::unix_timestamp`.
* In TS, `BigInt(Math.floor(Date.now() / 1000))`.

## BPS vs fixed-point

Don't mix them. Margin ratios and fees use BPS (4 decimals, denominator 10k).
Funding and yield math use 9-decimal fixed point. Convert explicitly:

```ts theme={null}
// 5% BPS → 9-decimal FP
const fp = (500n * ONE) / 10_000n;    // = 50_000_000n
```

## Overflow protection

All Rust `mul_div` calls intermediate through `u128` and return `Option<u64>`.
In TS, `bigint` handles arbitrary size natively, overflow is impossible
unless you explicitly cast to `Number`.

Every on-chain instruction that overflows returns `MathOverflow` (error code
`6070` on kimia-perp, similar codes on the other programs).
