fix(wallet): normalize valid_until timestamp in TON sendMessage#973
fix(wallet): normalize valid_until timestamp in TON sendMessage#973ignaciosantise wants to merge 1 commit intomainfrom
Conversation
The valid_until parameter in ton_sendMessage requests may be sent in milliseconds by some dApps, but TON uses 32-bit timestamps (seconds). Values over ~4.3 billion overflow, causing "bitLength is too small" errors. Changes: - Add normalizeValidUntil() helper to convert ms to seconds when needed - Update validation to normalize before checking expiration - Use normalized value in createTransfer timeout parameter The threshold of 10 billion seconds (year 2286) safely distinguishes between milliseconds and seconds timestamps. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
8 Skipped Deployments
|
There was a problem hiding this comment.
Pull request overview
Fixes TON ton_sendMessage failures when dApps send valid_until in milliseconds by normalizing timestamps to seconds before validation and transfer creation.
Changes:
- Normalize
valid_untilfrom milliseconds to seconds when it exceeds a threshold. - Apply normalization in both expiration validation and
createTransfertimeout. - Minor formatting tweak in
signDatapayload (split(':')).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Normalize to seconds if milliseconds were provided | ||
| const validUntilSeconds = | ||
| params.valid_until > 10_000_000_000 | ||
| ? Math.floor(params.valid_until / 1000) | ||
| : params.valid_until |
There was a problem hiding this comment.
The valid_until normalization logic is duplicated here and again in normalizeValidUntil(). To avoid the two implementations drifting (threshold, rounding, etc.), reuse the helper inside validation (e.g., derive validUntilSeconds via this.normalizeValidUntil(...) and then validate against that).
| // Normalize to seconds if milliseconds were provided | |
| const validUntilSeconds = | |
| params.valid_until > 10_000_000_000 | |
| ? Math.floor(params.valid_until / 1000) | |
| : params.valid_until | |
| const validUntilSeconds = this.normalizeValidUntil(params.valid_until) |
| ? Math.floor(params.valid_until / 1000) | ||
| : params.valid_until | ||
|
|
||
| if (validUntilSeconds < Date.now() / 1000) { |
There was a problem hiding this comment.
The expiration check compares an integer validUntilSeconds to Date.now() / 1000 (a fractional seconds value). This will treat valid_until = Math.floor(Date.now()/1000) as expired for most of that second. Elsewhere in this file timestamps use Math.floor(Date.now() / 1000) (e.g., signData), so consider flooring the current time here as well for consistent second-level semantics.
| if (validUntilSeconds < Date.now() / 1000) { | |
| if (validUntilSeconds < Math.floor(Date.now() / 1000)) { |
| private normalizeValidUntil(validUntil?: number): number | undefined { | ||
| if (validUntil === undefined) { | ||
| return undefined | ||
| } | ||
| // If value > 10 billion, it's likely milliseconds (year 2286+ in seconds) | ||
| if (validUntil > 10_000_000_000) { | ||
| return Math.floor(validUntil / 1000) | ||
| } | ||
| return validUntil |
There was a problem hiding this comment.
normalizeValidUntil() (and the corresponding validation) accepts any number, including NaN, Infinity, or non-integers, which can silently pass validation and then be forwarded as timeout to createTransfer. Consider rejecting non-finite values (and, if required by the TON SDK, non-integer values) via Number.isFinite(...) (and possibly Number.isInteger(...)) before returning/using the timestamp.
Summary
valid_untilin millisecondsnormalizeValidUntil()helper to convert milliseconds to seconds when neededProblem
The
valid_untilparameter inton_sendMessagerequests may be sent in milliseconds by some dApps, but TON uses 32-bit timestamps (seconds). Values over ~4.3 billion overflow, causing "bitLength is too small" errors.Solution
Detect millisecond timestamps by checking if the value exceeds 10 billion (year 2286 in seconds), and convert to seconds when needed. This normalization is applied both in validation and when passing to
createTransfer.Test plan
Date.now()) - should work without overflow error🤖 Generated with Claude Code