Zeqali precision
Tokens never round. The framework's balance ledger stores ZEQ in Zeqali — an integer subunit defined as
$$ 1\ \text{ZEQ} = 10^{18}\ \text{Zeqali} $$
This is the same convention Ethereum uses for wei vs. ether (1 ETH =
10¹⁸ wei). Every quantity in tally_supply, network_snapshots,
compute_charges, and the audit entangled state is stored as an integer count
of Zeqali, never as a floating-point ZEQ.
Updated 2026-05-18 as part of the v2_math economy lock.
1. Why integers, why 18 decimals
Why integers. Floating-point arithmetic is unsafe for money.
0.1 + 0.2 !== 0.3 in IEEE-754. A wallet that off-by-one'd because
of a binary-fraction rounding error would write a wrong row to the
audit entangled state and silently drift from the conservation invariant
(every charge, claim and envelope mint must balance to zero).
Integers eliminate the entire class of error.
Why 18 decimals. The math-derived mint rate at large N is extremely small. With α_econ ≈ 1.29 × 10⁻³ as the economy's modulation parameter (a tokenomics constant — distinct from the kernel's α_K = 10⁻³) and envelope splits computed over funding ratios at scale, individual fractional amounts can land in the 10⁻¹⁵ ZEQ range. 18 decimals gives us:
- enough headroom that the smallest non-zero math-derived payout is still ≥ 1 Zeqali (an integer the entangled state can write)
- alignment with the de-facto crypto-wallet standard so existing off-chain tooling (Ethers, web3, BigInt math) works unchanged
- a clean visual rule:
BigInt(amount_in_zeqali) / 10n**18nis the ZEQ integer part; the remainder is the fractional sub-token.
2. The conversion contract
In TypeScript:
const ZEQALI_PER_ZEQ = 10n ** 18n;
/** Convert a ZEQ amount (number or string) to Zeqali (BigInt). */
function toZeqali(zqt: string | number): bigint {
const [intPart, fracPart = ""] = String(zqt).split(".");
const padded = (fracPart + "0".repeat(18)).slice(0, 18);
return BigInt(intPart) * ZEQALI_PER_ZEQ + BigInt(padded);
}
/** Convert a Zeqali BigInt back to a fixed-precision ZEQ string. */
function fromZeqali(zeqali: bigint, decimals = 6): string {
const int = zeqali / ZEQALI_PER_ZEQ;
const frac = zeqali % ZEQALI_PER_ZEQ;
const fracStr = frac.toString().padStart(18, "0").slice(0, decimals);
return `${int.toString()}.${fracStr}`;
}
These two functions are the only conversion path the SDK exposes.
Anything that goes onto the wire as a wallet amount is Zeqali. Anything
shown to a user is rendered via fromZeqali(zeqali, 6) (six decimals
is the SDK default — enough resolution to see fuel flows without
overwhelming the display).
3. Wire format
API responses always carry the integer Zeqali count as a string (JSON numbers can't represent BigInts safely):
{
"wallet": {
"balance_zeqali": "12870000000000000000",
"balance_zqt": "12.870000"
},
"compute_charge_zeqali": "100000000000000000",
"compute_charge_zqt": "0.100000"
}
balance_zqt is the rendered string for display; balance_zeqali is
the truth-of-record. Clients must treat balance_zqt as derived
and never round-trip through it for arithmetic.
4. Worked example — α modulation at N = 1,000,000
The v2_math compute split at N machines has the form
f = b = α × log₂(1 + N). At N = 1,000,000:
log₂(1 + 1,000,000) ≈ 19.93α × log₂(1 + N) ≈ 1.29 × 10⁻³ × 19.93 ≈ 0.02571- foundation + burn each take 2.571% of the charge
For a 0.001 ZEQ call:
charge = 0.001 ZEQ = 1,000,000,000,000,000 Zeqali
foundation_zq = charge × 0.02571 ≈ 25,710,000,000,000 Zeqali
burn_zq = charge × 0.02571 ≈ 25,710,000,000,000 Zeqali
owner_zq = charge - found - burn ≈ 948,580,000,000,000 Zeqali
(recovered exactly via
subtraction — no rounding gap)
The mass-conservation rule is owner_zq = charge - foundation_zq - burn_zq,
computed as the residual, not independently. This guarantees the
sum is exactly the input charge with zero drift — even when the split
percentages are irrational at the precision we care about.
5. Sanity table — smallest representable amount per surface
| Surface | Smallest amount | In Zeqali |
|---|---|---|
| Compute charge (typical) | 10⁻³ ZEQ | 10¹⁵ |
| Subscription tier discount | 10⁻⁴ ZEQ | 10¹⁴ |
| Daily free-credit claim (Free tier) | 777 ZEQ | 7.77 × 10²⁰ |
| Smallest envelope-split fraction at N=1B | ~10⁻¹⁵ ZEQ | 10³ |
| Welcome package (signup) | 1,287 ZEQ | 1.287 × 10²¹ |
The smallest meaningful number in the framework — a fractional envelope share at network-scale N — is still three orders of magnitude above 1 Zeqali. There is no scenario where the precision floor truncates a real payout.
6. Common pitfalls
Don't multiply in floating-point first. This:
// WRONG — rounds at the JS Number boundary
const fee = Number(balance) * 0.05;
corrupts at ~15 significant digits. The correct path:
// RIGHT — stays in BigInt
const fee = (balance * 5n) / 100n;
Don't store Zeqali in JSON numbers. A wallet with 100 ZEQ is
already 10²⁰ Zeqali, well past Number.MAX_SAFE_INTEGER. Always
serialize as a string and parse on the other side via BigInt(...).
Don't infer ZEQ from a rounded display. If a UI shows
0.000001 ZEQ, that's 10¹² Zeqali — but the underlying balance
might be 1,234,567,890,123 Zeqali (≈ 0.000001234 ZEQ). Treat the
display as advisory; the entangled state row is canonical.
Bottom line. Zeqali is the framework's atom of value: one integer step at 18 decimals below ZEQ, written verbatim onto every chain row. The display layer is allowed to round; the ledger is not.