fix: a swap's unknown first take shows beside a PERMIT2_TRANSFER_FROM, only when the user pays it (closes #634)
decode() now records whether the user pays the V4 step that sets the input side any of its input token, and decides once, after the loop, whether that step counts as a take from the sender. A stated amount counts whoever pays it; with none stated, the step counts only when the user pays it. Paid from the router, it gets no Moved from the sender lines, with a PERMIT2_PERMIT of another token or without. When it counts and states no amount, its Unknown (could not be decoded) line also shows beside a PERMIT2_TRANSFER_FROM of its token, whose figure is on that move's own lines or, into the router, on its Paid to line. README Transaction Decoding says the same. Model: opus-5-5
This commit was merged in pull request #639.
This commit is contained in:
+23
-7
@@ -1204,6 +1204,10 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
||||
let inputToken = null;
|
||||
let inputAmount = null;
|
||||
let inputEstablished = false;
|
||||
// Whether the user pays the V4 step that set the input side any of
|
||||
// its input currency (see decodeV4Swap()). Only a V4 step can set the
|
||||
// input side with no amount, the one case in which this is read.
|
||||
let inputPaidByUser = false;
|
||||
// The last PERMIT2_PERMIT this decoder read, or null (see
|
||||
// permitStands after the loop).
|
||||
let permit = null;
|
||||
@@ -1756,6 +1760,7 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
||||
// this decoder could not read may take anything: the
|
||||
// router still runs it.
|
||||
const setInputHere = inputEstablished && !inputSetBefore;
|
||||
if (setInputHere) inputPaidByUser = paidIn !== undefined;
|
||||
if (v4) {
|
||||
for (const p of v4.paidByUser) {
|
||||
if (setInputHere && p === paidIn) continue;
|
||||
@@ -1844,15 +1849,22 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
||||
// (see spentUnread()), or a token it does not know.
|
||||
const spentFromSender = [];
|
||||
let total = null;
|
||||
// Whether the step that set the input side counts as a take from the
|
||||
// sender, which may get lines of its own. The amount it stated counts
|
||||
// whoever pays it. Stating none, it counts only when the user pays it
|
||||
// some of its input token: paid from the router, it takes nothing
|
||||
// from the sender.
|
||||
const hasFirstTake =
|
||||
inputEstablished && (present(inputAmount) || inputPaidByUser);
|
||||
// The take of the step that set the input side, when the total
|
||||
// starts from it and it stated no amount (see below), or null.
|
||||
let firstTakeUnstated = null;
|
||||
if (permit === null || sameAddress(inputToken, permit.token)) {
|
||||
total = inputAmount;
|
||||
if (inputEstablished && !present(inputAmount)) {
|
||||
if (hasFirstTake && !present(inputAmount)) {
|
||||
firstTakeUnstated = { token: inputToken, amount: null };
|
||||
}
|
||||
} else if (inputEstablished) {
|
||||
} else if (hasFirstTake) {
|
||||
// The step that set the input side spent a token other than the
|
||||
// permit's, or one not known, so the total starts with no figure.
|
||||
spentFromSender.push({ token: inputToken, amount: inputAmount });
|
||||
@@ -1873,14 +1885,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
|
||||
// is not known.
|
||||
// With no Amount figure, a later take's own figure, or that of a
|
||||
// PERMIT2_TRANSFER_FROM of the same token, into the router or not,
|
||||
// could read as all that leaves, so the step that set the input side,
|
||||
// when the user pays it and 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, ...movedIntoRouter].some((m) =>
|
||||
sameAddress(m.token, firstTakeUnstated.token),
|
||||
))
|
||||
) {
|
||||
spentFromSender.unshift(firstTakeUnstated);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user