From 1211cbc8bf3413a2b9ddef729bae68d430ff2482 Mon Sep 17 00:00:00 2001 From: ayomustap Date: Mon, 31 Aug 2026 01:00:45 +0000 Subject: [PATCH] Fix bigint escrow formatting --- apps/web/package.json | 2 +- apps/web/src/lib/amount.ts | 15 +++++++++++++++ apps/web/src/lib/chain.test.ts | 15 +++++++++++++++ apps/web/src/lib/chain.ts | 4 +++- 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 apps/web/src/lib/amount.ts create mode 100644 apps/web/src/lib/chain.test.ts diff --git a/apps/web/package.json b/apps/web/package.json index 6351b9de..bfc493bc 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -8,7 +8,7 @@ "dev": "vite", "build": "vite build", "preview": "vite preview", - "test": "node --import tsx --test src/demo/trace-health-check.test.ts src/lib/config.test.ts src/dashboard/fixture-health-check.test.ts src/lib/round-status.test.ts src/components/dashboard/RoundStatusCard.test.tsx", + "test": "node --import tsx --test src/demo/trace-health-check.test.ts src/lib/config.test.ts src/lib/chain.test.ts src/dashboard/fixture-health-check.test.ts src/lib/round-status.test.ts src/components/dashboard/RoundStatusCard.test.tsx", "typecheck": "tsc --noEmit -p tsconfig.json" }, "dependencies": { diff --git a/apps/web/src/lib/amount.ts b/apps/web/src/lib/amount.ts new file mode 100644 index 00000000..df2e2187 --- /dev/null +++ b/apps/web/src/lib/amount.ts @@ -0,0 +1,15 @@ +// Copyright (c) 2026 Sub Rosa contributors + +export function formatEscrowAmount(value: bigint, tokenLabel: string): string { + const SCALE = 10_000_000n; + const QUANTA = 10_000n; + + const whole = value / SCALE; + const remainder = value % SCALE; + const fractional = (remainder * QUANTA + (SCALE / 2n)) / SCALE; + + const normalizedWhole = fractional >= QUANTA ? whole + 1n : whole; + const normalizedFraction = fractional >= QUANTA ? 0n : fractional; + + return `${normalizedWhole}.${normalizedFraction.toString().padStart(4, "0")} ${tokenLabel}`; +} diff --git a/apps/web/src/lib/chain.test.ts b/apps/web/src/lib/chain.test.ts new file mode 100644 index 00000000..ceb38170 --- /dev/null +++ b/apps/web/src/lib/chain.test.ts @@ -0,0 +1,15 @@ +import assert from "node:assert/strict"; +import { test } from "node:test"; + +import { formatEscrowAmount } from "./amount"; + +test("formatEscrowAmount preserves exact 4-decimal display above Number.MAX_SAFE_INTEGER", () => { + assert.equal(formatEscrowAmount(9007199254740992n, "token"), "900719925.4741 token"); + assert.equal(formatEscrowAmount(9007199254741500n, "token"), "900719925.4742 token"); +}); + +test("formatEscrowAmount keeps four-decimal display for standard escrow values", () => { + assert.equal(formatEscrowAmount(10_000_000n, "token"), "1.0000 token"); + assert.equal(formatEscrowAmount(1_000_000n, "token"), "0.1000 token"); + assert.equal(formatEscrowAmount(123_456_789n, "token"), "12.3457 token"); +}); diff --git a/apps/web/src/lib/chain.ts b/apps/web/src/lib/chain.ts index c9dc2e7e..9122896d 100644 --- a/apps/web/src/lib/chain.ts +++ b/apps/web/src/lib/chain.ts @@ -8,6 +8,8 @@ import { import { RoundContract } from "@sub-rosa/sdk"; import { useMemo } from "react"; +import { formatEscrowAmount } from "./amount"; + export const LOGO_SRC = "/sub-rosa-logo.png"; export const RPC_URL = import.meta.env.VITE_RPC_URL ?? "https://soroban-testnet.stellar.org"; export const NETWORK = @@ -70,7 +72,7 @@ export function toDemoEscrowAmount(value: number): bigint { } export function formatDemoAmount(value: bigint): string { - return `${(Number(value) / 10_000_000).toFixed(4)} ${ESCROW_TOKEN_LABEL}`; + return formatEscrowAmount(value, ESCROW_TOKEN_LABEL); } export async function sha256Bytes(text: string): Promise {