fix: a PERMIT2_TRANSFER_FROM shows the swap's unknown first take beside its figure (closes #634)
When the step that sets the input side states no amount, a PERMIT2_TRANSFER_FROM of the same token still showed its own figure, which was then the only amount of that token on the screen. The rule that adds the line saying the first take is not known now also applies when such a move gives a figure of that token, before or after the swap step. A move of another token, and a move into the router, read as before. Model: opus-5-5
This commit is contained in:
@@ -3195,9 +3195,10 @@ Currently supported:
|
||||
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 and there is no
|
||||
`Amount` line, that step gets them too whenever another take's lines give a
|
||||
figure, so that figure cannot read as all that leaves. 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
|
||||
figure, or a `PERMIT2_TRANSFER_FROM` of its token gets the lines below, so
|
||||
that figure cannot read as all that leaves. 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
|
||||
|
||||
@@ -1873,14 +1873,18 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
||||
if (ofTokenIn && !present(t.amount)) total = null;
|
||||
}
|
||||
inputAmount = permitStands ? permit.amount : total;
|
||||
// With no Amount figure, a later take's own figure could read as all
|
||||
// that leaves, so the step that set the input side, when it stated
|
||||
// no amount, then gets lines of its own too, first, saying its amount
|
||||
// With no Amount figure, a later take's own figure, or that of a
|
||||
// PERMIT2_TRANSFER_FROM of the same token, could read as all that
|
||||
// leaves, so the step that set the input side, when it stated no
|
||||
// amount, then gets lines of its own too, first, saying its amount
|
||||
// is not known.
|
||||
if (
|
||||
!present(inputAmount) &&
|
||||
firstTakeUnstated !== null &&
|
||||
spentFromSender.some((s) => present(s.amount))
|
||||
(spentFromSender.some((s) => present(s.amount)) ||
|
||||
movedFromSender.some((m) =>
|
||||
sameAddress(m.token, firstTakeUnstated.token),
|
||||
))
|
||||
) {
|
||||
spentFromSender.unshift(firstTakeUnstated);
|
||||
}
|
||||
|
||||
@@ -2423,6 +2423,56 @@ describe("uniswap decoder", () => {
|
||||
},
|
||||
);
|
||||
|
||||
// https://git.eeqj.de/sneak/AutistMask/issues/634 — a
|
||||
// PERMIT2_TRANSFER_FROM of the token the V4 exact-out step spends,
|
||||
// before or after it, shows its own figure, so the step's amount is
|
||||
// shown as not known beside it, and the 400 USDT cannot read as all
|
||||
// that leaves. On next only the 400 USDT was shown.
|
||||
const transferTo = (token, amount) =>
|
||||
coder.encode(
|
||||
["address", "address", "uint160"],
|
||||
[token, OTHER_ADDR, amount],
|
||||
);
|
||||
const MOVED_400_USDT = [
|
||||
["Moved from the sender", "400.0000 USDT"],
|
||||
["Token moved", "USDT (" + USDT_ADDR + ")"],
|
||||
["Moved to", OTHER_ADDR],
|
||||
];
|
||||
test.each([
|
||||
{
|
||||
kind: "a V4 exact-out step of at most 600 USDT, then a PERMIT2_TRANSFER_FROM of 400 USDT to another address",
|
||||
commands: [0x10, 0x02],
|
||||
inputs: [V4_EXACT_OUT_600, transferTo(USDT_ADDR, USDT_400)],
|
||||
},
|
||||
{
|
||||
kind: "a PERMIT2_TRANSFER_FROM of 400 USDT to another address, then a V4 exact-out step of at most 600 USDT",
|
||||
commands: [0x02, 0x10],
|
||||
inputs: [transferTo(USDT_ADDR, USDT_400), V4_EXACT_OUT_600],
|
||||
},
|
||||
])(
|
||||
"$kind, paid by the user, shows that the step's amount is not known",
|
||||
({ commands, inputs }) => {
|
||||
const result = decodeSteps(commands, inputs);
|
||||
expect(linesBetweenTokens(result)).toEqual([
|
||||
...UNKNOWN_USDT,
|
||||
...MOVED_400_USDT,
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
// A move of another token says nothing of how much USDT leaves.
|
||||
test("a V4 exact-out step of at most 600 USDT, then a PERMIT2_TRANSFER_FROM of 400 DAI, shows only the DAI moved", () => {
|
||||
const result = decodeSteps(
|
||||
[0x10, 0x02],
|
||||
[V4_EXACT_OUT_600, transferTo(DAI_ADDR, DAI_400)],
|
||||
);
|
||||
expect(linesBetweenTokens(result)).toEqual([
|
||||
["Moved from the sender", "400.0000 DAI"],
|
||||
["Token moved", "DAI (" + DAI_ADDR + ")"],
|
||||
["Moved to", OTHER_ADDR],
|
||||
]);
|
||||
});
|
||||
|
||||
// A V2 exact-out step makes every amount the swap steps spend a maximum,
|
||||
// the total included.
|
||||
test("a split with a V2 exact-out step the user pays for shows the total as a maximum", () => {
|
||||
|
||||
Reference in New Issue
Block a user