Compare commits

..
1 Commits
Author SHA1 Message Date
sneak bde428e98c fix: any token a swap leaves in the router keeps it from reading as received (closes #606)
check / check (push) Canceled after 0s
e2e / e2e-chrome (push) Canceled after 0s
e2e / e2e-firefox (push) Canceled after 0s
The decoder checked only the swap's output for being left in the router.
It now records every token a step pays the router, the WETH of a
WRAP_ETH and the rest of a V4 SETTLE taken to the router among them, and
any token still there after the last step gets a Paid to line naming it,
so the minimum reads Min. paid out. Steps that spend all the router holds
of a token count as spending it, and so do swap steps from the router
that together spend what a WRAP_ETH stated, when the router held no WETH
before it. A SETTLE of OPEN_DELTA from the router counts only in the
plain shape of Uniswap's own routes.

Model: opus-5-5
2026-10-19 19:46:08 +00:00
2 changed files with 54 additions and 3 deletions
+7 -3
View File
@@ -3064,9 +3064,13 @@ Currently supported:
token to anyone but the router, an `ACROSS_V4_DEPOSIT_V3` of token to anyone but the router, an `ACROSS_V4_DEPOSIT_V3` of
`CONTRACT_BALANCE` of that token, or of ETH when it sets `useNative`, or a V2 `CONTRACT_BALANCE` of that token, or of ETH when it sets `useNative`, or a V2
or V3 exact-in swap step or V4 `SETTLE` that pays `CONTRACT_BALANCE` of that or V3 exact-in swap step or V4 `SETTLE` that pays `CONTRACT_BALANCE` of that
token from the router (`payerIsUser` false). Such steps also spend all the token from the router (`payerIsUser` false). V2 and V3 exact-in swap steps and
WETH a `WRAP_ETH` paid the router once together they spend the amount the V4 `SETTLE`s that pay WETH from the router also spend all the WETH a
`WRAP_ETH` states, as a swap paid in ETH does. The router pays a `SETTLE` of `WRAP_ETH` paid it once together they spend the amount the `WRAP_ETH` states,
as a swap paid in ETH does, but only when that amount is not
`CONTRACT_BALANCE` and the router held no WETH from an earlier step when the
`WRAP_ETH` ran: after two `WRAP_ETH`s of 0.5 ETH into the router, a swap of 1
WETH from it reads as leaving the WETH there. The router pays a `SETTLE` of
`OPEN_DELTA` (zero) only what its step still owes of that token when the `OPEN_DELTA` (zero) only what its step still owes of that token when the
`SETTLE` runs, so one from the router counts as spending the amounts the `SETTLE` runs, so one from the router counts as spending the amounts the
step's swap actions state they spend of that token only when every action in step's swap actions state they spend of that token only when every action in
+47
View File
@@ -678,6 +678,53 @@ describe("any token left in the router is not received", () => {
), ),
left: tokenLine(WETH, "WETH"), left: tokenLine(WETH, "WETH"),
}, },
// Only a swap the router pays from its own balance spends the WETH
// a WRAP_ETH paid it, and its stated amount is followed only when the
// router held no WETH before the WRAP_ETH.
{
kind: "a WRAP_ETH of 1 ETH into the router, then a V2 swap of 1 WETH that the user pays for",
data: execute(
wrapEth(ADDRESS_THIS, ONE_WETH),
v2Swap(0x08, MSG_SENDER, ONE_WETH, USDC_1990, [WETH, USDC]),
),
left: tokenLine(WETH, "WETH"),
},
{
kind: "a WRAP_ETH of 1 ETH into the router, then a V3 swap of 1 WETH that the user pays for",
data: execute(
wrapEth(ADDRESS_THIS, ONE_WETH),
v3SwapExactIn(MSG_SENDER, ONE_WETH, USDC_1990, WETH, USDC),
),
left: tokenLine(WETH, "WETH"),
},
{
kind: "a WRAP_ETH of 1 ETH into the router, then a V4 swap of 1 WETH with a SETTLE of 1 WETH by the user",
data: execute(
wrapEth(ADDRESS_THIS, ONE_WETH),
v4Swap(
swapExactInSingle(WETH, USDC, ONE_WETH, USDC_1990),
settle(WETH, ONE_WETH, true),
takeAll(USDC),
),
),
left: tokenLine(WETH, "WETH"),
},
{
kind: "a swap paying WETH to the router, a WRAP_ETH of 1 ETH into the router, then a swap of 1 WETH from the router",
data: execute(
swapToWeth(ADDRESS_THIS),
wrapEth(ADDRESS_THIS, ONE_WETH),
v3SwapExactIn(
MSG_SENDER,
ONE_WETH,
USDC_1990,
WETH,
USDC,
false,
),
),
left: tokenLine(WETH, "WETH"),
},
// A SETTLE of OPEN_DELTA from the router pays only what the step // A SETTLE of OPEN_DELTA from the router pays only what the step
// still owes of its currency when it runs. // still owes of its currency when it runs.
{ {