Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c456df556 |
No files matched your search
@@ -1277,21 +1277,18 @@ see Transaction Decoding), do not always read as a number. They can read:
|
|||||||
step pays nothing itself and swaps whatever an earlier step sent to the pair,
|
step pays nothing itself and swaps whatever an earlier step sent to the pair,
|
||||||
so the calldata states no quantity. A V3 exact-in `amountIn` of zero has no
|
so the calldata states no quantity. A V3 exact-in `amountIn` of zero has no
|
||||||
such meaning and is shown as a zero.
|
such meaning and is shown as a zero.
|
||||||
- `None (no minimum guaranteed)`: the swap's `Min. received` line, when the
|
- `None (no minimum guaranteed)`: the swap's `Min. received` line, when it shows
|
||||||
minimum it shows is zero, whether a V2, V3 or V4 swap's minimum or a
|
a V2, V3 or V4 swap's minimum of zero. The router passes a
|
||||||
`BALANCE_CHECK_ERC20` step's `minBalance`. Before
|
`BALANCE_CHECK_ERC20` step whenever the balance is at least `minBalance`, so a
|
||||||
[#359](https://git.eeqj.de/sneak/AutistMask/issues/359), a zero `minBalance`
|
zero `minBalance` guarantees nothing. A check with a zero `minBalance` sets
|
||||||
read `0.0000` when the token's scale was known. The router passes a balance
|
neither `Token Out` nor `Min. received`. A nonzero `minBalance` sets both
|
||||||
check whenever the balance is at least `minBalance`, so a zero `minBalance`
|
lines, as a swap step does. Only a check of the transaction's sender's own
|
||||||
guarantees nothing. A check with a zero `minBalance` sets `Token Out` and
|
balance sets either line; a check of any other address sets neither (see
|
||||||
`Min. received` only when no earlier step set the output side. A nonzero
|
Transaction Decoding). A `BALANCE_CHECK_ERC20` step that the router lets fail
|
||||||
`minBalance` sets both lines, as a swap step does. Only a check of the
|
without reverting the transaction (see Transaction Decoding) guarantees
|
||||||
transaction's sender's own balance sets either line; a check of any other
|
nothing either, whatever its `minBalance`, and is read as one whose
|
||||||
address sets neither (see Transaction Decoding). A `BALANCE_CHECK_ERC20` step
|
`minBalance` is zero. A minimum stated by a V4 swap step the router lets fail
|
||||||
that the router lets fail without reverting the transaction (see Transaction
|
is likewise read as zero.
|
||||||
Decoding) guarantees nothing either, whatever its `minBalance`, and is read as
|
|
||||||
one whose `minBalance` is zero. A minimum stated by a V4 swap step the router
|
|
||||||
lets fail is likewise read as zero.
|
|
||||||
|
|
||||||
The swap's `Token In` and `Token Out` lines name a currency, not an amount; each
|
The swap's `Token In` and `Token Out` lines name a currency, not an amount; each
|
||||||
reads `Unknown (not named in the calldata)` when the decoder found no token for
|
reads `Unknown (not named in the calldata)` when the decoder found no token for
|
||||||
@@ -3397,12 +3394,12 @@ Currently supported:
|
|||||||
such as one whose owner word has a nonzero top byte (the router reads the
|
such as one whose owner word has a nonzero top byte (the router reads the
|
||||||
owner from the word's last 20 bytes), likewise sets neither, and it is listed
|
owner from the word's last 20 bytes), likewise sets neither, and it is listed
|
||||||
as `Balance Check (could not be decoded)`. A check with a zero `minBalance`
|
as `Balance Check (could not be decoded)`. A check with a zero `minBalance`
|
||||||
never changes an output side that an earlier step set. When a swap step,
|
sets neither `Token Out` nor the minimum. When a swap step, `TAKE` or
|
||||||
`TAKE` or `TAKE_PORTION` pays the router any token, the swap's output or
|
`TAKE_PORTION` pays the router any token, the swap's output or another, a
|
||||||
another, a `WRAP_ETH` pays it WETH, or an `UNWRAP_WETH` into the router turns
|
`WRAP_ETH` pays it WETH, or an `UNWRAP_WETH` into the router turns WETH a step
|
||||||
WETH a step paid it into ETH, that token stays in the router unless a later
|
paid it into ETH, that token stays in the router unless a later step pays out
|
||||||
step pays out or spends all the router holds of it: a `SWEEP` of that token to
|
or spends all the router holds of it: a `SWEEP` of that token to anyone but
|
||||||
anyone but the router, an `UNWRAP_WETH` when it is WETH, a `WRAP_ETH` of
|
the router, an `UNWRAP_WETH` when it is WETH, a `WRAP_ETH` of
|
||||||
`CONTRACT_BALANCE` when it is ETH, a `TRANSFER` of `CONTRACT_BALANCE`, a
|
`CONTRACT_BALANCE` when it is ETH, a `TRANSFER` of `CONTRACT_BALANCE`, a
|
||||||
`PAY_PORTION` of 10,000 bips or a `PAY_PORTION_FULL_PRECISION` of 1e18 of that
|
`PAY_PORTION` of 10,000 bips or a `PAY_PORTION_FULL_PRECISION` of 1e18 of that
|
||||||
token to anyone but the router, an `ACROSS_V4_DEPOSIT_V3` of
|
token to anyone but the router, an `ACROSS_V4_DEPOSIT_V3` of
|
||||||
|
|||||||
@@ -1629,14 +1629,13 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
} else {
|
} else {
|
||||||
// The router passes this check whenever the owner
|
// The router passes this check whenever the owner
|
||||||
// holds at least minBalance, so a zero one guarantees
|
// holds at least minBalance, so a zero one guarantees
|
||||||
// nothing. A check with a zero minBalance leaves
|
// nothing. A check the router lets fail guarantees
|
||||||
// alone an output side that an earlier step set,
|
// nothing either, so it is read as a zero one. A zero
|
||||||
// token included. A check the router lets fail
|
// check sets neither Token Out nor the minimum. Any
|
||||||
// guarantees nothing either, so it is read as a zero
|
// other minBalance sets the output side as a swap
|
||||||
// one. Any other minBalance sets the output side as a
|
// does. The check pays nobody.
|
||||||
// swap does. The check pays nobody.
|
|
||||||
const minBalance = allowedToFail ? 0n : b.minBalance;
|
const minBalance = allowedToFail ? 0n : b.minBalance;
|
||||||
if (!(minBalance === 0n && outputEstablished)) {
|
if (minBalance !== 0n) {
|
||||||
setOutput(i, b.token, minBalance, []);
|
setOutput(i, b.token, minBalance, []);
|
||||||
}
|
}
|
||||||
keepsRouterWeth = true;
|
keepsRouterWeth = true;
|
||||||
|
|||||||
+13
-7
@@ -4380,10 +4380,9 @@ describe("uniswap decoder", () => {
|
|||||||
expect(detail(result, "Min. received").value).toBe("2.0000 USDC");
|
expect(detail(result, "Min. received").value).toBe("2.0000 USDC");
|
||||||
});
|
});
|
||||||
|
|
||||||
// With no minimum stated before it, a zero balance check is what sets the
|
// A zero balance check sets neither Token Out nor the minimum. The route
|
||||||
// output side, and it guarantees nothing. No step pays anyone, so the
|
// pays only the WRAP_ETH's WETH, to the router, where it stays.
|
||||||
// minimum is not said to be received.
|
test("a zero balance check after a WRAP_ETH into the router names no output token and no minimum", () => {
|
||||||
test("a zero balance check with no earlier minimum states no minimum", () => {
|
|
||||||
const data = buildExecute(
|
const data = buildExecute(
|
||||||
solidityPacked(["uint8", "uint8"], [0x0b, 0x0e]),
|
solidityPacked(["uint8", "uint8"], [0x0b, 0x0e]),
|
||||||
[
|
[
|
||||||
@@ -4396,9 +4395,16 @@ describe("uniswap decoder", () => {
|
|||||||
const result = uniswap.decode(data, ROUTER_ADDR, "0x1", {}, USER_ADDR);
|
const result = uniswap.decode(data, ROUTER_ADDR, "0x1", {}, USER_ADDR);
|
||||||
expect(result).not.toBeNull();
|
expect(result).not.toBeNull();
|
||||||
|
|
||||||
expect(detail(result, "Token Out").value).toContain("USDT");
|
expect(detail(result, "Token Out").value).toBe(
|
||||||
expect(detail(result, "Min. paid out").value).toBe(
|
"Unknown (not named in the calldata)",
|
||||||
"None (no minimum guaranteed)",
|
);
|
||||||
|
expect(detail(result, "Min. paid out")).toBeUndefined();
|
||||||
|
expect(detail(result, "Min. received")).toBeUndefined();
|
||||||
|
expect(detail(result, "Paid to").value).toBe(
|
||||||
|
"The router, where it stays (no later step pays it out)",
|
||||||
|
);
|
||||||
|
expect(detail(result, "Token moved into the router").address).toBe(
|
||||||
|
WETH_ADDR,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -716,6 +716,34 @@ describe("an UNWRAP_WETH makes the output ETH only when the router holds it", ()
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// A PERMIT2_TRANSFER_FROM moves the sender's WETH into the router. An
|
||||||
|
// UNWRAP_WETH pays that WETH to the user as ETH. A zero balance check of
|
||||||
|
// USDC sets neither Token Out nor the minimum, before the UNWRAP_WETH or
|
||||||
|
// after it (https://git.eeqj.de/sneak/AutistMask/issues/649).
|
||||||
|
test.each([
|
||||||
|
{
|
||||||
|
kind: "before the UNWRAP_WETH",
|
||||||
|
steps: [balanceCheck(USDC, 0n), unwrapWeth(MSG_SENDER)],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "after the UNWRAP_WETH",
|
||||||
|
steps: [unwrapWeth(MSG_SENDER), balanceCheck(USDC, 0n)],
|
||||||
|
},
|
||||||
|
])(
|
||||||
|
"WETH moved into the router and unwrapped, with a zero balance check of USDC $kind, reads as ETH with no minimum",
|
||||||
|
({ steps }) => {
|
||||||
|
const result = decode(
|
||||||
|
execute(
|
||||||
|
permit2TransferFrom(WETH, ADDRESS_THIS, ONE_WETH),
|
||||||
|
...steps,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(detail(result, "Token Out").value).toBe("ETH");
|
||||||
|
expect(detail(result, "Min. received")).toBeUndefined();
|
||||||
|
expect(detail(result, "Min. paid out")).toBeUndefined();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// A TAKE the decoder cannot read may pay part of the WETH to the user.
|
// A TAKE the decoder cannot read may pay part of the WETH to the user.
|
||||||
test("one V4 step paying WETH to the router beside a TAKE that cannot be read, then an UNWRAP_WETH, reads as ETH with no minimum", () => {
|
test("one V4 step paying WETH to the router beside a TAKE that cannot be read, then an UNWRAP_WETH, reads as ETH with no minimum", () => {
|
||||||
const result = decode(
|
const result = decode(
|
||||||
@@ -2848,17 +2876,16 @@ describe("the allow-revert flag", () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
test("a BALANCE_CHECK_ERC20 with the flag, and no minimum before it, states none", () => {
|
test("a BALANCE_CHECK_ERC20 with the flag, and no minimum before it, names no output token and no minimum", () => {
|
||||||
const check = balanceCheck(WETH, ONE_WETH);
|
const check = balanceCheck(WETH, ONE_WETH);
|
||||||
expect(detail(decode(execute(check)), "Min. paid out").value).toBe(
|
expect(detail(decode(execute(check)), "Min. paid out").value).toBe(
|
||||||
"1.0000 WETH",
|
"1.0000 WETH",
|
||||||
);
|
);
|
||||||
|
|
||||||
const withFlag = decode(execute(flagged(check)));
|
const withFlag = decode(execute(flagged(check)));
|
||||||
expect(detail(withFlag, "Token Out").address).toBe(WETH);
|
expect(detail(withFlag, "Token Out").value).toBe(UNNAMED);
|
||||||
expect(detail(withFlag, "Min. paid out").value).toBe(
|
expect(detail(withFlag, "Min. paid out")).toBeUndefined();
|
||||||
"None (no minimum guaranteed)",
|
expect(detail(withFlag, "Min. received")).toBeUndefined();
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Only the routers from UniversalRouterV2 on let a PERMIT2_PERMIT fail.
|
// Only the routers from UniversalRouterV2 on let a PERMIT2_PERMIT fail.
|
||||||
|
|||||||
Reference in new issue
Block a user