fix: a V4 SETTLE of ETH paid from the router reads as moved from the sender (closes #682)
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
This commit is contained in:
@@ -3477,65 +3477,71 @@ Currently supported:
|
||||
of any amount but `OPEN_DELTA` pays that amount, and a `SETTLE` of
|
||||
`OPEN_DELTA` or a `SETTLE_ALL` pays what the step owes, as above. So a V4 step
|
||||
that swaps 400 USDT, with a `SETTLE` of 5,000 USDT paid by the user and the
|
||||
rest taken to another address, reads `5000.0000 USDT`. A later step paid from
|
||||
the router spends what the router holds and takes nothing, and so does a V2
|
||||
exact-in whose `amountIn` is `ALREADY_PAID`. A later take of `Token In` is
|
||||
added to the total while both are quantities: a V3 exact-in of 600 USDT and a
|
||||
V2 exact-in of 400 USDT, both paid by the user, read `1000.0000 USDT`. When
|
||||
the decoder does not know a take's amount, the total is not known and there is
|
||||
no `Amount` line. A `PERMIT2_PERMIT` names `Token In` only when its amount,
|
||||
`Unlimited` included, stands as the `Amount` figure in place of the total,
|
||||
which it does only in the plain shape of Uniswap's own routes: it comes before
|
||||
the step that sets the input side, it is the only `PERMIT2_PERMIT` in the
|
||||
transaction and there is no `PERMIT2_PERMIT_BATCH`, its spender is the router,
|
||||
the router may not let it fail, no step before it takes its token, a
|
||||
`PERMIT2_TRANSFER_FROM` of it included, or a token the decoder does not know,
|
||||
and the decoder reads every step after it in full. Permit2 then lets the
|
||||
router take no more of the token than that amount, so the permit covers every
|
||||
take of it. A step before the permit takes under whatever allowance the router
|
||||
already had, so it may take more than the permit's amount, which would then
|
||||
read lower than what leaves the user's wallet: a `PERMIT2_TRANSFER_FROM` of
|
||||
2,000 USDT into the router, then a permit of 600 USDT to the router and a V3
|
||||
exact-in of 2,000 USDT paid from the router, read `Amount 2000.0000 USDT`. A
|
||||
later permit or batch may raise what Permit2 lets the router take, and so may
|
||||
a step the decoder does not read in full: a command the decoder does not read
|
||||
(listed at the end of this section), a step whose input it cannot read, in
|
||||
whole or in part, and a step it fails on. Every other `PERMIT2_PERMIT`, before
|
||||
the step that sets the input side or after it, leaves `Token In` and the
|
||||
`Amount` line as they read with no permit, unless it lets a spender other than
|
||||
the router take `Token In` (see below): a permit of 5,000 DAI to another
|
||||
address and then a V3 exact-in of 600 USDT read `Swap USDT → USDC` with
|
||||
`Amount 600.0000 USDT`, and so do that exact-in and then a permit of 5,000 DAI
|
||||
to the router. A permit on the zero address never stands as the `Amount`
|
||||
figure, because Permit2 has no allowance of ETH. When a permit's amount stands
|
||||
and the step that sets the input side spends a token other than the permit's,
|
||||
or one the decoder does not know, that step's amount gets lines of its own,
|
||||
unless it states no amount and the user pays it none of its input token. Each
|
||||
take the total does not count gives three lines after the `Amount` line (after
|
||||
`Token In` when there is 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 wording on the `Amount` line, or no stated
|
||||
amount, as of a V4 exact-out step); and one whose amount the decoder does not
|
||||
know. When there is no `Amount` line, each take the total counts gets them
|
||||
too, so that every amount the decoder reads is shown: the amount the step that
|
||||
sets the input side states, when it is a quantity and the user pays that step
|
||||
(a V2 or V3 step whose `payerIsUser` is true, a V4 step the user pays some of
|
||||
its input token, or a `WRAP_ETH`, whose ETH comes from the transaction's
|
||||
value), and each later take of `Token In` added to it. A step that sets the
|
||||
input side and is paid from the router takes nothing from the user's wallet
|
||||
and gets none. A `PERMIT2_PERMIT` the decoder cannot read, then V3 exact-ins
|
||||
of 600 USDT and 400 DAI paid by the user, give lines for both amounts. When
|
||||
the step that sets the input side states no amount, the user pays it some of
|
||||
its input token, and there is no `Amount` line, that step gets them too
|
||||
whenever another take's lines give a figure, or a `PERMIT2_TRANSFER_FROM` of
|
||||
its token gives one, on the lines below or, into the router, on its `Paid to`
|
||||
line, so that figure cannot read as all that leaves. When it states no amount
|
||||
and the user pays it none of its input token, as when the router pays it, that
|
||||
step takes none of that token from the user's wallet and never gets them, with
|
||||
a permit or without. They come in step order, except that the step that sets
|
||||
the input side comes first when it has them, followed, when there is no
|
||||
`Amount` line, by the other takes the total counts: `Moved from the sender`,
|
||||
its amount, worded as the `Amount` line words one, or
|
||||
rest taken to another address, reads `5000.0000 USDT`. A later step that pays
|
||||
an ERC-20 token from the router takes none of that token from the user's
|
||||
wallet. A V2 exact-in whose `amountIn` is `ALREADY_PAID` takes nothing either.
|
||||
A V4 `SETTLE` of ETH paid from the router still takes from the user's wallet,
|
||||
since the router holds the transaction's value. When the decoder does not know
|
||||
the amount of such a `SETTLE`, as for `CONTRACT_BALANCE`, that `SETTLE` counts
|
||||
as a later step's take. When an earlier step left ETH in the router, that ETH
|
||||
may pay part of a `SETTLE` of ETH paid from the router. That `SETTLE` then
|
||||
gets lines of its own, with `Up to` before its amount. A later take of
|
||||
`Token In` that only the user's wallet pays is added to the total while both
|
||||
are quantities: a V3 exact-in of 600 USDT and a V2 exact-in of 400 USDT, both
|
||||
paid by the user, read `1000.0000 USDT`. When the decoder does not know a
|
||||
take's amount, the total is not known and there is no `Amount` line. A
|
||||
`PERMIT2_PERMIT` names `Token In` only when its amount, `Unlimited` included,
|
||||
stands as the `Amount` figure in place of the total, which it does only in the
|
||||
plain shape of Uniswap's own routes: it comes before the step that sets the
|
||||
input side, it is the only `PERMIT2_PERMIT` in the transaction and there is no
|
||||
`PERMIT2_PERMIT_BATCH`, its spender is the router, the router may not let it
|
||||
fail, no step before it takes its token, a `PERMIT2_TRANSFER_FROM` of it
|
||||
included, or a token the decoder does not know, and the decoder reads every
|
||||
step after it in full. Permit2 then lets the router take no more of the token
|
||||
than that amount, so the permit covers every take of it. A step before the
|
||||
permit takes under whatever allowance the router already had, so it may take
|
||||
more than the permit's amount, which would then read lower than what leaves
|
||||
the user's wallet: a `PERMIT2_TRANSFER_FROM` of 2,000 USDT into the router,
|
||||
then a permit of 600 USDT to the router and a V3 exact-in of 2,000 USDT paid
|
||||
from the router, read `Amount 2000.0000 USDT`. A later permit or batch may
|
||||
raise what Permit2 lets the router take, and so may a step the decoder does
|
||||
not read in full: a command the decoder does not read (listed at the end of
|
||||
this section), a step whose input it cannot read, in whole or in part, and a
|
||||
step it fails on. Every other `PERMIT2_PERMIT`, before the step that sets the
|
||||
input side or after it, leaves `Token In` and the `Amount` line as they read
|
||||
with no permit, unless it lets a spender other than the router take `Token In`
|
||||
(see below): a permit of 5,000 DAI to another address and then a V3 exact-in
|
||||
of 600 USDT read `Swap USDT → USDC` with `Amount 600.0000 USDT`, and so do
|
||||
that exact-in and then a permit of 5,000 DAI to the router. A permit on the
|
||||
zero address never stands as the `Amount` figure, because Permit2 has no
|
||||
allowance of ETH. When a permit's amount stands and the step that sets the
|
||||
input side spends a token other than the permit's, or one the decoder does not
|
||||
know, that step's amount gets lines of its own, unless it states no amount and
|
||||
the user pays it none of its input token. Each take the total does not count
|
||||
gives three lines after the `Amount` line (after `Token In` when there is
|
||||
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
|
||||
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;
|
||||
and one whose amount the decoder does not know. When there is no `Amount`
|
||||
line, each take the total counts gets them too, so that every amount the
|
||||
decoder reads is shown: the amount the step that sets the input side states,
|
||||
when it is a quantity and the user pays that step (a V2 or V3 step whose
|
||||
`payerIsUser` is true, a V4 step the user pays some of its input token, or a
|
||||
`WRAP_ETH`, whose ETH comes from the transaction's value), and each later take
|
||||
of `Token In` added to it. A step that sets the input side gets none when the
|
||||
user pays it none of its input token. A `PERMIT2_PERMIT` the decoder cannot
|
||||
read, then V3 exact-ins of 600 USDT and 400 DAI paid by the user, give lines
|
||||
for both amounts. When the step that sets the input side states no amount, the
|
||||
user pays it some of its input token, and there is no `Amount` line, that step
|
||||
gets them too whenever another take's lines give a figure, or a
|
||||
`PERMIT2_TRANSFER_FROM` of its token gives one, on the lines below or, into
|
||||
the router, on its `Paid to` line, so that figure cannot read as all that
|
||||
leaves. When it states no amount and the user pays it none of its input token,
|
||||
that step never gets them, with a permit or without. They come in step order,
|
||||
except that the step that sets the input side comes first when it has them,
|
||||
followed, when there is no `Amount` line, by the other takes the total counts:
|
||||
`Moved from the sender`, its amount, worded as the `Amount` line words one, or
|
||||
`Unknown (could not be decoded)` when the decoder does not know it;
|
||||
`Token moved`, giving the token's address as the `Token In` line does; and
|
||||
`Moved to`, which reads `The swap step that spends it`. A token the decoder
|
||||
|
||||
Reference in New Issue
Block a user