From 580146f14b649264be0bfac550ed2542adef3d8c Mon Sep 17 00:00:00 2001 From: sneak Date: Sun, 4 Oct 2026 21:12:59 +0000 Subject: [PATCH] fix: a swap deadline later than a date can hold is stated in words (closes #437) decode() rendered the Deadline line with toISOString(), which throws on a date past 275760-09-13, the last a JavaScript date can hold. A later deadline, such as the uint256 maximum, therefore left the whole swap undecoded, with nothing saying why. That line now reads "After 275760-09-13 00:00:00 (no deadline in practice)". Model: opus-5-5 --- README.md | 6 ++++++ TODO.md | 6 ++++++ src/shared/uniswap.js | 7 ++++++- tests/uniswap.test.js | 27 +++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e7a0ed..666f79a 100644 --- a/README.md +++ b/README.md @@ -1022,6 +1022,12 @@ unwraps the WETH it did not spend shows USDC. The token permission warning on the signature screen has its own amount wording, including `Unknown`; the SignApproval section below describes it. +The swap's `Deadline` line is the router's deadline as a UTC date and time, e.g. +`2026-02-27 08:25:51`. A JavaScript date reaches only to 275760-09-13 00:00:00 +UTC, so a later deadline, such as the `uint256` maximum, reads +`After 275760-09-13 00:00:00 (no deadline in practice)` rather than leaving the +whole swap undecoded. + #### Partial USD totals Prices are fetched for the top 25 tokens only, so an address can hold assets the diff --git a/TODO.md b/TODO.md index dbc4085..9d15cdd 100644 --- a/TODO.md +++ b/TODO.md @@ -45,6 +45,12 @@ but the review is broader than any of them. # Completed Steps +- 2026-10-04: A swap whose deadline is later than a JavaScript date can hold is + decoded ([#437](https://git.eeqj.de/sneak/AutistMask/issues/437)). A date + reaches only to 275760-09-13, so a later deadline, such as the `uint256` + maximum, made the `Deadline` line throw, and the approval screen showed the + swap as an undecoded contract call with nothing saying why. That line now + reads `After 275760-09-13 00:00:00 (no deadline in practice)`. - 2026-10-04: The swap decoder reads two router zeros the way the router does ([#415](https://git.eeqj.de/sneak/AutistMask/issues/415)). A V2 exact-in `amountIn` of zero means an earlier step already sent the tokens to the pair; diff --git a/src/shared/uniswap.js b/src/shared/uniswap.js index 0f4496d..0b62a8c 100644 --- a/src/shared/uniswap.js +++ b/src/shared/uniswap.js @@ -724,10 +724,15 @@ function decode(data, toAddress, sources) { details.push({ label: "Steps", value: commandNames.join(" \u2192 ") }); + // A JavaScript date reaches only to 275760-09-13 00:00:00 UTC. A + // later deadline, such as the uint256 maximum, makes an invalid date, + // and toISOString() throws on one, so that deadline is said in words. const deadlineDate = new Date(Number(deadline) * 1000); details.push({ label: "Deadline", - value: deadlineDate.toISOString().replace("T", " ").slice(0, 19), + value: isNaN(deadlineDate.getTime()) + ? "After 275760-09-13 00:00:00 (no deadline in practice)" + : deadlineDate.toISOString().replace("T", " ").slice(0, 19), }); return { diff --git a/tests/uniswap.test.js b/tests/uniswap.test.js index 91931cb..952a340 100644 --- a/tests/uniswap.test.js +++ b/tests/uniswap.test.js @@ -554,6 +554,33 @@ describe("uniswap decoder", () => { ); }); + test("shows the deadline as a UTC date and time", () => { + const result = uniswap.decode(FIRST_SWAP_CALLDATA, ROUTER_ADDR); + expect(detail(result, "Deadline").value).toBe("2026-02-27 08:25:51"); + }); + + // A JavaScript date cannot hold this deadline. It used to make the whole + // swap undecoded. + test("a deadline of the uint256 maximum is stated in words", () => { + const data = buildExecute( + "0x08", // V2_SWAP_EXACT_IN + [ + encodeV2SwapExactIn(USER_ADDR, 1000000n, 500000000000000n, [ + USDT_ADDR, + WETH_ADDR, + ]), + ], + 2n ** 256n - 1n, + ); + + const result = uniswap.decode(data, ROUTER_ADDR); + expect(result).not.toBeNull(); + expect(result.name).toBe("Swap USDT \u2192 WETH"); + expect(detail(result, "Deadline").value).toBe( + "After 275760-09-13 00:00:00 (no deadline in practice)", + ); + }); + test("formats permit amount when not unlimited", () => { const data = buildExecute( "0x0a", -- 2.54.0