Risk Level
CRITICAL
Location
core/src/exchanges/smarkets/price.ts:20-35 (utility functions)
core/src/exchanges/smarkets/index.ts:316,321 (order building call site)
Code
// price.ts:20-22
export function toBasisPoints(probability: number): number {
return Math.round(probability * BASIS_POINTS_SCALE); // * 10000
}
// price.ts:34-36
export function toQuantityUnits(gbp: number): number {
return Math.round(gbp * BASIS_POINTS_SCALE); // * 10000
}
// index.ts:316,321 — both are sent directly to the Smarkets API
quantity: toQuantityUnits(params.amount),
body.price = toBasisPoints(params.price);
Problem
probability * 10000 and gbp * 10000 are IEEE 754 float multiplications before Math.round. Any input price or amount that is not exactly representable in binary floating point can produce a dirty intermediate (e.g. 0.3335 * 10000 = 3334.9999999999995) that Math.round then rounds the wrong way.
The integer results are the exact values sent to the Smarkets API as price (basis points, 0–10000) and quantity (1/10000 GBP units). A 1-unit error in price shifts the order by 1 basis point (0.01%); a 1-unit error in quantity is 0.0001 GBP off the requested size. Both values affect order placement.
Example Failure
// GBP quantity edge case
gbp = 0.10015
0.10015 * 10000 = 1001.4999999999999 (IEEE 754)
Math.round(1001.4999...) = 1001 // should be 1002 — order is 0.0001 GBP short
// Price basis-points edge case
probability = 0.05750
0.05750 * 10000 = 574.9999999999999 (IEEE 754)
Math.round(574.999...) = 575 // happens to be right here
probability = 0.10115
0.10115 * 10000 = 1011.4999999999999 (IEEE 754)
Math.round(1011.499...) = 1011 // should be 1012 — order placed at wrong price
Suggested Fix
Use integer arithmetic with decimal.js before multiplying:
import Decimal from 'decimal.js';
export function toBasisPoints(probability: number): number {
return new Decimal(probability).times(BASIS_POINTS_SCALE).toDecimalPlaces(0, Decimal.ROUND_HALF_UP).toNumber();
}
export function toQuantityUnits(gbp: number): number {
return new Decimal(gbp).times(BASIS_POINTS_SCALE).toDecimalPlaces(0, Decimal.ROUND_HALF_UP).toNumber();
}
Found by automated float safety audit
Risk Level
CRITICAL
Location
core/src/exchanges/smarkets/price.ts:20-35(utility functions)core/src/exchanges/smarkets/index.ts:316,321(order building call site)Code
Problem
probability * 10000andgbp * 10000are IEEE 754 float multiplications beforeMath.round. Any input price or amount that is not exactly representable in binary floating point can produce a dirty intermediate (e.g.0.3335 * 10000 = 3334.9999999999995) thatMath.roundthen rounds the wrong way.The integer results are the exact values sent to the Smarkets API as
price(basis points, 0–10000) andquantity(1/10000 GBP units). A 1-unit error inpriceshifts the order by 1 basis point (0.01%); a 1-unit error inquantityis 0.0001 GBP off the requested size. Both values affect order placement.Example Failure
Suggested Fix
Use integer arithmetic with
decimal.jsbefore multiplying:Found by automated float safety audit