fix: the swap decoder shows the ETH of a WRAP_ETH that does not set the input side (closes #721)
A later WRAP_ETH of a stated amount now counts as a take from the sender. When it pays anyone but the router, it gets its own Moved from the sender lines, with the recipient on Moved to. When it pays the router, it joins the Amount line if Token In is ETH, and otherwise gets those lines too. When the router may already hold ETH, the amount reads Up to. A WRAP_ETH whose input this decoder cannot read gets a line saying the amount could not be decoded. A WRAP_ETH of CONTRACT_BALANCE states no amount and reads as before, so Uniswap's own routes do not change. Model: opus-5-5
This commit was merged in pull request #725.
This commit is contained in:
@@ -2593,6 +2593,9 @@ describe("uniswap decoder", () => {
|
||||
],
|
||||
lines: [
|
||||
["Amount", "1.0000 ETH"],
|
||||
["Moved from the sender", "Up to 1.0000 ETH"],
|
||||
["Token moved", "ETH"],
|
||||
["Moved to", OTHER_ADDR],
|
||||
...ethLines("Up to 1.0000 ETH"),
|
||||
],
|
||||
},
|
||||
@@ -2622,6 +2625,7 @@ describe("uniswap decoder", () => {
|
||||
],
|
||||
lines: [
|
||||
["Amount", "600.0000 USDT"],
|
||||
...wrapLines("The swap step that spends it"),
|
||||
...ethLines("Up to 1.0000 ETH"),
|
||||
],
|
||||
},
|
||||
@@ -2753,6 +2757,172 @@ describe("uniswap decoder", () => {
|
||||
expect(linesBetweenTokens(result)).toEqual(lines);
|
||||
});
|
||||
|
||||
// https://git.eeqj.de/sneak/AutistMask/issues/721 — a WRAP_ETH that
|
||||
// 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
|
||||
// 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
|
||||
// do.
|
||||
const CONTRACT_BALANCE = 2n ** 255n;
|
||||
const WRAP_TO_OTHER = encodeWrapEth(OTHER_ADDR, ONE_ETH);
|
||||
test.each([
|
||||
{
|
||||
kind: "a V3 exact-in of 600 USDT, then a WRAP_ETH of 1 ETH to another address",
|
||||
commands: [0x00, 0x0b],
|
||||
inputs: [V3_600, WRAP_TO_OTHER],
|
||||
lines: [["Amount", "600.0000 USDT"], ...wrapLines(OTHER_ADDR)],
|
||||
},
|
||||
{
|
||||
kind: "a V3 exact-in of 600 USDT, then a WRAP_ETH of 1 ETH to address(1)",
|
||||
commands: [0x00, 0x0b],
|
||||
inputs: [V3_600, encodeWrapEth(MSG_SENDER, ONE_ETH)],
|
||||
lines: [
|
||||
["Amount", "600.0000 USDT"],
|
||||
...wrapLines("The sender"),
|
||||
],
|
||||
},
|
||||
{
|
||||
kind: "a V3 exact-in of 600 USDT, then a WRAP_ETH of 1 ETH to address(2)",
|
||||
commands: [0x00, 0x0b],
|
||||
inputs: [V3_600, WRAP_INTO_ROUTER],
|
||||
lines: [
|
||||
["Amount", "600.0000 USDT"],
|
||||
...wrapLines("The swap step that spends it"),
|
||||
],
|
||||
},
|
||||
{
|
||||
kind: "a V3 exact-in of 600 USDT, then a WRAP_ETH of 1 ETH to the router by its own address",
|
||||
commands: [0x00, 0x0b],
|
||||
inputs: [V3_600, encodeWrapEth(ROUTER_ADDR, ONE_ETH)],
|
||||
lines: [
|
||||
["Amount", "600.0000 USDT"],
|
||||
...wrapLines("The swap step that spends it"),
|
||||
],
|
||||
},
|
||||
{
|
||||
kind: "a WRAP_ETH of 1 ETH into the router, then a WRAP_ETH of 1 ETH to another address",
|
||||
commands: [0x0b, 0x0b],
|
||||
inputs: [WRAP_INTO_ROUTER, WRAP_TO_OTHER],
|
||||
lines: [["Amount", "1.0000 ETH"], ...wrapLines(OTHER_ADDR)],
|
||||
},
|
||||
{
|
||||
kind: "two WRAP_ETHs of 1 ETH into the router, which the Amount line adds up",
|
||||
commands: [0x0b, 0x0b],
|
||||
inputs: [WRAP_INTO_ROUTER, WRAP_INTO_ROUTER],
|
||||
lines: [["Amount", "2.0000 ETH"]],
|
||||
},
|
||||
{
|
||||
kind: "a V3 exact-in of 600 USDT for WETH paid to the router, an UNWRAP_WETH into the router, then a WRAP_ETH of 1 ETH to another address",
|
||||
commands: [0x00, 0x0c, 0x0b],
|
||||
inputs: [
|
||||
encodeV3SwapExactIn(ADDRESS_THIS, USDT_600, 1n, [
|
||||
USDT_ADDR,
|
||||
WETH_ADDR,
|
||||
]),
|
||||
UNWRAP_INTO_ROUTER,
|
||||
WRAP_TO_OTHER,
|
||||
],
|
||||
lines: [
|
||||
["Amount", "600.0000 USDT"],
|
||||
["Moved from the sender", "Up to 1.0000 ETH"],
|
||||
["Token moved", "ETH"],
|
||||
["Moved to", OTHER_ADDR],
|
||||
],
|
||||
},
|
||||
{
|
||||
kind: "a WRAP_ETH of 1 ETH into the router, an UNWRAP_WETH into the router, then a WRAP_ETH of 1 ETH into the router",
|
||||
commands: [0x0b, 0x0c, 0x0b],
|
||||
inputs: [
|
||||
WRAP_INTO_ROUTER,
|
||||
UNWRAP_INTO_ROUTER,
|
||||
WRAP_INTO_ROUTER,
|
||||
],
|
||||
lines: [
|
||||
["Amount", "1.0000 ETH"],
|
||||
...ethLines("Up to 1.0000 ETH"),
|
||||
],
|
||||
},
|
||||
{
|
||||
kind: "a PERMIT2_PERMIT of 5,000 USDT to the router, a V3 exact-in of 600 USDT, then a WRAP_ETH of 1 ETH to another address",
|
||||
commands: [0x0a, 0x00, 0x0b],
|
||||
inputs: [
|
||||
encodePermit2(USDT_ADDR, 5000000000n, ROUTER_ADDR),
|
||||
V3_600,
|
||||
WRAP_TO_OTHER,
|
||||
],
|
||||
lines: [["Amount", "5000.0000 USDT"], ...wrapLines(OTHER_ADDR)],
|
||||
},
|
||||
{
|
||||
kind: "a V3 exact-in of 600 USDT, a WRAP_ETH of 1 ETH to another address, then an EXECUTE_SUB_PLAN",
|
||||
commands: [0x00, 0x0b, 0x21],
|
||||
inputs: [V3_600, WRAP_TO_OTHER, SUB_PLAN],
|
||||
lines: [
|
||||
...USDT_600_GROUP,
|
||||
...wrapLines(OTHER_ADDR),
|
||||
["Moved from the sender", UNDECODED],
|
||||
],
|
||||
},
|
||||
{
|
||||
kind: "a V3 exact-in of 600 USDT, then a WRAP_ETH whose input this decoder cannot read",
|
||||
commands: [0x00, 0x0b],
|
||||
inputs: [V3_600, "0x1234"],
|
||||
lines: [
|
||||
...USDT_600_GROUP,
|
||||
["Moved from the sender", UNDECODED],
|
||||
],
|
||||
},
|
||||
{
|
||||
kind: "a V3 exact-in of 600 USDT, then a WRAP_ETH of nothing to another address, reads as on next",
|
||||
commands: [0x00, 0x0b],
|
||||
inputs: [V3_600, encodeWrapEth(OTHER_ADDR, 0n)],
|
||||
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",
|
||||
commands: [0x10, 0x0b, 0x00],
|
||||
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),
|
||||
],
|
||||
),
|
||||
encodeWrapEth(ADDRESS_THIS, CONTRACT_BALANCE),
|
||||
coder.encode(
|
||||
["address", "uint256", "uint256", "bytes", "bool"],
|
||||
[
|
||||
USER_ADDR,
|
||||
CONTRACT_BALANCE,
|
||||
1n,
|
||||
encodeV3Path([WETH_ADDR, USDC_ADDR]),
|
||||
false,
|
||||
],
|
||||
),
|
||||
],
|
||||
lines: [["Amount", "600.0000 USDT"]],
|
||||
},
|
||||
])("$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`
|
||||
// USDT for USDC.
|
||||
const v3ExactOut = (amountInMax) =>
|
||||
|
||||
@@ -370,7 +370,8 @@ const PAID_ELSEWHERE = [
|
||||
"Steps",
|
||||
"Deadline",
|
||||
];
|
||||
// `lines` with the lines of one PERMIT2_TRANSFER_FROM after Amount.
|
||||
// `lines` with the lines of one PERMIT2_TRANSFER_FROM or later WRAP_ETH after
|
||||
// Amount.
|
||||
const withMove = (lines) =>
|
||||
lines.flatMap((l) =>
|
||||
l === "Amount"
|
||||
@@ -985,7 +986,7 @@ describe("what reaches the UNWRAP_WETH of the swap's WETH", () => {
|
||||
);
|
||||
|
||||
// The SWEEP pays the user the swap's WETH, so the UNWRAP_WETH unwraps the
|
||||
// WRAP_ETH's.
|
||||
// WRAP_ETH's. The WRAP_ETH's 1 ETH gets lines of its own.
|
||||
test("a SWEEP of the swap's WETH to the user, then a WRAP_ETH into the router, reads as ETH with no minimum", () => {
|
||||
const result = decode(
|
||||
execute(
|
||||
@@ -996,7 +997,10 @@ describe("what reaches the UNWRAP_WETH of the swap's WETH", () => {
|
||||
),
|
||||
);
|
||||
expect(result.name).toBe("Swap USDT → ETH");
|
||||
expect(labels(result)).toEqual(NO_MINIMUM_TO_USER);
|
||||
expect(labels(result)).toEqual(withMove(NO_MINIMUM_TO_USER));
|
||||
expect(detail(result, "Moved from the sender").value).toBe(
|
||||
"1.0000 ETH",
|
||||
);
|
||||
});
|
||||
|
||||
test("an UNWRAP_WETH into the router, then a WRAP_ETH of all its ETH to the user, reads as WETH with no minimum", () => {
|
||||
@@ -1097,7 +1101,9 @@ describe("what reaches the UNWRAP_WETH of the swap's WETH", () => {
|
||||
},
|
||||
);
|
||||
|
||||
// The user receives 0.5 WETH and the rest of the swap's output as ETH.
|
||||
// The user receives 0.5 WETH and the rest of the swap's output as ETH. The
|
||||
// router holds ETH when the WRAP_ETH runs, so the sender pays at most its
|
||||
// 0.5 ETH.
|
||||
test("an UNWRAP_WETH into the router, then a WRAP_ETH of 0.5 ETH to the user, reads as WETH with no minimum", () => {
|
||||
const result = decode(
|
||||
execute(
|
||||
@@ -1108,7 +1114,11 @@ describe("what reaches the UNWRAP_WETH of the swap's WETH", () => {
|
||||
),
|
||||
);
|
||||
expect(result.name).toBe("Swap USDT → WETH");
|
||||
expect(labels(result)).toEqual(NO_MINIMUM_TO_USER);
|
||||
expect(labels(result)).toEqual(withMove(NO_MINIMUM_TO_USER));
|
||||
expect(detail(result, "Moved from the sender").value).toBe(
|
||||
"Up to 0.5000 ETH",
|
||||
);
|
||||
expect(detail(result, "Moved to").value).toBe("The sender");
|
||||
});
|
||||
|
||||
// The UNWRAP_WETH pays the user the swap's WETH as ETH; the WRAP_ETH wraps
|
||||
@@ -1348,6 +1358,7 @@ describe("any token left in the router is not received", () => {
|
||||
),
|
||||
),
|
||||
left: tokenLine(WETH, "WETH"),
|
||||
spent: "1.0000 ETH",
|
||||
},
|
||||
// A SETTLE of OPEN_DELTA from the router pays only what the step
|
||||
// still owes of its currency when it runs.
|
||||
@@ -1516,8 +1527,8 @@ describe("any token left in the router is not received", () => {
|
||||
"Moved from the sender",
|
||||
]
|
||||
: ["Amount"]),
|
||||
// A later swap step the user pays for spends `spent` of a token
|
||||
// other than Token In.
|
||||
// A later swap step or WRAP_ETH the user pays for spends `spent`
|
||||
// of a token other than Token In.
|
||||
...(spent
|
||||
? ["Moved from the sender", "Token moved", "Moved to"]
|
||||
: []),
|
||||
|
||||
Reference in New Issue
Block a user