diff --git a/src/utils/_format.ts b/src/utils/_format.ts index 1d088c7e..e382fe83 100644 --- a/src/utils/_format.ts +++ b/src/utils/_format.ts @@ -29,6 +29,14 @@ export function formatPrice(price: string | number, szDecimals: number, type: "p const maxDecimals = Math.max((type === "perp" ? 6 : 8) - szDecimals, 0); price = StringMath.toFixedTruncate(price, maxDecimals); + // Integer prices are always allowed, including values that become integers + // after decimal truncation (e.g. "100001.0" -> "100001"). Without this + // re-check the significant-figure step below would truncate them (-> "100000"). + // A value that truncated all the way to zero is left for the zero check below. + if (/^-?\d+$/.test(price) && !/^-?0+$/.test(price)) { + return formatDecimalString(price); + } + // Apply sig figs limit: max 5 significant figures price = StringMath.toPrecisionTruncate(price, 5); diff --git a/tests/utils/format.test.ts b/tests/utils/format.test.ts index 9a6d939b..975bc442 100644 --- a/tests/utils/format.test.ts +++ b/tests/utils/format.test.ts @@ -32,6 +32,14 @@ Deno.test("formatPrice", async (t) => { assertEquals(formatPrice("1234567", 0), "1234567"); }); + await t.step("integer value with trailing decimal zeros bypasses limit", () => { + assertEquals(formatPrice("100001.0", 0), "100001"); + assertEquals(formatPrice("123456.0", 0), "123456"); + assertEquals(formatPrice("100001.00", 0), "100001"); + assertEquals(formatPrice("-123456.0", 0), "-123456"); + assertEquals(formatPrice("100001.0", 0, "spot"), "100001"); + }); + await t.step("truncates to 5 sig figs", () => { assertEquals(formatPrice("12345.6", 0), "12345"); assertEquals(formatPrice("0.00123456", 0), "0.001234");