Skip to main content
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

Converting in and out

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

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:
In TS, replicate via integer bigint math:

Unrealized PnL example

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:

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).