vike
DeveloperTesting

Wire quantizers

The places an f64 becomes the decimal string a venue is sent or an order is signed over — the roster, the source gate that holds them exact, and the cliff they amplify.

A wire quantizer is any place in this workspace where an f64 crosses into rust_decimal and comes back out as the string that is sent to a venue or signed into an order hash. crates/vike-bridge-core/tests/wire_quantizer_probe.rs is both the measurement probe and the committed gate over that family. It exists because a survey of the non-f64 numeric surface reported nothing to fix — and reached that verdict by reading source, which is exactly what this program exists to distrust.

The roster is a constant, not a sentence

vike-bridge-core's own format.rs header used to end "rust_decimal exists only here and at OKX", and that had stopped being true. There are three files, not two, and the third — crates/bridges/hyperliquid/src/px.rs — is a whole module of quantizers whose own doc had called itself the twin of format_to_step since it was written. The correction was not to fix the sentence but to delete it: the probe's WIRE_FILES constant is the list, its source gate walks exactly those files, and the prose points at the constant.

What these functions amplify

The probe's own table names the cliff at each site, and it is the reason the family gets a gate rather than a comment:

sitethe decisionone ULP upstream becomes
format_to_step and its float twin(value / step).trunc()a whole tick or lot
format_scaled_to_step_fthe same truncation, after an exact rational rescalea whole step
okx's to_contractsa truncation through contract size and stepa whole contract step
hyperliquid's clamp_pricemidpoint-away-from-zeroa whole tick, inside the signed action hash
hyperliquid's round_sizetoward zeroa whole lot
polymarket's to_base_unitsa round at an exact halfone micro-unit, inside the signed order

Why this is not a last-bit problem

Two boxes disagreeing by one ULP produce two prices that differ in the sixteenth digit — invisible, and arguably harmless. Push those same two prices through a quantizer whose decision is a truncation or an exact-midpoint comparison and the two boxes emit different wire strings: a different limit price, a different size, and for the two signing venues a different signature over a different order.

The truncation cuts both ways, and the silent direction is the one the header adds. Quantizing down stops an overshoot past a limit, which a venue rejects loudly; the opposite artifact is quiet, since a value sitting one ULP below a grid point emits a whole step less. Whether the ordinary round-then-format chain ever hit that was unmeasured until this probe measured it — the answer was 150 of 4096, a whole step dropped on a value already on the grid, with no perturbation applied at all. That measurement produced the cure, and the row records 0/4096 today.

The source gate

the_wire_quantizers_reach_decimal_through_a_string is the half that runs on every ordinary test pass, and it has three arms.

A required spelling. Every file in WIRE_FILES must contain Decimal::from_str. This is the non-vacuity arm: a scan that opened the wrong path, or read an empty file, would report a confident zero banned hits, so a positive hit is demanded to make that failure loud.

A banned set, in two families. Decimal::from_f64 and Decimal::from_f32 are the wrong door into Decimal — they convert the binary value's full noise, where the string route converts the number the caller meant, and at an exact decimal midpoint the two round opposite ways. The second family is an enumerated set of platform-libm method spellings: a wire quantizer's job is exact arithmetic, and a transcendental appearing in one would put a platform-dependent value inside the amplifier rather than upstream of it. Square root is deliberately absent, because the standard requires it correctly rounded.

A reached-file roster. round_size's grid witness calls into hyperliquid's instruments module for its lot step, deliberately — the witness can only ask its question against the same f64 the grid was built from. The cost is a powi on the path of a quantizer whose output is signed, in a file WIRE_FILES does not scan. REACHED_FILES puts it under the libm half of the ban, because before that roster the only thing standing between a signed order size and a runtime-base powf was prose. The one exemption is a literal base ten with an exponent the witness itself bounds at 22, where every power of ten is exactly representable — measured bit-identical across both platforms. The rule generalizes: a literal 10 or 2 needs nothing, an arbitrary runtime base needs the libm crate.

The hash pin, and what it does not claim

The probe also hashes each quantizer's output over a fixed corpus. That corpus is pure arithmetic — a linear congruential generator and the four operations, never a transcendental — because generating inputs with platform-dependent functions would make every column diverge because of the inputs rather than the subject, a false positive that reads exactly like a real one. A control row hashes the generator's own output, so a table where every other row moved is a function regression, while one where the control moved too is a broken corpus. Each row carries a distinctness floor, so a collapsed corpus cannot pass as agreement, and unrecorded rows read "RECORD" — a placeholder that cannot match a sixteen-character hex hash on length or on content, so an unfinished recording is never mistakable for a measured value.

One site is covered by the source gate and not by the hash pin, for a stated reason: okx's to_contracts is a method on a client, so calling it means standing up a signer and a transport double. It is not unpinned either — crates/bridges/okx/tests/offline/r6_okx_parity.rs compares it bit-for-bit against the frozen fixtures/r6 export, a stronger statement than a hash for the values that fixture carries and a weaker one for every value it does not.

Polymarket's to_base_units is reached by neither half. It is private, its public caller sits behind a crate feature this crate does not take, and WIRE_FILES names neither its file nor any file reaching it — so the sharpest cliff in the table above is the one this probe cannot see, and the header says outright that it deserves a probe in its own crate. Both gaps are declared rather than left implied.

Related: the data model and the venues tree.

On this page