fix: a PERMIT2_PERMIT_BATCH, and a permit that cannot be read, state what they allow (closes #652)
check / check (push) Canceled after 0s
e2e / e2e-chrome (push) Canceled after 0s
e2e / e2e-firefox (push) Canceled after 0s

A PERMIT2_PERMIT_BATCH was never read, and a PERMIT2_PERMIT whose input
could not be read got no lines, so the approval screen showed nothing of
the allowances either grants.

Each allowance of a batch now gets the three lines a permit whose amount
does not stand gets: Permit2 allowance, Allowance token and Allowance
spender. A permit or batch that cannot be read gets one Permit2 allowance
line reading Unknown (could not be decoded) and leaves no Amount line.
Any batch in the transaction keeps a PERMIT2_PERMIT's amount from
standing. A batch pays nobody, so it no longer adds a Paid to line.
README Transaction Decoding and the TxApproval element list match.

Model: opus-5-5
This commit was merged in pull request #656.
This commit is contained in:
2026-10-21 01:41:35 +02:00
parent 45aead6340
commit f53b503b15
3 changed files with 292 additions and 94 deletions
+57 -47
View File
@@ -2428,10 +2428,11 @@ view would leave a wallet one click from deletion.
- Decoded action (if calldata is recognized): action name, token details,
amounts, what each swap step spends that the `Amount` line does not give,
what each `PERMIT2_TRANSFER_FROM` moves and where to, what each
`PERMIT2_PERMIT` whose amount is not the `Amount` figure lets its spender
take, steps, deadline, and unless a swap pays only the From address, a
`Paid to` line for each other address it pays, or saying that a token
stays in the router or who it pays is unknown (see Transaction Decoding)
`PERMIT2_PERMIT` whose amount is not the `Amount` figure, and each
`PERMIT2_PERMIT_BATCH`, lets its spender take, steps, deadline, and unless
a swap pays only the From address, a `Paid to` line for each other address
it pays, or saying that a token stays in the router or who it pays is
unknown (see Transaction Decoding)
- From: color dot + full address + etherscan link
- Contract: color dot + full address + etherscan link, token symbol label if
known; for a contract creation, the same sentence as on WaitTx
@@ -3224,38 +3225,39 @@ Currently supported:
`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, its spender is the router, the router may not let it fail, no
step before it takes its token 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 the decoder does not read in full may raise what Permit2 lets the
router take, as a `PERMIT2_PERMIT_BATCH` can: 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: 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 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, the step that sets the input side first when
it has them: `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
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 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 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:
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 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, the step that
sets the input side first when it has them: `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
does not know gives the `Moved from the sender` line alone. A step may also
take from the user's wallet what the decoder did not read: a V4 step whose
@@ -3284,17 +3286,25 @@ Currently supported:
giving the token's address as the `Token In` line does; and
`Allowance spender`, the address it lets take the token. Only a permit whose
amount stands gives none: the `Amount` line gives its amount, `Token In` its
token, and its spender is the router. These lines change neither the `Paid to`
lines nor the minimum's label. 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_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.
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)`, and leaves no `Amount`
line, whose figure might be too low. These lines change neither the `Paid to`
lines nor the minimum's label: a permit or batch pays nobody. 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