Narrows a u64 (bigint) into a JS number with an explicit safety check.
The deserializeU64 reader returns bigint, but several keyless code
paths historically narrowed the value with Number(value) to fit existing
number-typed fields (expiry timestamps, expiry horizons). For values
larger than Number.MAX_SAFE_INTEGER (~9 × 10^15), Number(bigint)
silently loses precision — comparisons against Date.now() / 1000 then
return wrong results.
Real-world expiry values are far below the unsafe range (year ~285 million
AD as a Unix timestamp), so this check is effectively a guard against
corrupted or malicious BCS data rather than a precision concern in normal
operation. Throwing is correct behavior at the BCS/JSON boundary.
Narrows a u64 (
bigint) into a JSnumberwith an explicit safety check.The
deserializeU64reader returnsbigint, but several keyless code paths historically narrowed the value withNumber(value)to fit existingnumber-typed fields (expiry timestamps, expiry horizons). For values larger thanNumber.MAX_SAFE_INTEGER(~9 × 10^15),Number(bigint)silently loses precision — comparisons againstDate.now() / 1000then return wrong results.Real-world expiry values are far below the unsafe range (year ~285 million AD as a Unix timestamp), so this check is effectively a guard against corrupted or malicious BCS data rather than a precision concern in normal operation. Throwing is correct behavior at the BCS/JSON boundary.