Skip to content

Float safety: Myriad normalizer Number(priceWei) / 1e18 order book levels #256

@realfishsam

Description

@realfishsam

Risk Level

HIGH

Location

core/src/exchanges/myriad/normalizer.ts:196-202

Code

normalizeClobOrderBook(raw: { bids: [string, string][]; asks: [string, string][] }): OrderBook {
    const WEI = 1e18;
    return {
        bids: raw.bids.map(([priceWei, sizeWei]) => ({
            price: Number(priceWei) / WEI,
            size: Number(sizeWei) / WEI,
        })),
        asks: raw.asks.map(([priceWei, sizeWei]) => ({
            price: Number(priceWei) / WEI,
            size: Number(sizeWei) / WEI,
        })),
        timestamp: Date.now(),
    };
}

Problem

Number(priceWei) converts a 256-bit EVM integer string to an IEEE 754 double. JavaScript Number has only 53 bits of mantissa — any wei value above 2^53 (≈9 × 10^15) loses precision silently. Since WEI = 1e18, a typical full-token price in wei is on the order of 5 × 10^17, which is within the 53-bit range, but sizes (quantities) in wei can easily exceed 2^53.

Division by 1e18 then loses further precision.

Example Failure

priceWei = "999999999999999999"  // 0.999999999999999999 ETH-denominated
Number("999999999999999999") = 1000000000000000000  // rounded up! (> 2^53)
price = 1000000000000000000 / 1e18 = 1.0  // shown as 100% instead of ~99.9999...%

This means a 99.9999% order appears on the book at 100%, which is invalid for a prediction market.

Suggested Fix

Use BigInt for wei values and only convert at the last step:

const WEI = 10n ** 18n;
price: Number((BigInt(priceWei) * 10000n) / WEI) / 10000,

Or use decimal.js with string input to preserve all digits:

import Decimal from 'decimal.js';
price: new Decimal(priceWei).dividedBy('1e18').toNumber(),

Found by automated float safety audit

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions