1 Commits
Author SHA1 Message Date
sneak 060042f923 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. When the decoder does not know the SETTLE's
amount, as for CONTRACT_BALANCE, its line reads "Unknown (could not be
decoded)", also on the step that sets the input side.

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
2026-10-27 05:36:48 +00:00
+38 -38
View File
@@ -3522,44 +3522,44 @@ Currently supported:
none): one of a token other than `Token In`; one of `Token In` after an amount none): one of a token other than `Token In`; one of `Token In` after an amount
that is not a quantity (a V4 open delta, `ALREADY_PAID`, which keep their that is not a quantity (a V4 open delta, `ALREADY_PAID`, which keep their
wording on the `Amount` line, or no stated amount, as of a V4 exact-out step); wording on the `Amount` line, or no stated amount, as of a V4 exact-out step);
one of `Token In` that ETH an earlier step left in the router may pay part of; an ETH take whose line reads `Up to` (see above); and one whose amount the
and one whose amount the decoder does not know. When there is no `Amount` decoder does not know. When there is no `Amount` line, each take the total
line, each take the total counts gets them too, so that every amount the counts gets them too, so that every amount the decoder reads is shown: the
decoder reads is shown: the amount the step that sets the input side states, amount the step that sets the input side states, when it is a quantity and the
when it is a quantity and the user pays that step (a V2 or V3 step whose user pays that step (a V2 or V3 step whose `payerIsUser` is true, a V4 step
`payerIsUser` is true, a V4 step the user pays some of its input token, or a the user pays some of its input token, or a `WRAP_ETH`, whose ETH comes from
`WRAP_ETH`, whose ETH comes from the transaction's value), and each later take the transaction's value), and each later take of `Token In` added to it. A
of `Token In` added to it. A step that sets the input side gets none when the step that sets the input side gets none when the user pays it none of its
user pays it none of its input token. A `PERMIT2_PERMIT` the decoder cannot input token. A `PERMIT2_PERMIT` the decoder cannot read, then V3 exact-ins of
read, then V3 exact-ins of 600 USDT and 400 DAI paid by the user, give lines 600 USDT and 400 DAI paid by the user, give lines for both amounts. When the
for both amounts. When the step that sets the input side states no amount, the step that sets the input side states no amount, the user pays it some of its
user pays it some of its input token, and there is no `Amount` line, that step input token, and there is no `Amount` line, that step gets them too whenever
gets them too whenever another take's lines give a figure, or a another take's lines give a figure, or a `PERMIT2_TRANSFER_FROM` of its token
`PERMIT2_TRANSFER_FROM` of its token gives one, on the lines below or, into gives one, on the lines below or, into the router, on its `Paid to` line, so
the router, on its `Paid to` line, so that figure cannot read as all that that figure cannot read as all that leaves. When it states no amount and the
leaves. When it states no amount and the user pays it none of its input token, user pays it none of its input token, that step never gets them, with a permit
that step never gets them, with a permit or without. They come in step order, or without. They come in step order, except that the step that sets the input
except that the step that sets the input side comes first when it has them, side comes first when it has them, followed, when there is no `Amount` line,
followed, when there is no `Amount` line, by the other takes the total counts: by the other takes the total counts: `Moved from the sender`, its amount,
`Moved from the sender`, its amount, worded as the `Amount` line words one, or worded as the `Amount` line words one, or `Unknown (could not be decoded)`
`Unknown (could not be decoded)` when the decoder does not know it; when the decoder does not know it; `Token moved`, giving the token's address
`Token moved`, giving the token's address as the `Token In` line does; and as the `Token In` line does; and `Moved to`, which reads
`Moved to`, which reads `The swap step that spends it`. A token the decoder `The swap step that spends it`. A token the decoder does not know gives the
does not know gives the `Moved from the sender` line alone. A step may also `Moved from the sender` line alone. A step may also take from the user's
take from the user's wallet what the decoder did not read: a V4 step whose wallet what the decoder did not read: a V4 step whose input or one of whose
input or one of whose `SETTLE`s or `SETTLE_ALL`s it cannot read, which the `SETTLE`s or `SETTLE_ALL`s it cannot read, which the router still runs; a V2
router still runs; a V2 or V3 exact-in or exact-out step or a or V3 exact-in or exact-out step or a `PERMIT2_TRANSFER_FROM` whose input it
`PERMIT2_TRANSFER_FROM` whose input it cannot read, such as a V3 step whose cannot read, such as a V3 step whose path is shorter than one token address or
path is shorter than one token address or has bytes after its last hop; every has bytes after its last hop; every `PERMIT2_TRANSFER_FROM_BATCH`; every
`PERMIT2_TRANSFER_FROM_BATCH`; every `EXECUTE_SUB_PLAN`, wherever it stands; `EXECUTE_SUB_PLAN`, wherever it stands; and every step it fails on. Each such
and every step it fails on. Each such step gives one `Moved from the sender` step gives one `Moved from the sender` line among those, reading
line among those, reading `Unknown (could not be decoded)`. That line, or any `Unknown (could not be decoded)`. That line, or any line for a token the
line for a token the decoder does not know, leaves no `Amount` line, whose decoder does not know, leaves no `Amount` line, whose figure might be too low,
figure might be too low, and such a step before a `PERMIT2_PERMIT` keeps the and such a step before a `PERMIT2_PERMIT` keeps the permit's amount from
permit's amount from standing. Then each `PERMIT2_TRANSFER_FROM` but one into standing. Then each `PERMIT2_TRANSFER_FROM` but one into the router, in step
the router, in step order, gives three lines: `Moved from the sender`, the order, gives three lines: `Moved from the sender`, the amount it moves, for
amount it moves, for example `1000000.0000 USDT`; `Token moved`, giving the example `1000000.0000 USDT`; `Token moved`, giving the token's address as the
token's address as the `Token In` line does; and `Moved to`, which reads `Token In` line does; and `Moved to`, which reads
`The V2 pair the next swap spends` for a hop and `The sender` for `address(1)` `The V2 pair the next swap spends` for a hop and `The sender` for `address(1)`
on every router but `UniversalRouterV1`, and otherwise gives the address. A on every router but `UniversalRouterV1`, and otherwise gives the address. A
move into the router needs none of them, because its `Paid to` line and move into the router needs none of them, because its `Paid to` line and