fix: each router release names and reads its own commands (closes #592)
Each Universal Router release now carries the command it runs for each command type, by the name its pinned Commands.sol gives it, and the decoder names and reads each step as that command instead of using one table for every router. On UniversalRouterV1 and UniversalRouterV1_2_V2Support, 0x10 to 0x13 are NFT commands, such as Seaport: they are no longer read as V4 commands, so they draw no swap lines and their payouts count as unread. UniversalRouterV1 has no BALANCE_CHECK_ERC20 and reverts on 0x0e, which is now listed as Command 0x0e and sets no minimum. No release lets a V4 swap fail, so the zero-minimum reading for a flagged one is gone. Model: opus-5-5
This commit was merged in pull request #616.
This commit is contained in:
+304
-29
@@ -2,7 +2,9 @@
|
||||
// (https://git.eeqj.de/sneak/AutistMask/issues/594 and
|
||||
// https://git.eeqj.de/sneak/AutistMask/issues/599), the allow-revert flag
|
||||
// on the steps that pay it
|
||||
// (https://git.eeqj.de/sneak/AutistMask/issues/602), and the address whose
|
||||
// (https://git.eeqj.de/sneak/AutistMask/issues/602), the command each router
|
||||
// release runs for a command type
|
||||
// (https://git.eeqj.de/sneak/AutistMask/issues/592), and the address whose
|
||||
// balance a BALANCE_CHECK_ERC20 checks
|
||||
// (https://git.eeqj.de/sneak/AutistMask/issues/600).
|
||||
//
|
||||
@@ -1570,32 +1572,6 @@ describe("the allow-revert flag", () => {
|
||||
);
|
||||
});
|
||||
|
||||
// On these two routers 0x10 is an NFT market call the router lets fail,
|
||||
// still read as a V4 swap
|
||||
// (https://git.eeqj.de/sneak/AutistMask/issues/592).
|
||||
test.each([
|
||||
{ router: "UniversalRouterV1", address: ROUTER_V1 },
|
||||
{ router: "UniversalRouterV1_2_V2Support", address: ROUTER_V1_2 },
|
||||
])(
|
||||
"on $router, a V4_SWAP with the flag is allowed to fail and states no minimum",
|
||||
({ address }) => {
|
||||
const step = v4Swap(SWAP_USDT_FOR_USDC, SETTLE_USDT, takeAll(USDC));
|
||||
|
||||
const plain = decode(execute(step), USER, address);
|
||||
expect(detail(plain, "Steps").value).toBe("V4 Swap");
|
||||
expect(detail(plain, "Min. received").value).toBe("1990.0000 USDC");
|
||||
|
||||
const withFlag = decode(execute(flagged(step)), USER, address);
|
||||
expect(detail(withFlag, "Steps").value).toBe(
|
||||
"V4 Swap (allowed to fail)",
|
||||
);
|
||||
expect(detail(withFlag, "Token Out").address).toBe(USDC);
|
||||
expect(detail(withFlag, "Min. received").value).toBe(
|
||||
"None (no minimum guaranteed)",
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
// Only the routers from UniversalRouterV2 on let a PERMIT2_PERMIT fail.
|
||||
test.each([
|
||||
{ router: "UniversalRouterV1", address: ROUTER_V1, mark: "" },
|
||||
@@ -1663,14 +1639,14 @@ describe("the allow-revert flag", () => {
|
||||
address: ROUTER_V1,
|
||||
command: "FOUNDATION",
|
||||
id: 0x1c,
|
||||
name: "Command 0x1c",
|
||||
name: "Foundation",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1_2_V2Support",
|
||||
address: ROUTER_V1_2,
|
||||
command: "ELEMENT_MARKET",
|
||||
id: 0x1e,
|
||||
name: "Command 0x1e",
|
||||
name: "Element Market",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV2",
|
||||
@@ -1718,6 +1694,305 @@ describe("the allow-revert flag", () => {
|
||||
);
|
||||
});
|
||||
|
||||
// https://git.eeqj.de/sneak/AutistMask/issues/592: each release runs its own
|
||||
// command for a command type, as its Commands.sol names it. The decoder named
|
||||
// and read every type as UniversalRouterV2 does, so on the two older routers
|
||||
// an NFT command read as a V4 swap, and on UniversalRouterV1, which reverts on
|
||||
// 0x0e, that type read as a balance check that set the minimum.
|
||||
describe("the command each release runs for a command type", () => {
|
||||
// Inputs UniversalRouterV2 reads as a V4 swap of 2,000 USDT for at least
|
||||
// 1,990 USDC paid to the user, and as a check that the user holds at
|
||||
// least 1 WETH.
|
||||
const swapInput = v4Swap(SWAP_USDT_FOR_USDC, SETTLE_USDT, takeAll(USDC))[1];
|
||||
const checkInput = balanceCheck(WETH, ONE_WETH)[1];
|
||||
// The lines of a transaction whose one step the decoder does not read.
|
||||
const NOT_READ = [
|
||||
"Protocol",
|
||||
"Token In",
|
||||
"Token Out",
|
||||
"Paid to",
|
||||
"Steps",
|
||||
"Deadline",
|
||||
];
|
||||
|
||||
test.each([
|
||||
{
|
||||
router: "UniversalRouterV1",
|
||||
address: ROUTER_V1,
|
||||
id: 0x0e,
|
||||
input: checkInput,
|
||||
name: "Command 0x0e",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1",
|
||||
address: ROUTER_V1,
|
||||
id: 0x10,
|
||||
input: swapInput,
|
||||
name: "Seaport",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1",
|
||||
address: ROUTER_V1,
|
||||
id: 0x11,
|
||||
input: swapInput,
|
||||
name: "LooksRare 721",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1",
|
||||
address: ROUTER_V1,
|
||||
id: 0x12,
|
||||
input: swapInput,
|
||||
name: "NFTX",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1",
|
||||
address: ROUTER_V1,
|
||||
id: 0x13,
|
||||
input: swapInput,
|
||||
name: "CryptoPunks",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1",
|
||||
address: ROUTER_V1,
|
||||
id: 0x14,
|
||||
input: swapInput,
|
||||
name: "LooksRare 1155",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1",
|
||||
address: ROUTER_V1,
|
||||
id: 0x15,
|
||||
input: swapInput,
|
||||
name: "Owner Check 721",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1",
|
||||
address: ROUTER_V1,
|
||||
id: 0x16,
|
||||
input: swapInput,
|
||||
name: "Owner Check 1155",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1",
|
||||
address: ROUTER_V1,
|
||||
id: 0x17,
|
||||
input: swapInput,
|
||||
name: "Sweep ERC-721",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1",
|
||||
address: ROUTER_V1,
|
||||
id: 0x18,
|
||||
input: swapInput,
|
||||
name: "X2Y2 721",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1",
|
||||
address: ROUTER_V1,
|
||||
id: 0x19,
|
||||
input: swapInput,
|
||||
name: "Sudoswap",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1",
|
||||
address: ROUTER_V1,
|
||||
id: 0x1a,
|
||||
input: swapInput,
|
||||
name: "NFT20",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1",
|
||||
address: ROUTER_V1,
|
||||
id: 0x1b,
|
||||
input: swapInput,
|
||||
name: "X2Y2 1155",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1",
|
||||
address: ROUTER_V1,
|
||||
id: 0x1c,
|
||||
input: swapInput,
|
||||
name: "Foundation",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1",
|
||||
address: ROUTER_V1,
|
||||
id: 0x1d,
|
||||
input: swapInput,
|
||||
name: "Sweep ERC-1155",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1_2_V2Support",
|
||||
address: ROUTER_V1_2,
|
||||
id: 0x10,
|
||||
input: swapInput,
|
||||
name: "Seaport V1.5",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1_2_V2Support",
|
||||
address: ROUTER_V1_2,
|
||||
id: 0x11,
|
||||
input: swapInput,
|
||||
name: "LooksRare V2",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1_2_V2Support",
|
||||
address: ROUTER_V1_2,
|
||||
id: 0x12,
|
||||
input: swapInput,
|
||||
name: "NFTX",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1_2_V2Support",
|
||||
address: ROUTER_V1_2,
|
||||
id: 0x13,
|
||||
input: swapInput,
|
||||
name: "CryptoPunks",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1_2_V2Support",
|
||||
address: ROUTER_V1_2,
|
||||
id: 0x14,
|
||||
input: swapInput,
|
||||
name: "Command 0x14",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1_2_V2Support",
|
||||
address: ROUTER_V1_2,
|
||||
id: 0x15,
|
||||
input: swapInput,
|
||||
name: "Owner Check 721",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1_2_V2Support",
|
||||
address: ROUTER_V1_2,
|
||||
id: 0x16,
|
||||
input: swapInput,
|
||||
name: "Owner Check 1155",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1_2_V2Support",
|
||||
address: ROUTER_V1_2,
|
||||
id: 0x17,
|
||||
input: swapInput,
|
||||
name: "Sweep ERC-721",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1_2_V2Support",
|
||||
address: ROUTER_V1_2,
|
||||
id: 0x18,
|
||||
input: swapInput,
|
||||
name: "X2Y2 721",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1_2_V2Support",
|
||||
address: ROUTER_V1_2,
|
||||
id: 0x19,
|
||||
input: swapInput,
|
||||
name: "Sudoswap",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1_2_V2Support",
|
||||
address: ROUTER_V1_2,
|
||||
id: 0x1a,
|
||||
input: swapInput,
|
||||
name: "NFT20",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1_2_V2Support",
|
||||
address: ROUTER_V1_2,
|
||||
id: 0x1b,
|
||||
input: swapInput,
|
||||
name: "X2Y2 1155",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1_2_V2Support",
|
||||
address: ROUTER_V1_2,
|
||||
id: 0x1c,
|
||||
input: swapInput,
|
||||
name: "Foundation",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1_2_V2Support",
|
||||
address: ROUTER_V1_2,
|
||||
id: 0x1d,
|
||||
input: swapInput,
|
||||
name: "Sweep ERC-1155",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1_2_V2Support",
|
||||
address: ROUTER_V1_2,
|
||||
id: 0x1e,
|
||||
input: swapInput,
|
||||
name: "Element Market",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1_2_V2Support",
|
||||
address: ROUTER_V1_2,
|
||||
id: 0x20,
|
||||
input: swapInput,
|
||||
name: "Seaport V1.4",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV1_2_V2Support",
|
||||
address: ROUTER_V1_2,
|
||||
id: 0x22,
|
||||
input: swapInput,
|
||||
name: "Approve ERC-20",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV2",
|
||||
address: ROUTER,
|
||||
id: 0x11,
|
||||
input: swapInput,
|
||||
name: "V3 Position Mgr Permit",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV2",
|
||||
address: ROUTER,
|
||||
id: 0x12,
|
||||
input: swapInput,
|
||||
name: "V3 Position Mgr Call",
|
||||
},
|
||||
{
|
||||
router: "UniversalRouterV2",
|
||||
address: ROUTER,
|
||||
id: 0x13,
|
||||
input: swapInput,
|
||||
name: "V4 Initialize Pool",
|
||||
},
|
||||
])(
|
||||
"on $router, '$name' is a step the decoder does not read",
|
||||
({ address, id, input, name }) => {
|
||||
const result = decode(execute([id, input]), USER, address);
|
||||
expect(detail(result, "Steps").value).toBe(name);
|
||||
expect(result.name).toBe("Uniswap Swap");
|
||||
expect(labels(result)).toEqual(NOT_READ);
|
||||
expect(paidTo(result)).toEqual([UNDECODED]);
|
||||
},
|
||||
);
|
||||
|
||||
test.each([
|
||||
{ router: "UniversalRouterV1_2_V2Support", address: ROUTER_V1_2 },
|
||||
{ router: "UniversalRouterV2", address: ROUTER },
|
||||
])(
|
||||
"on $router, 0x0e is a balance check, which sets the minimum",
|
||||
({ address }) => {
|
||||
const result = decode(execute([0x0e, checkInput]), USER, address);
|
||||
expect(detail(result, "Steps").value).toBe("Balance Check");
|
||||
expect(detail(result, "Token Out").address).toBe(WETH);
|
||||
expect(detail(result, "Min. paid out").value).toBe("1.0000 WETH");
|
||||
},
|
||||
);
|
||||
|
||||
test("on UniversalRouterV2, 0x10 is a V4 swap", () => {
|
||||
const result = decode(execute([0x10, swapInput]), USER, ROUTER);
|
||||
expect(detail(result, "Steps").value).toBe("V4 Swap");
|
||||
expect(result.name).toBe("Swap USDT → USDC");
|
||||
expect(detail(result, "Min. received").value).toBe("1990.0000 USDC");
|
||||
});
|
||||
});
|
||||
|
||||
// https://git.eeqj.de/sneak/AutistMask/issues/600: on every release that has
|
||||
// BALANCE_CHECK_ERC20, the router checks the balance of the owner as written,
|
||||
// without map(), so address(1) and address(2) there are those addresses, not
|
||||
|
||||
Reference in New Issue
Block a user