Compare commits
1
Commits
next
...
5dc24d2d57
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5dc24d2d57 |
@@ -1416,8 +1416,10 @@ when both tokens are known. The lines are:
|
|||||||
after the step that sets `Token In` takes the amount it states from the
|
after the step that sets `Token In` takes the amount it states from the
|
||||||
sender. When it pays anyone but the router, that amount gets these lines. When
|
sender. When it pays anyone but the router, that amount gets these lines. When
|
||||||
it pays the router, that amount joins the `Amount` line if `Token In` is ETH,
|
it pays the router, that amount joins the `Amount` line if `Token In` is ETH,
|
||||||
and gets these lines if not. A later `WRAP_ETH` of `CONTRACT_BALANCE` states
|
and gets these lines if not. A later `WRAP_ETH` of `CONTRACT_BALANCE` to
|
||||||
no amount, so it gets no lines. ETH that the sender pays a V4 step or a
|
anyone but the router gets these lines, unless an earlier step paid ETH to the
|
||||||
|
router. Its `Moved from the sender` line reads
|
||||||
|
`All the ETH the transaction carries`. ETH that the sender pays a V4 step or a
|
||||||
`WRAP_ETH` of a stated amount can get these three lines when the router may
|
`WRAP_ETH` of a stated amount can get these three lines when the router may
|
||||||
hold ETH from an earlier step. When the decoder knows the amount, its
|
hold ETH from an earlier step. When the decoder knows the amount, its
|
||||||
`Moved from the sender` line reads `Up to` and the amount.
|
`Moved from the sender` line reads `Up to` and the amount.
|
||||||
|
|||||||
+90
-31
@@ -404,6 +404,11 @@ const OPEN_DELTA = Symbol("v4-open-delta");
|
|||||||
// that nothing is swapped.
|
// that nothing is swapped.
|
||||||
const ALREADY_PAID = Symbol("v2-already-paid");
|
const ALREADY_PAID = Symbol("v2-already-paid");
|
||||||
|
|
||||||
|
// A later WRAP_ETH of CONTRACT_BALANCE wraps all the ETH the router holds, and
|
||||||
|
// so all the ETH the transaction carries. The calldata states no quantity for
|
||||||
|
// it. The approval screen's Value line gives that ETH.
|
||||||
|
const TRANSACTION_ETH = Symbol("transaction-eth");
|
||||||
|
|
||||||
// The router's whole-balance amount, universal-router
|
// The router's whole-balance amount, universal-router
|
||||||
// `ActionConstants.CONTRACT_BALANCE`: a V2 exact-in given it as `amountIn`
|
// `ActionConstants.CONTRACT_BALANCE`: a V2 exact-in given it as `amountIn`
|
||||||
// pays the pair all the router holds of the input token.
|
// pays the pair all the router holds of the input token.
|
||||||
@@ -416,6 +421,7 @@ const CONTRACT_BALANCE = 2n ** 255n;
|
|||||||
const OPEN_DELTA_AMOUNT = "All available (V4 open delta)";
|
const OPEN_DELTA_AMOUNT = "All available (V4 open delta)";
|
||||||
const ALREADY_PAID_AMOUNT =
|
const ALREADY_PAID_AMOUNT =
|
||||||
"Whatever an earlier step sent to the pair (V2 already paid)";
|
"Whatever an earlier step sent to the pair (V2 already paid)";
|
||||||
|
const TRANSACTION_ETH_AMOUNT = "All the ETH the transaction carries";
|
||||||
const NO_MINIMUM = "None (no minimum guaranteed)";
|
const NO_MINIMUM = "None (no minimum guaranteed)";
|
||||||
|
|
||||||
// Permit2 amounts are uint160; the maximum is Permit2's "unbounded".
|
// Permit2 amounts are uint160; the maximum is Permit2's "unbounded".
|
||||||
@@ -1271,6 +1277,8 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
// when it is not the router; otherwise null. That WRAP_ETH pays its
|
// when it is not the router; otherwise null. That WRAP_ETH pays its
|
||||||
// WETH there, not to a swap step (see the Moved to lines).
|
// WETH there, not to a swap step (see the Moved to lines).
|
||||||
let wrapEthRecipient = null;
|
let wrapEthRecipient = null;
|
||||||
|
// The index of the WRAP_ETH that set the input side, or null.
|
||||||
|
let wrapEthStep = null;
|
||||||
// The last PERMIT2_PERMIT this decoder read before a step set the
|
// The last PERMIT2_PERMIT this decoder read before a step set the
|
||||||
// input side, or null (see permitStands after the loop).
|
// input side, or null (see permitStands after the loop).
|
||||||
let permit = null;
|
let permit = null;
|
||||||
@@ -1289,6 +1297,9 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
let minOutput = null;
|
let minOutput = null;
|
||||||
let outputEstablished = false;
|
let outputEstablished = false;
|
||||||
let hasUnwrapWeth = false;
|
let hasUnwrapWeth = false;
|
||||||
|
// Set once an UNWRAP_WETH pays ETH to the router, which a later
|
||||||
|
// WRAP_ETH of CONTRACT_BALANCE then wraps.
|
||||||
|
let unwrappedIntoRouter = false;
|
||||||
// Set when an UNWRAP_WETH pays out, as ETH, the output side's WETH,
|
// Set when an UNWRAP_WETH pays out, as ETH, the output side's WETH,
|
||||||
// which the router holds; cleared whenever the output side is set
|
// which the router holds; cleared whenever the output side is set
|
||||||
// again, or a later step may pay that ETH out as WETH (see after the
|
// again, or a later step may pay that ETH out as WETH (see after the
|
||||||
@@ -1308,6 +1319,10 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
// other than WETH, and not of ETH to a WETH contract, which pays the
|
// other than WETH, and not of ETH to a WETH contract, which pays the
|
||||||
// router WETH (see keepsRouterWeth in the loop). None of those can.
|
// router WETH (see keepsRouterWeth in the loop). None of those can.
|
||||||
let lastWethStep = -1;
|
let lastWethStep = -1;
|
||||||
|
// The index of the last swap step paid from WETH the router holds, a
|
||||||
|
// V4 SETTLE included, or -1 (see spendFromRouter()). Only such a step
|
||||||
|
// spends the WETH of an earlier WRAP_ETH into the router.
|
||||||
|
let lastRouterWethSwapStep = -1;
|
||||||
// Where the step that set the output side paid its output: the
|
// Where the step that set the output side paid its output: the
|
||||||
// recipient of a swap step, as written, or of each TAKE, TAKE_ALL and
|
// recipient of a swap step, as written, or of each TAKE, TAKE_ALL and
|
||||||
// TAKE_PORTION of it in a V4 step, a TAKE_ALL as paid to the sender,
|
// TAKE_PORTION of it in a V4 step, a TAKE_ALL as paid to the sender,
|
||||||
@@ -1370,7 +1385,9 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
// `amount`: it never joins the Amount line, and its line reads
|
// `amount`: it never joins the Amount line, and its line reads
|
||||||
// "Up to" and the amount. A take with a `recipient`, the ETH of a
|
// "Up to" and the amount. A take with a `recipient`, the ETH of a
|
||||||
// later WRAP_ETH that pays anyone but the router, never joins the
|
// later WRAP_ETH that pays anyone but the router, never joins the
|
||||||
// Amount line either: its Moved to line names that recipient.
|
// Amount line either: its Moved to line names that recipient. The
|
||||||
|
// take of a later WRAP_ETH of a stated amount has that step's index as
|
||||||
|
// `wrapStep`.
|
||||||
const userPaid = [];
|
const userPaid = [];
|
||||||
// A swap step the user pays for (`payerIsUser` true) takes `amount`
|
// A swap step the user pays for (`payerIsUser` true) takes `amount`
|
||||||
// of `token` from the sender, or at most that when `atMost` is set. A
|
// of `token` from the sender, or at most that when `atMost` is set. A
|
||||||
@@ -1445,17 +1462,20 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
const r = recipient.toLowerCase();
|
const r = recipient.toLowerCase();
|
||||||
return r === MSG_SENDER || r === sender;
|
return r === MSG_SENDER || r === sender;
|
||||||
};
|
};
|
||||||
// A swap step or V4 SETTLE pays `amount` of `token` from the router's
|
// A swap step or V4 SETTLE at `step` pays `amount` of `token` from the
|
||||||
// own balance. CONTRACT_BALANCE pays all of it. Any other quantity
|
// router's own balance. CONTRACT_BALANCE pays all of it. Any other
|
||||||
// counts against the amount a WRAP_ETH stated, and the steps pay all
|
// quantity counts against the amount a WRAP_ETH stated, and the steps
|
||||||
// of it once their amounts reach that one: a swap paid in ETH wraps
|
// pay all of it once their amounts reach that one: a swap paid in ETH
|
||||||
// what its swap steps then spend. An amount that is not a quantity,
|
// wraps what its swap steps then spend. An amount that is not a
|
||||||
// such as the null decodeV4Swap() gives a SETTLE whose payment it
|
// quantity, such as the null decodeV4Swap() gives a SETTLE whose
|
||||||
// cannot tell, or one of a token whose amount is not known, pays out
|
// payment it cannot tell, or one of a token whose amount is not known,
|
||||||
// nothing this decoder can see.
|
// pays out nothing this decoder can see.
|
||||||
const spendFromRouter = (token, amount) => {
|
const spendFromRouter = (step, token, amount) => {
|
||||||
const t = token.toLowerCase();
|
const t = token.toLowerCase();
|
||||||
const held = heldByRouter.get(t);
|
const held = heldByRouter.get(t);
|
||||||
|
if (t === WETH.get(chainId) && heldByRouter.has(t)) {
|
||||||
|
lastRouterWethSwapStep = step;
|
||||||
|
}
|
||||||
if (amount === CONTRACT_BALANCE) {
|
if (amount === CONTRACT_BALANCE) {
|
||||||
heldByRouter.delete(t);
|
heldByRouter.delete(t);
|
||||||
} else if (typeof held === "bigint" && typeof amount === "bigint") {
|
} else if (typeof held === "bigint" && typeof amount === "bigint") {
|
||||||
@@ -1741,7 +1761,7 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
[s.recipient],
|
[s.recipient],
|
||||||
);
|
);
|
||||||
if (!s.payerIsUser) {
|
if (!s.payerIsUser) {
|
||||||
spendFromRouter(s.tokenIn, s.amountIn);
|
spendFromRouter(i, s.tokenIn, s.amountIn);
|
||||||
}
|
}
|
||||||
if (!isHop(i, s.tokenOut, s.recipient)) {
|
if (!isHop(i, s.tokenOut, s.recipient)) {
|
||||||
addPayee(s.recipient, s.tokenOut);
|
addPayee(s.recipient, s.tokenOut);
|
||||||
@@ -1770,7 +1790,7 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
[s.recipient],
|
[s.recipient],
|
||||||
);
|
);
|
||||||
if (!s.payerIsUser) {
|
if (!s.payerIsUser) {
|
||||||
spendFromRouter(s.tokenIn, s.amountIn);
|
spendFromRouter(i, s.tokenIn, s.amountIn);
|
||||||
}
|
}
|
||||||
if (!isHop(i, s.tokenOut, s.recipient)) {
|
if (!isHop(i, s.tokenOut, s.recipient)) {
|
||||||
addPayee(s.recipient, s.tokenOut);
|
addPayee(s.recipient, s.tokenOut);
|
||||||
@@ -1786,8 +1806,7 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
) {
|
) {
|
||||||
// Buys exactly amountOut and spends at most amountInMax.
|
// Buys exactly amountOut and spends at most amountInMax.
|
||||||
// Paid from the router, it spends an amount the calldata
|
// Paid from the router, it spends an amount the calldata
|
||||||
// does not state, so it spends nothing spendFromRouter()
|
// does not state, so spendFromRouter() has none to count.
|
||||||
// could count.
|
|
||||||
hasV2OrV3ExactOut = true;
|
hasV2OrV3ExactOut = true;
|
||||||
const s =
|
const s =
|
||||||
command === "V2_SWAP_EXACT_OUT"
|
command === "V2_SWAP_EXACT_OUT"
|
||||||
@@ -1809,6 +1828,9 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
]),
|
]),
|
||||||
[s.recipient],
|
[s.recipient],
|
||||||
);
|
);
|
||||||
|
if (!s.payerIsUser) {
|
||||||
|
spendFromRouter(i, s.tokenIn, null);
|
||||||
|
}
|
||||||
if (!isHop(i, s.tokenOut, s.recipient)) {
|
if (!isHop(i, s.tokenOut, s.recipient)) {
|
||||||
addPayee(s.recipient, s.tokenOut);
|
addPayee(s.recipient, s.tokenOut);
|
||||||
}
|
}
|
||||||
@@ -1906,6 +1928,7 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
w.amount,
|
w.amount,
|
||||||
);
|
);
|
||||||
inputPaidByUser = true;
|
inputPaidByUser = true;
|
||||||
|
wrapEthStep = i;
|
||||||
if (!isRouter(w.recipient)) {
|
if (!isRouter(w.recipient)) {
|
||||||
wrapEthRecipient = w.recipient;
|
wrapEthRecipient = w.recipient;
|
||||||
}
|
}
|
||||||
@@ -1916,8 +1939,7 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
// The ETH of a stated amount comes from the
|
// The ETH of a stated amount comes from the
|
||||||
// transaction's value. ETH an earlier step left in
|
// transaction's value. ETH an earlier step left in
|
||||||
// the router may pay part of it, and the sender
|
// the router may pay part of it, and the sender
|
||||||
// then pays at most that amount. CONTRACT_BALANCE
|
// then pays at most that amount.
|
||||||
// states no amount to take.
|
|
||||||
userPaid.push({
|
userPaid.push({
|
||||||
token: "0x0000000000000000000000000000000000000000",
|
token: "0x0000000000000000000000000000000000000000",
|
||||||
amount: w.amount,
|
amount: w.amount,
|
||||||
@@ -1927,6 +1949,25 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
recipient: isRouter(w.recipient)
|
recipient: isRouter(w.recipient)
|
||||||
? null
|
? null
|
||||||
: w.recipient,
|
: w.recipient,
|
||||||
|
wrapStep: i,
|
||||||
|
});
|
||||||
|
} else if (
|
||||||
|
w.amount === CONTRACT_BALANCE &&
|
||||||
|
!isRouter(w.recipient) &&
|
||||||
|
!unwrappedIntoRouter &&
|
||||||
|
!heldByRouter.has(
|
||||||
|
"0x0000000000000000000000000000000000000000",
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// It pays the recipient all the ETH the transaction
|
||||||
|
// carries. After an earlier step paid ETH to the
|
||||||
|
// router there is no line: Uniswap's routes pay back
|
||||||
|
// what their swap did not spend this way, and carry
|
||||||
|
// no ETH.
|
||||||
|
userPaid.push({
|
||||||
|
token: "0x0000000000000000000000000000000000000000",
|
||||||
|
amount: TRANSACTION_ETH,
|
||||||
|
recipient: w.recipient,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
addPayee(w.recipient);
|
addPayee(w.recipient);
|
||||||
@@ -1996,7 +2037,7 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
// Each SETTLE paid from the router spends the amount
|
// Each SETTLE paid from the router spends the amount
|
||||||
// decodeV4Swap() says it pays.
|
// decodeV4Swap() says it pays.
|
||||||
for (const s of v4.settledFromRouter) {
|
for (const s of v4.settledFromRouter) {
|
||||||
spendFromRouter(s.currency, s.amount);
|
spendFromRouter(i, s.currency, s.amount);
|
||||||
}
|
}
|
||||||
for (const t of v4.takes) {
|
for (const t of v4.takes) {
|
||||||
if (!isHop(i, t.currency, t.recipient)) {
|
if (!isHop(i, t.currency, t.recipient)) {
|
||||||
@@ -2169,6 +2210,9 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
heldByRouter.has(w),
|
heldByRouter.has(w),
|
||||||
);
|
);
|
||||||
WETH_ADDRESSES.forEach((w) => heldByRouter.delete(w));
|
WETH_ADDRESSES.forEach((w) => heldByRouter.delete(w));
|
||||||
|
if (isRouter(u.recipient)) {
|
||||||
|
unwrappedIntoRouter = true;
|
||||||
|
}
|
||||||
if (isRouter(u.recipient) && heldWeth) {
|
if (isRouter(u.recipient) && heldWeth) {
|
||||||
heldByRouter.set(
|
heldByRouter.set(
|
||||||
"0x0000000000000000000000000000000000000000",
|
"0x0000000000000000000000000000000000000000",
|
||||||
@@ -2264,10 +2308,11 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
permit.beforeEveryTake &&
|
permit.beforeEveryTake &&
|
||||||
!stepsUnread.some((step) => step > permit.step);
|
!stepsUnread.some((step) => step > permit.step);
|
||||||
// What the steps take that the Amount line does not give, as
|
// What the steps take that the Amount line does not give, as
|
||||||
// { token, amount, atMost, recipient }. A null token is a step this
|
// { token, amount, atMost, recipient, wrapStep }. A null token is a
|
||||||
// decoder did not read (see spentUnread()), or a token it does not
|
// step this decoder did not read (see spentUnread()), or a token it
|
||||||
// know. `atMost` is as in `userPaid`. Only the take of a WRAP_ETH that
|
// does not know. `atMost` is as in `userPaid`. Only the take of a
|
||||||
// pays elsewhere has a recipient (see wrapEthRecipient and userPaid).
|
// WRAP_ETH that pays elsewhere has a recipient (see wrapEthRecipient
|
||||||
|
// and userPaid). Only the take of a WRAP_ETH has a `wrapStep`.
|
||||||
const spentFromSender = [];
|
const spentFromSender = [];
|
||||||
let total = null;
|
let total = null;
|
||||||
// The takes from the sender that `total` adds up, each a quantity, in
|
// The takes from the sender that `total` adds up, each a quantity, in
|
||||||
@@ -2292,6 +2337,7 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
token: inputToken,
|
token: inputToken,
|
||||||
amount: inputAmount,
|
amount: inputAmount,
|
||||||
recipient: wrapEthRecipient,
|
recipient: wrapEthRecipient,
|
||||||
|
wrapStep: wrapEthStep,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (hasFirstTake && !present(inputAmount)) {
|
if (hasFirstTake && !present(inputAmount)) {
|
||||||
@@ -2304,6 +2350,7 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
token: inputToken,
|
token: inputToken,
|
||||||
amount: inputAmount,
|
amount: inputAmount,
|
||||||
recipient: wrapEthRecipient,
|
recipient: wrapEthRecipient,
|
||||||
|
wrapStep: wrapEthStep,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (permitStands) inputToken = permit.token;
|
if (permitStands) inputToken = permit.token;
|
||||||
@@ -2413,13 +2460,14 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The text of an amount the swap steps spend, for the Amount line and
|
// The text of an amount the swap steps spend, for the Amount line and
|
||||||
// the lines for other tokens below it. Three amounts need no scale to
|
// the lines for other tokens below it. Four amounts need no scale to
|
||||||
// describe and are named rather than formatted: V4's open delta and
|
// describe and are named rather than formatted: V4's open delta, V2's
|
||||||
// V2's already-paid zero, neither of which is a quantity at all (see
|
// already-paid zero and the ETH the transaction carries, none of which
|
||||||
// OPEN_DELTA and ALREADY_PAID), and an unbounded permit. Those two
|
// is a quantity at all (see OPEN_DELTA, ALREADY_PAID and
|
||||||
// tests come first — the sentinels are not bigints and cannot be
|
// TRANSACTION_ETH), and an unbounded permit. Those three tests come
|
||||||
// compared with one. `atMost` marks an amount that is only the most a
|
// first — the sentinels are not bigints and cannot be compared with
|
||||||
// take may be (see userPaid).
|
// one. `atMost` marks an amount that is only the most a take may be
|
||||||
|
// (see userPaid).
|
||||||
const spentText = (amount, info, atMost) => {
|
const spentText = (amount, info, atMost) => {
|
||||||
if (amount === OPEN_DELTA) {
|
if (amount === OPEN_DELTA) {
|
||||||
return { raw: OPEN_DELTA_AMOUNT, display: OPEN_DELTA_AMOUNT };
|
return { raw: OPEN_DELTA_AMOUNT, display: OPEN_DELTA_AMOUNT };
|
||||||
@@ -2430,6 +2478,12 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
display: ALREADY_PAID_AMOUNT,
|
display: ALREADY_PAID_AMOUNT,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (amount === TRANSACTION_ETH) {
|
||||||
|
return {
|
||||||
|
raw: TRANSACTION_ETH_AMOUNT,
|
||||||
|
display: TRANSACTION_ETH_AMOUNT,
|
||||||
|
};
|
||||||
|
}
|
||||||
if (amount >= MAX_UINT160) {
|
if (amount >= MAX_UINT160) {
|
||||||
return { raw: "Unlimited", display: "Unlimited" };
|
return { raw: "Unlimited", display: "Unlimited" };
|
||||||
}
|
}
|
||||||
@@ -2489,8 +2543,9 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
// of the lines below for a PERMIT2_TRANSFER_FROM. An amount this
|
// of the lines below for a PERMIT2_TRANSFER_FROM. An amount this
|
||||||
// decoder does not know is said so, and a step it did not read gets
|
// decoder does not know is said so, and a step it did not read gets
|
||||||
// that one line alone. A take with no recipient goes to the swap step
|
// that one line alone. A take with no recipient goes to the swap step
|
||||||
// that spends it. A take with a recipient goes to that recipient;
|
// that spends it. The take of a WRAP_ETH into the router goes to the
|
||||||
// `MSG_SENDER` means the sender.
|
// router, unless a later swap step spends its WETH. A take with a
|
||||||
|
// recipient goes to that recipient; `MSG_SENDER` means the sender.
|
||||||
for (const s of spentFromSender) {
|
for (const s of spentFromSender) {
|
||||||
details.push({
|
details.push({
|
||||||
label: "Moved from the sender",
|
label: "Moved from the sender",
|
||||||
@@ -2512,7 +2567,11 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
if (!present(s.recipient)) {
|
if (!present(s.recipient)) {
|
||||||
details.push({
|
details.push({
|
||||||
label: "Moved to",
|
label: "Moved to",
|
||||||
value: "The swap step that spends it",
|
value:
|
||||||
|
present(s.wrapStep) &&
|
||||||
|
s.wrapStep > lastRouterWethSwapStep
|
||||||
|
? "The router"
|
||||||
|
: "The swap step that spends it",
|
||||||
});
|
});
|
||||||
} else if (s.recipient.toLowerCase() === MSG_SENDER) {
|
} else if (s.recipient.toLowerCase() === MSG_SENDER) {
|
||||||
details.push({ label: "Moved to", value: "The sender" });
|
details.push({ label: "Moved to", value: "The sender" });
|
||||||
|
|||||||
+334
-21
@@ -2474,10 +2474,9 @@ describe("uniswap decoder", () => {
|
|||||||
// SETTLE of ETH from the router's own ETH, whichever payer it names.
|
// SETTLE of ETH from the router's own ETH, whichever payer it names.
|
||||||
// After an earlier step that may leave ETH in the router, the ETH that
|
// After an earlier step that may leave ETH in the router, the ETH that
|
||||||
// the user pays a V4 step reads as a maximum, on lines of its own.
|
// the user pays a V4 step reads as a maximum, on lines of its own.
|
||||||
// Every row reads at least the ETH that can leave the wallet. The two
|
// Every row reads at least the ETH that can leave the wallet. The row
|
||||||
// rows marked "reads as on next" read the same on next. On next every
|
// marked "reads as on next" reads the same on next. On next every other
|
||||||
// other row added that ETH to the Amount line, or read it as an exact
|
// row added that ETH to the Amount line, or read it as an exact amount.
|
||||||
// amount.
|
|
||||||
//
|
//
|
||||||
// ADDRESS_THIS is the router on every release.
|
// ADDRESS_THIS is the router on every release.
|
||||||
const ADDRESS_THIS = "0x0000000000000000000000000000000000000002";
|
const ADDRESS_THIS = "0x0000000000000000000000000000000000000002";
|
||||||
@@ -2625,7 +2624,7 @@ describe("uniswap decoder", () => {
|
|||||||
],
|
],
|
||||||
lines: [
|
lines: [
|
||||||
["Amount", "600.0000 USDT"],
|
["Amount", "600.0000 USDT"],
|
||||||
...wrapLines("The swap step that spends it"),
|
...wrapLines("The router"),
|
||||||
...ethLines("Up to 1.0000 ETH"),
|
...ethLines("Up to 1.0000 ETH"),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -2674,7 +2673,7 @@ describe("uniswap decoder", () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
kind: "a WRAP_ETH of 1 ETH into the router, an UNWRAP_WETH into the router, then a V4 exact-out paid in ETH with a SETTLE_ALL of at most 3 ETH, reads as on next",
|
kind: "a WRAP_ETH of 1 ETH into the router, an UNWRAP_WETH into the router, then a V4 exact-out paid in ETH with a SETTLE_ALL of at most 3 ETH",
|
||||||
commands: [0x0b, 0x0c, 0x10],
|
commands: [0x0b, 0x0c, 0x10],
|
||||||
inputs: [
|
inputs: [
|
||||||
WRAP_INTO_ROUTER,
|
WRAP_INTO_ROUTER,
|
||||||
@@ -2697,10 +2696,7 @@ describe("uniswap decoder", () => {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
lines: [
|
lines: [...wrapLines("The router"), ...ethLines(UNDECODED)],
|
||||||
...wrapLines("The swap step that spends it"),
|
|
||||||
...ethLines(UNDECODED),
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
kind: "a WRAP_ETH of 1 ETH into the router, a V3 exact-out of at most 1 WETH paid from the router, an UNWRAP_WETH into the router, then a V4 swap of 1 ETH that the user settles",
|
kind: "a WRAP_ETH of 1 ETH into the router, a V3 exact-out of at most 1 WETH paid from the router, an UNWRAP_WETH into the router, then a V4 swap of 1 ETH that the user settles",
|
||||||
@@ -2761,8 +2757,8 @@ describe("uniswap decoder", () => {
|
|||||||
// does not set the input side takes the amount it states from the
|
// does not set the input side takes the amount it states from the
|
||||||
// sender. On next no line gave that ETH. The rows marked "reads as on
|
// sender. On next no line gave that ETH. The rows marked "reads as on
|
||||||
// next" state no amount to take from the sender. Uniswap's own routes
|
// next" state no amount to take from the sender. Uniswap's own routes
|
||||||
// wrap CONTRACT_BALANCE after their first step, as the last two rows
|
// wrap CONTRACT_BALANCE into the router after their first step, as the
|
||||||
// do.
|
// last row does.
|
||||||
const CONTRACT_BALANCE = 2n ** 255n;
|
const CONTRACT_BALANCE = 2n ** 255n;
|
||||||
const WRAP_TO_OTHER = encodeWrapEth(OTHER_ADDR, ONE_ETH);
|
const WRAP_TO_OTHER = encodeWrapEth(OTHER_ADDR, ONE_ETH);
|
||||||
test.each([
|
test.each([
|
||||||
@@ -2787,7 +2783,7 @@ describe("uniswap decoder", () => {
|
|||||||
inputs: [V3_600, WRAP_INTO_ROUTER],
|
inputs: [V3_600, WRAP_INTO_ROUTER],
|
||||||
lines: [
|
lines: [
|
||||||
["Amount", "600.0000 USDT"],
|
["Amount", "600.0000 USDT"],
|
||||||
...wrapLines("The swap step that spends it"),
|
...wrapLines("The router"),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2796,7 +2792,7 @@ describe("uniswap decoder", () => {
|
|||||||
inputs: [V3_600, encodeWrapEth(ROUTER_ADDR, ONE_ETH)],
|
inputs: [V3_600, encodeWrapEth(ROUTER_ADDR, ONE_ETH)],
|
||||||
lines: [
|
lines: [
|
||||||
["Amount", "600.0000 USDT"],
|
["Amount", "600.0000 USDT"],
|
||||||
...wrapLines("The swap step that spends it"),
|
...wrapLines("The router"),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2839,7 +2835,9 @@ describe("uniswap decoder", () => {
|
|||||||
],
|
],
|
||||||
lines: [
|
lines: [
|
||||||
["Amount", "1.0000 ETH"],
|
["Amount", "1.0000 ETH"],
|
||||||
...ethLines("Up to 1.0000 ETH"),
|
["Moved from the sender", "Up to 1.0000 ETH"],
|
||||||
|
["Token moved", "ETH"],
|
||||||
|
["Moved to", "The router"],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2877,12 +2875,6 @@ describe("uniswap decoder", () => {
|
|||||||
inputs: [V3_600, encodeWrapEth(OTHER_ADDR, 0n)],
|
inputs: [V3_600, encodeWrapEth(OTHER_ADDR, 0n)],
|
||||||
lines: [["Amount", "600.0000 USDT"]],
|
lines: [["Amount", "600.0000 USDT"]],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
kind: "a V3 exact-in of 600 USDT, then a WRAP_ETH of CONTRACT_BALANCE to the sender, reads as on next",
|
|
||||||
commands: [0x00, 0x0b],
|
|
||||||
inputs: [V3_600, encodeWrapEth(MSG_SENDER, CONTRACT_BALANCE)],
|
|
||||||
lines: [["Amount", "600.0000 USDT"]],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
kind: "a V4 swap of 600 USDT that takes ETH into the router, a WRAP_ETH of CONTRACT_BALANCE into the router, then a V3 exact-in of it, reads as on next",
|
kind: "a V4 swap of 600 USDT that takes ETH into the router, a WRAP_ETH of CONTRACT_BALANCE into the router, then a V3 exact-in of it, reads as on next",
|
||||||
commands: [0x10, 0x0b, 0x00],
|
commands: [0x10, 0x0b, 0x00],
|
||||||
@@ -2923,6 +2915,327 @@ describe("uniswap decoder", () => {
|
|||||||
expect(linesBetweenTokens(result)).toEqual(lines);
|
expect(linesBetweenTokens(result)).toEqual(lines);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// https://git.eeqj.de/sneak/AutistMask/issues/747 — the WETH of a
|
||||||
|
// WRAP_ETH into the router goes to a swap step only when a later swap
|
||||||
|
// step paid from the router spends it. On next every row not marked
|
||||||
|
// "reads as on next" read The swap step that spends it.
|
||||||
|
const SWAP_STEP = "The swap step that spends it";
|
||||||
|
// Each pays 1 WETH from the router, for USDC, to the user.
|
||||||
|
const V3_WETH_FROM_ROUTER = coder.encode(
|
||||||
|
["address", "uint256", "uint256", "bytes", "bool"],
|
||||||
|
[
|
||||||
|
USER_ADDR,
|
||||||
|
ONE_ETH,
|
||||||
|
1n,
|
||||||
|
encodeV3Path([WETH_ADDR, USDC_ADDR]),
|
||||||
|
false,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
const V2_WETH_FROM_ROUTER = coder.encode(
|
||||||
|
["address", "uint256", "uint256", "address[]", "bool"],
|
||||||
|
[USER_ADDR, ONE_ETH, 1n, [WETH_ADDR, USDC_ADDR], false],
|
||||||
|
);
|
||||||
|
const V4_WETH_FROM_ROUTER = encodeV4Swap(
|
||||||
|
new Uint8Array([
|
||||||
|
V4_SWAP_EXACT_IN_SINGLE_ID,
|
||||||
|
V4_SETTLE_ID,
|
||||||
|
V4_TAKE_ALL_ID,
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
encodeV4ExactInSingle(WETH_ADDR, USDC_ADDR, ONE_ETH, 1n),
|
||||||
|
settle(WETH_ADDR, 0n, false),
|
||||||
|
encodeV4TakeAll(USDC_ADDR, 0n),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
// SWEEP has the layout of TRANSFER, and its amount is a minimum.
|
||||||
|
const SWEEP_WETH = payOut(WETH_ADDR, 0n);
|
||||||
|
test.each([
|
||||||
|
{
|
||||||
|
kind: "a V3 exact-in of 600 USDT, a WRAP_ETH of 1 ETH into the router, then a SWEEP of that WETH to another address",
|
||||||
|
commands: [0x00, 0x0b, 0x04],
|
||||||
|
inputs: [V3_600, WRAP_INTO_ROUTER, SWEEP_WETH],
|
||||||
|
lines: [
|
||||||
|
["Amount", "600.0000 USDT"],
|
||||||
|
...wrapLines("The router"),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "a V3 exact-in of 600 USDT, a WRAP_ETH of 1 ETH into the router, a SWEEP of that WETH to another address, then a V3 exact-in paid from the router's WETH",
|
||||||
|
commands: [0x00, 0x0b, 0x04, 0x00],
|
||||||
|
inputs: [
|
||||||
|
V3_600,
|
||||||
|
WRAP_INTO_ROUTER,
|
||||||
|
SWEEP_WETH,
|
||||||
|
V3_WETH_FROM_ROUTER,
|
||||||
|
],
|
||||||
|
lines: [
|
||||||
|
["Amount", "600.0000 USDT"],
|
||||||
|
...wrapLines("The router"),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "a V3 exact-in of 600 USDT, a WRAP_ETH of 1 ETH into the router, then a V3 exact-in of WETH that the user pays",
|
||||||
|
commands: [0x00, 0x0b, 0x00],
|
||||||
|
inputs: [
|
||||||
|
V3_600,
|
||||||
|
WRAP_INTO_ROUTER,
|
||||||
|
encodeV3SwapExactIn(USER_ADDR, ONE_ETH, 1n, [
|
||||||
|
WETH_ADDR,
|
||||||
|
USDC_ADDR,
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
lines: [
|
||||||
|
["Amount", "600.0000 USDT"],
|
||||||
|
...wrapLines("The router"),
|
||||||
|
["Moved from the sender", "1.0000 WETH"],
|
||||||
|
["Token moved", "WETH (" + WETH_ADDR + ")"],
|
||||||
|
["Moved to", SWAP_STEP],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "a V3 exact-in of 600 USDT, a WRAP_ETH of 1 ETH into the router, a V3 exact-in paid from the router's WETH, then another WRAP_ETH of 1 ETH into the router",
|
||||||
|
commands: [0x00, 0x0b, 0x00, 0x0b],
|
||||||
|
inputs: [
|
||||||
|
V3_600,
|
||||||
|
WRAP_INTO_ROUTER,
|
||||||
|
V3_WETH_FROM_ROUTER,
|
||||||
|
WRAP_INTO_ROUTER,
|
||||||
|
],
|
||||||
|
lines: [
|
||||||
|
["Amount", "600.0000 USDT"],
|
||||||
|
...wrapLines(SWAP_STEP),
|
||||||
|
...wrapLines("The router"),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "a V3 exact-in of 600 USDT, a WRAP_ETH of 1 ETH into the router, then a V3 exact-in paid from the router's WETH, reads as on next",
|
||||||
|
commands: [0x00, 0x0b, 0x00],
|
||||||
|
inputs: [V3_600, WRAP_INTO_ROUTER, V3_WETH_FROM_ROUTER],
|
||||||
|
lines: [["Amount", "600.0000 USDT"], ...wrapLines(SWAP_STEP)],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "the same with a V2 exact-in paid from the router's WETH, reads as on next",
|
||||||
|
commands: [0x00, 0x0b, 0x08],
|
||||||
|
inputs: [V3_600, WRAP_INTO_ROUTER, V2_WETH_FROM_ROUTER],
|
||||||
|
lines: [["Amount", "600.0000 USDT"], ...wrapLines(SWAP_STEP)],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "the same with a V3 exact-out paid from the router's WETH, reads as on next",
|
||||||
|
commands: [0x00, 0x0b, 0x01],
|
||||||
|
inputs: [
|
||||||
|
V3_600,
|
||||||
|
WRAP_INTO_ROUTER,
|
||||||
|
encodeV3SwapExactOut(
|
||||||
|
USER_ADDR,
|
||||||
|
390000000n,
|
||||||
|
ONE_ETH,
|
||||||
|
[USDC_ADDR, WETH_ADDR],
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
lines: [
|
||||||
|
["Amount", "Up to 600.0000 USDT"],
|
||||||
|
["Moved from the sender", "Up to 1.0000 ETH"],
|
||||||
|
["Token moved", "ETH"],
|
||||||
|
["Moved to", SWAP_STEP],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "the same with a V4 swap that the router's WETH settles, reads as on next",
|
||||||
|
commands: [0x00, 0x0b, 0x10],
|
||||||
|
inputs: [V3_600, WRAP_INTO_ROUTER, V4_WETH_FROM_ROUTER],
|
||||||
|
lines: [["Amount", "600.0000 USDT"], ...wrapLines(SWAP_STEP)],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "a WRAP_ETH of 1 ETH into the router that sets the input side, a SWEEP of that WETH to another address, then an EXECUTE_SUB_PLAN",
|
||||||
|
commands: [0x0b, 0x04, 0x21],
|
||||||
|
inputs: [WRAP_INTO_ROUTER, SWEEP_WETH, SUB_PLAN],
|
||||||
|
lines: [
|
||||||
|
...wrapLines("The router"),
|
||||||
|
["Moved from the sender", UNDECODED],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "a WRAP_ETH of 1 ETH into the router that sets the input side, a V3 exact-in paid from the router's WETH, then an EXECUTE_SUB_PLAN, reads as on next",
|
||||||
|
commands: [0x0b, 0x00, 0x21],
|
||||||
|
inputs: [WRAP_INTO_ROUTER, V3_WETH_FROM_ROUTER, SUB_PLAN],
|
||||||
|
lines: [
|
||||||
|
...wrapLines(SWAP_STEP),
|
||||||
|
["Moved from the sender", UNDECODED],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "a PERMIT2_PERMIT of 5,000 USDT to the router, a WRAP_ETH of 1 ETH into the router, then a V3 exact-in of 600 USDT",
|
||||||
|
commands: [0x0a, 0x0b, 0x00],
|
||||||
|
inputs: [
|
||||||
|
encodePermit2(USDT_ADDR, 5000000000n, ROUTER_ADDR),
|
||||||
|
WRAP_INTO_ROUTER,
|
||||||
|
V3_600,
|
||||||
|
],
|
||||||
|
lines: [
|
||||||
|
["Amount", "5000.0000 USDT"],
|
||||||
|
...wrapLines("The router"),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "the same with a V3 exact-in paid from the router's WETH after the WRAP_ETH, reads as on next",
|
||||||
|
commands: [0x0a, 0x0b, 0x00, 0x00],
|
||||||
|
inputs: [
|
||||||
|
encodePermit2(USDT_ADDR, 5000000000n, ROUTER_ADDR),
|
||||||
|
WRAP_INTO_ROUTER,
|
||||||
|
V3_WETH_FROM_ROUTER,
|
||||||
|
V3_600,
|
||||||
|
],
|
||||||
|
lines: [["Amount", "5000.0000 USDT"], ...wrapLines(SWAP_STEP)],
|
||||||
|
},
|
||||||
|
])("$kind", ({ commands, inputs, lines }) => {
|
||||||
|
const result = decodeSteps(commands, inputs);
|
||||||
|
expect(linesBetweenTokens(result)).toEqual(lines);
|
||||||
|
});
|
||||||
|
|
||||||
|
// https://git.eeqj.de/sneak/AutistMask/issues/747 — a later WRAP_ETH
|
||||||
|
// of CONTRACT_BALANCE wraps all the ETH the router holds. Unless an
|
||||||
|
// earlier step paid ETH to the router, that is the ETH the transaction
|
||||||
|
// carries. On next no line gave it. Uniswap's own routes pay back what
|
||||||
|
// their swap did not spend this way, and carry no ETH, so in the rows
|
||||||
|
// marked "reads as on next" that WRAP_ETH gets no lines.
|
||||||
|
const WRAP_ALL_TO_OTHER = encodeWrapEth(OTHER_ADDR, CONTRACT_BALANCE);
|
||||||
|
const WRAP_ALL_TO_SENDER = encodeWrapEth(MSG_SENDER, CONTRACT_BALANCE);
|
||||||
|
// The lines of such a WRAP_ETH whose Moved to line reads `to`.
|
||||||
|
const allEthLines = (to) => [
|
||||||
|
["Moved from the sender", "All the ETH the transaction carries"],
|
||||||
|
["Token moved", "ETH"],
|
||||||
|
["Moved to", to],
|
||||||
|
];
|
||||||
|
// The first steps of a route that spends WETH on a V4 pool of ETH:
|
||||||
|
// a PERMIT2_TRANSFER_FROM of 1 WETH into the router, an UNWRAP_WETH
|
||||||
|
// into the router, then a V4 exact-out paid from the router's ETH.
|
||||||
|
const UNWRAP_ROUTE = [
|
||||||
|
coder.encode(
|
||||||
|
["address", "address", "uint160"],
|
||||||
|
[WETH_ADDR, ADDRESS_THIS, ONE_ETH],
|
||||||
|
),
|
||||||
|
UNWRAP_INTO_ROUTER,
|
||||||
|
encodeV4Swap(
|
||||||
|
new Uint8Array([
|
||||||
|
V4_SWAP_EXACT_OUT_SINGLE_ID,
|
||||||
|
V4_SETTLE_ID,
|
||||||
|
V4_TAKE_ALL_ID,
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
encodeV4ExactOutSingle(
|
||||||
|
ZERO_ADDR,
|
||||||
|
USDC_ADDR,
|
||||||
|
390000000n,
|
||||||
|
ONE_ETH,
|
||||||
|
),
|
||||||
|
settle(ZERO_ADDR, 0n, false),
|
||||||
|
encodeV4TakeAll(USDC_ADDR, 0n),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
];
|
||||||
|
// The lines of that route on next: this decoder cannot tell what the
|
||||||
|
// V4 step's SETTLE of ETH pays.
|
||||||
|
const UNWRAP_ROUTE_LINES = [
|
||||||
|
["Moved from the sender", UNDECODED],
|
||||||
|
["Token moved", "ETH"],
|
||||||
|
["Moved to", SWAP_STEP],
|
||||||
|
];
|
||||||
|
test.each([
|
||||||
|
{
|
||||||
|
kind: "a V3 exact-in of 600 USDT, then a WRAP_ETH of CONTRACT_BALANCE to another address",
|
||||||
|
commands: [0x00, 0x0b],
|
||||||
|
inputs: [V3_600, WRAP_ALL_TO_OTHER],
|
||||||
|
lines: [
|
||||||
|
["Amount", "600.0000 USDT"],
|
||||||
|
...allEthLines(OTHER_ADDR),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "a V3 exact-in of 600 USDT, then a WRAP_ETH of CONTRACT_BALANCE to the sender",
|
||||||
|
commands: [0x00, 0x0b],
|
||||||
|
inputs: [V3_600, WRAP_ALL_TO_SENDER],
|
||||||
|
lines: [
|
||||||
|
["Amount", "600.0000 USDT"],
|
||||||
|
...allEthLines("The sender"),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "a V3 exact-out of at most 600 USDT, then a WRAP_ETH of CONTRACT_BALANCE to another address",
|
||||||
|
commands: [0x01, 0x0b],
|
||||||
|
inputs: [
|
||||||
|
encodeV3SwapExactOut(USER_ADDR, 390000000n, USDT_600, [
|
||||||
|
USDC_ADDR,
|
||||||
|
USDT_ADDR,
|
||||||
|
]),
|
||||||
|
WRAP_ALL_TO_OTHER,
|
||||||
|
],
|
||||||
|
lines: [
|
||||||
|
["Amount", "Up to 600.0000 USDT"],
|
||||||
|
...allEthLines(OTHER_ADDR),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "a WRAP_ETH of 1 ETH into the router, then a WRAP_ETH of CONTRACT_BALANCE to another address",
|
||||||
|
commands: [0x0b, 0x0b],
|
||||||
|
inputs: [WRAP_INTO_ROUTER, WRAP_ALL_TO_OTHER],
|
||||||
|
lines: [["Amount", "1.0000 ETH"], ...allEthLines(OTHER_ADDR)],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "a V3 exact-in of 600 USDT, an UNWRAP_WETH to the sender, then a WRAP_ETH of CONTRACT_BALANCE to another address",
|
||||||
|
commands: [0x00, 0x0c, 0x0b],
|
||||||
|
inputs: [
|
||||||
|
V3_600,
|
||||||
|
encodeWrapEth(MSG_SENDER, 0n),
|
||||||
|
WRAP_ALL_TO_OTHER,
|
||||||
|
],
|
||||||
|
lines: [
|
||||||
|
["Amount", "600.0000 USDT"],
|
||||||
|
...allEthLines(OTHER_ADDR),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "a V4 swap of 600 USDT that takes ETH into the router, then a WRAP_ETH of CONTRACT_BALANCE to the sender, reads as on next",
|
||||||
|
commands: [0x10, 0x0b],
|
||||||
|
inputs: [
|
||||||
|
encodeV4Swap(
|
||||||
|
new Uint8Array([
|
||||||
|
V4_SWAP_EXACT_IN_SINGLE_ID,
|
||||||
|
V4_SETTLE_ID,
|
||||||
|
V4_TAKE_ID,
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
encodeV4ExactInSingle(
|
||||||
|
USDT_ADDR,
|
||||||
|
ZERO_ADDR,
|
||||||
|
USDT_600,
|
||||||
|
1n,
|
||||||
|
),
|
||||||
|
settle(USDT_ADDR, 0n, true),
|
||||||
|
take(ZERO_ADDR, ADDRESS_THIS, 0n),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
WRAP_ALL_TO_SENDER,
|
||||||
|
],
|
||||||
|
lines: [["Amount", "600.0000 USDT"]],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "the unwrap route, then a WRAP_ETH of CONTRACT_BALANCE to the sender, reads as on next",
|
||||||
|
commands: [0x02, 0x0c, 0x10, 0x0b],
|
||||||
|
inputs: [...UNWRAP_ROUTE, WRAP_ALL_TO_SENDER],
|
||||||
|
lines: UNWRAP_ROUTE_LINES,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "the unwrap route, then a WRAP_ETH of CONTRACT_BALANCE to another address, reads as on next",
|
||||||
|
commands: [0x02, 0x0c, 0x10, 0x0b],
|
||||||
|
inputs: [...UNWRAP_ROUTE, WRAP_ALL_TO_OTHER],
|
||||||
|
lines: UNWRAP_ROUTE_LINES,
|
||||||
|
},
|
||||||
|
])("$kind", ({ commands, inputs, lines }) => {
|
||||||
|
const result = decodeSteps(commands, inputs);
|
||||||
|
expect(linesBetweenTokens(result)).toEqual(lines);
|
||||||
|
});
|
||||||
|
|
||||||
// A V3_SWAP_EXACT_OUT the user pays for, of at most `amountInMax`
|
// A V3_SWAP_EXACT_OUT the user pays for, of at most `amountInMax`
|
||||||
// USDT for USDC.
|
// USDT for USDC.
|
||||||
const v3ExactOut = (amountInMax) =>
|
const v3ExactOut = (amountInMax) =>
|
||||||
|
|||||||
Reference in New Issue
Block a user