fix: a V4 SETTLE of ETH paid from the router reads as moved from the sender (closes #682)
check / check (push) Canceled after 0s
e2e / e2e-chrome (push) Canceled after 0s
e2e / e2e-firefox (push) Canceled after 0s

V4Router pays a SETTLE of ETH from the router's own ETH, whichever payer
it names. The router holds the transaction's value. So a SETTLE of ETH
that names the router as payer now counts as paid by the user.

When an earlier step left ETH in the router, such a SETTLE gets lines of
its own. Its line reads "Up to" and its amount, and that amount never
joins the Amount total. A SETTLE of CONTRACT_BALANCE reads as an amount
the decoder does not know.

One existing row in tests/uniswapRecipient.test.js now expects the ETH
lines. Its SETTLE spends all the router's ETH, the transaction's value
included.

Model: opus-5-5
This commit is contained in:
2026-10-27 04:34:53 +00:00
parent 36b200247a
commit 182742152d
4 changed files with 166 additions and 29 deletions
+29 -9
View File
@@ -1661,9 +1661,18 @@ describe("any token left in the router is not received", () => {
),
min: "1990.0000 USDC",
},
{
kind: "a swap paying WETH to the router, an UNWRAP_WETH into the router, then a V4 swap settling all the ETH from the router",
data: execute(
])("$kind reads as a swap paid to the user", ({ data, min }) => {
const result = decode(data);
expect(labels(result)).toEqual(PAID_TO_USER);
expect(detail(result, "Min. received").value).toBe(min);
});
// https://git.eeqj.de/sneak/AutistMask/issues/682 — the SETTLE spends all
// the router's ETH, the transaction's value included, so the sender pays
// an amount the calldata does not state.
test("a swap paying WETH to the router, an UNWRAP_WETH into the router, then a V4 swap settling all the ETH from the router reads as a swap paid to the user", () => {
const result = decode(
execute(
swapToWeth(ADDRESS_THIS),
unwrapWeth(ADDRESS_THIS),
v4Swap(
@@ -1672,12 +1681,23 @@ describe("any token left in the router is not received", () => {
takeAll(USDC),
),
),
min: "1990.0000 USDC",
},
])("$kind reads as a swap paid to the user", ({ data, min }) => {
const result = decode(data);
expect(labels(result)).toEqual(PAID_TO_USER);
expect(detail(result, "Min. received").value).toBe(min);
);
expect(labels(result)).toEqual([
"Protocol",
"Token In",
"Amount",
"Moved from the sender",
"Token moved",
"Moved to",
"Token Out",
"Min. received",
"Steps",
"Deadline",
]);
expect(detail(result, "Moved from the sender").value).toBe(
"Unknown (could not be decoded)",
);
expect(detail(result, "Min. received").value).toBe("1990.0000 USDC");
});
});