fix: a permit on the zero address never reads as ETH (closes #660)
Permit2 has no allowance of ETH, but the swap decoder read the zero address in a PERMIT2_PERMIT or a batch entry as ETH. Its Allowance token line now names the zero address, as for a token nothing knows. Its amount never stands as the Amount figure, and it never counts as an allowance of Token In, so a route that pays ETH after such a permit shows that ETH. Tests cover the single permit, the batch entry and the 1-wei route. Model: opus-5-5
This commit was merged in pull request #683.
This commit is contained in:
@@ -3506,34 +3506,36 @@ Currently supported:
|
||||
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. 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
|
||||
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
|
||||
`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
|
||||
@@ -3566,30 +3568,32 @@ Currently supported:
|
||||
amount stands gives none: the `Amount` line gives its amount, `Token In` its
|
||||
token, and its spender is the router. Each allowance a `PERMIT2_PERMIT_BATCH`
|
||||
grants, one for each token it names, all for its one spender, gives the same
|
||||
three lines, in step order with those of each `PERMIT2_PERMIT`. A
|
||||
`PERMIT2_PERMIT` or `PERMIT2_PERMIT_BATCH` whose input the decoder cannot
|
||||
read, such as one whose token or spender word has a nonzero top byte, may let
|
||||
any spender take any amount of any token: it gives one `Permit2 allowance`
|
||||
line alone, reading `Unknown (could not be decoded)`. These lines change no
|
||||
`Paid to` line: a permit or batch pays nobody. But code that a step runs, such
|
||||
as a V4 pool's hook or a token's own code, can call a spender other than the
|
||||
router, which can then take up to its allowance from the user's wallet before
|
||||
the transaction ends. So an allowance to any spender but the router, or a
|
||||
permit or batch the decoder cannot read, makes the minimum read
|
||||
`Min. paid out`, and when its token is `Token In`, or the decoder does not
|
||||
know its token or `Token In`, it leaves no `Amount` line, whose figure might
|
||||
be too low: a permit of 5,000 USDT to another address and then a V3 exact-in
|
||||
of 600 USDT read with no `Amount` line, and the 600 USDT gets lines of its
|
||||
own. A step goes unread when its recipient does not decode as an address, when
|
||||
it is a V3 swap step whose path is shorter than one token address or has bytes
|
||||
after its last hop, or when it is a command the decoder does not read: every
|
||||
command other than `PERMIT2_PERMIT`, `PERMIT2_PERMIT_BATCH`,
|
||||
`PERMIT2_TRANSFER_FROM`, `V2_SWAP_EXACT_IN`, `V2_SWAP_EXACT_OUT`,
|
||||
`V3_SWAP_EXACT_IN`, `V3_SWAP_EXACT_OUT`, `V4_SWAP`, `SWEEP`, `TRANSFER`,
|
||||
`PAY_PORTION`, `PAY_PORTION_FULL_PRECISION`, `ACROSS_V4_DEPOSIT_V3`,
|
||||
`WRAP_ETH`, `UNWRAP_WETH` and `BALANCE_CHECK_ERC20`
|
||||
(`PERMIT2_TRANSFER_FROM_BATCH`, `EXECUTE_SUB_PLAN` and the NFT commands among
|
||||
them), or a type its release names no command for.
|
||||
three lines, in step order with those of each `PERMIT2_PERMIT`. For an
|
||||
allowance of the zero address, `Permit2 allowance` gives the amount in base
|
||||
units and `Allowance token` gives the zero address. A `PERMIT2_PERMIT` or
|
||||
`PERMIT2_PERMIT_BATCH` whose input the decoder cannot read, such as one whose
|
||||
token or spender word has a nonzero top byte, may let any spender take any
|
||||
amount of any token: it gives one `Permit2 allowance` line alone, reading
|
||||
`Unknown (could not be decoded)`. These lines change no `Paid to` line: a
|
||||
permit or batch pays nobody. But code that a step runs, such as a V4 pool's
|
||||
hook or a token's own code, can call a spender other than the router, which
|
||||
can then take up to its allowance from the user's wallet before the
|
||||
transaction ends. So an allowance to any spender but the router, or a permit
|
||||
or batch the decoder cannot read, makes the minimum read `Min. paid out`, and
|
||||
when its token is `Token In`, or the decoder does not know its token or
|
||||
`Token In`, it leaves no `Amount` line, whose figure might be too low: a
|
||||
permit of 5,000 USDT to another address and then a V3 exact-in of 600 USDT
|
||||
read with no `Amount` line, and the 600 USDT gets lines of its own. A step
|
||||
goes unread when its recipient does not decode as an address, when it is a V3
|
||||
swap step whose path is shorter than one token address or has bytes after its
|
||||
last hop, or when it is a command the decoder does not read: every command
|
||||
other than `PERMIT2_PERMIT`, `PERMIT2_PERMIT_BATCH`, `PERMIT2_TRANSFER_FROM`,
|
||||
`V2_SWAP_EXACT_IN`, `V2_SWAP_EXACT_OUT`, `V3_SWAP_EXACT_IN`,
|
||||
`V3_SWAP_EXACT_OUT`, `V4_SWAP`, `SWEEP`, `TRANSFER`, `PAY_PORTION`,
|
||||
`PAY_PORTION_FULL_PRECISION`, `ACROSS_V4_DEPOSIT_V3`, `WRAP_ETH`,
|
||||
`UNWRAP_WETH` and `BALANCE_CHECK_ERC20` (`PERMIT2_TRANSFER_FROM_BATCH`,
|
||||
`EXECUTE_SUB_PLAN` and the NFT commands among them), or a type its release
|
||||
names no command for.
|
||||
|
||||
### Non-Goals Forever
|
||||
|
||||
|
||||
Reference in New Issue
Block a user