fix: each PERMIT2_TRANSFER_FROM shows the amount it moves and where to (closes #611)
The swap decoder now gives three lines for every PERMIT2_TRANSFER_FROM it reads but a move into the router, after the swap's Amount line: the amount moved from the sender, the token with its address, and where it goes (the V2 pair the next swap spends, the sender, or the address itself on a line of its own). A move into the router keeps its Paid to and Token moved into the router lines, which already give its amount. Before, a move to another address or to the next V2 pair showed no amount at all. Who counts as paid, and so Min. received against Min. paid out, is unchanged. tokenMovedLine() moves to module level and takes its label as an argument. Model: opus-5-5
This commit was merged in pull request #620.
This commit is contained in:
+66
-21
@@ -488,6 +488,21 @@ function amountText(raw, info) {
|
||||
};
|
||||
}
|
||||
|
||||
// The line giving a moved token under `label`, in the shape of the Token In
|
||||
// line, so the screens show it as they show that one. ETH has no address.
|
||||
function tokenMovedLine(label, token, sources) {
|
||||
const info = tokenInfo(token, sources);
|
||||
if (!present(info.address)) {
|
||||
return { label, value: info.symbol };
|
||||
}
|
||||
return {
|
||||
label,
|
||||
value: info.symbol ? info.symbol + " (" + token + ")" : token,
|
||||
address: token,
|
||||
isToken: true,
|
||||
};
|
||||
}
|
||||
|
||||
// Decode PERMIT2_PERMIT (command 0x0a) input bytes.
|
||||
// ABI: ((address token, uint160 amount, uint48 expiration, uint48 nonce),
|
||||
// address spender, uint256 sigDeadline), bytes signature
|
||||
@@ -1171,6 +1186,13 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
||||
// router, as { token, amount }. Later steps may leave part of it
|
||||
// there: nothing here checks that they spend all of it.
|
||||
const movedIntoRouter = [];
|
||||
// What each PERMIT2_TRANSFER_FROM not into the router moves from the
|
||||
// sender, in step order, whoever counts as paid, as
|
||||
// { token, recipient, amount, to }: `to` says where it goes, the
|
||||
// sender or the V2 pair the next swap spends, and is null when it
|
||||
// goes to `recipient` as written. A move into the router is in
|
||||
// `movedIntoRouter`, whose lines give its amount already.
|
||||
const movedFromSender = [];
|
||||
// Each token a step paid to the router that no later step paid out
|
||||
// or spent in full, by its address, lowercased, ETH as the zero
|
||||
// address. The router is paid what a swap step, V4 TAKE or
|
||||
@@ -1302,10 +1324,23 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
||||
// pays address(1) and address(2) as written (see
|
||||
// decodePermit2TransferFrom()).
|
||||
addPaidElsewhere(p.recipient);
|
||||
movedFromSender.push({ ...p, to: null });
|
||||
} else if (isRouter(p.recipient)) {
|
||||
movedIntoRouter.push(p);
|
||||
} else if (!isHop(i, p.token, p.recipient)) {
|
||||
} else if (isHop(i, p.token, p.recipient)) {
|
||||
movedFromSender.push({
|
||||
...p,
|
||||
to: "The V2 pair the next swap spends",
|
||||
});
|
||||
} else {
|
||||
addPayee(p.recipient);
|
||||
movedFromSender.push({
|
||||
...p,
|
||||
to:
|
||||
p.recipient.toLowerCase() === MSG_SENDER
|
||||
? "The sender"
|
||||
: null,
|
||||
});
|
||||
}
|
||||
} else if (command === "BALANCE_CHECK_ERC20") {
|
||||
const b = decodeBalanceCheck(inputs[i]);
|
||||
@@ -1675,6 +1710,26 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
||||
});
|
||||
}
|
||||
|
||||
// What each PERMIT2_TRANSFER_FROM moves: its amount, its token and
|
||||
// where it goes, an address on a line of its own.
|
||||
for (const m of movedFromSender) {
|
||||
details.push({
|
||||
label: "Moved from the sender",
|
||||
value: amountText(m.amount, tokenInfo(m.token, sources))
|
||||
.display,
|
||||
});
|
||||
details.push(tokenMovedLine("Token moved", m.token, sources));
|
||||
details.push(
|
||||
present(m.to)
|
||||
? { label: "Moved to", value: m.to }
|
||||
: {
|
||||
label: "Moved to",
|
||||
value: m.recipient,
|
||||
address: m.recipient,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Keyed on the address, not the symbol: a token absent from the
|
||||
// bundled list has no symbol, and gating the line on one dropped it
|
||||
// entirely, leaving a Min. received figure with nothing saying what is
|
||||
@@ -1723,24 +1778,6 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
||||
if (bridgeDeposit) {
|
||||
paidTo.push({ label: "Paid to", value: PAID_TO_BRIDGE });
|
||||
}
|
||||
// The line giving a token in the router, in the shape of the Token In
|
||||
// line, so the screens show it as they show that one. ETH has no
|
||||
// address.
|
||||
const tokenMovedLine = (token) => {
|
||||
const info = tokenInfo(token, sources);
|
||||
if (!present(info.address)) {
|
||||
return {
|
||||
label: "Token moved into the router",
|
||||
value: info.symbol,
|
||||
};
|
||||
}
|
||||
return {
|
||||
label: "Token moved into the router",
|
||||
value: info.symbol ? info.symbol + " (" + token + ")" : token,
|
||||
address: token,
|
||||
isToken: true,
|
||||
};
|
||||
};
|
||||
for (const m of movedIntoRouter) {
|
||||
const info = tokenInfo(m.token, sources);
|
||||
paidTo.push({
|
||||
@@ -1750,7 +1787,9 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
||||
amountText(m.amount, info).display +
|
||||
" from the sender (later steps may not spend all of it)",
|
||||
});
|
||||
paidTo.push(tokenMovedLine(m.token));
|
||||
paidTo.push(
|
||||
tokenMovedLine("Token moved into the router", m.token, sources),
|
||||
);
|
||||
}
|
||||
if (outputHeld) {
|
||||
paidTo.push({ label: "Paid to", value: STAYS_IN_ROUTER });
|
||||
@@ -1764,7 +1803,13 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
||||
continue;
|
||||
}
|
||||
paidTo.push({ label: "Paid to", value: STAYS_IN_ROUTER });
|
||||
paidTo.push(tokenMovedLine(getAddress(token)));
|
||||
paidTo.push(
|
||||
tokenMovedLine(
|
||||
"Token moved into the router",
|
||||
getAddress(token),
|
||||
sources,
|
||||
),
|
||||
);
|
||||
}
|
||||
if (payeeUnread) {
|
||||
paidTo.push({ label: "Paid to", value: UNDECODED_CURRENCY });
|
||||
|
||||
Reference in New Issue
Block a user