Skip to content

Prices, sizes, and units

Every numeric field that represents a human price, size, balance, or volume is a decimal string — books, fills, candles, trades, and maker balances all share the same Decimal { value }Decimal(value=...) wrapper. This is the load-bearing contract: get it right and everything downstream works.

Why strings

Floating-point arithmetic loses precision for large notionals. Decimal strings preserve the exact representation. Parse with whatever fixed-precision type your language offers:

LanguageLibrary
Rustrust_decimal::Decimal
Pythondecimal.Decimal
TypeScriptbignumber.js or decimal.js

Conventions on the wire

FieldExampleMeaning
price"155.14"Quote per base, human-readable
size"10.0"Base token units (e.g. SOL)
volume"42.137"Candle base-asset volume
open / high / low / close"154.97"Candle OHLC
balance"1.5"Maker balance in token units (server scales by SpotMetadata.decimals)
best_bid / best_ask / midstringsOptional, omitted on empty side

You will never see on the wire:

  • Lot multiples.
  • Oracle units.

MakerService reports balances in human token units — the server applies SpotMetadata.decimals for you, so a 1.5-SOL balance arrives as a decimal string value of "1.5", not 1_500_000_000 atoms.

The SDK's quoting layer converts the human values you pass to the on-chain integer forms exactly once, at the point of building the instruction. The integer forms are documented in How Flint works for completeness — most integrators never have to think about them.

Pricing helpers

For when you need the conversion outside a QuoteBuildercore.builder() call:

rust
use flint_api_client::pricing::{human_to_oracle, oracle_to_human, human_size_to_lots};

let cfg = client.refresh_config(None).await?;
let market = cfg.market("SOL/USDC")?;

let oracle = human_to_oracle(155.14, market);  // → 155_140
let back = oracle_to_human(oracle, market);    // → 155.14
let lots = human_size_to_lots(10.0, market);   // → 10_000
python
from decimal import Decimal
from flint.onchain import human_size_to_lots, human_to_oracle, oracle_to_human

oracle = human_to_oracle(Decimal("155.14"), market.units)
back = oracle_to_human(oracle, market.units)
lots = human_size_to_lots("10.0", market.units)

Edge cases (saturate, NaN, negative) are documented in the Rust function-level docs.Human money inputs must be decimal.Decimal, decimal strings, or integers. Floats, NaN/Infinity, negatives, overflows, fractional atoms, and non-lot-aligned sizes raise instead of being rounded into quote bytes.

Timestamps

  • Timestamp { micros }Timestamp(micros=...) — Unix microseconds since epoch. Used on trades, candles, stream events, and range bounds.
  • slot — Solana slot number. Useful for cross-referencing on-chain data.
  • Historical start is inclusive. Historical end is exclusive and defaults to server time when unset or micros = 0micros=0.

Enums on the wire

Wire/proto enum names use these variant names:

FieldExamples
interval"CANDLE_INTERVAL_5M", "CANDLE_INTERVAL_1H", "CANDLE_INTERVAL_1D"
side"SIDE_BUY", "SIDE_SELL"
state"HEALTH_STATE_HEALTHY", "HEALTH_STATE_DEGRADED"

The SDKs expose typed enum forms or generated constants, so you don't have to hardcode raw numbers.

Built on Solana