diff --git a/script/Benchmark.s.sol b/script/Benchmark.s.sol index a25a2ba..5e62a31 100644 --- a/script/Benchmark.s.sol +++ b/script/Benchmark.s.sol @@ -60,7 +60,9 @@ contract Benchmark is Script, OneInchContracts { v5AggregationRouter.swap(v5AggregationExecutor, v5Desc, v5Permit, v5Data); // Optimized router v5 swap call - (bool v5Ok,) = payable(v5Rtr).call(abi.encode(DAI, 100_000, v5Desc.minReturnAmount, v5Data, 0)); + (bool v5Ok,) = payable(v5Rtr).call( + abi.encodePacked(DAI, uint96(100_000), uint96(v5Desc.minReturnAmount), uint256(0), v5Data) + ); if (!v5Ok) revert OptimizedV5RouterFailed(); @@ -78,7 +80,9 @@ contract Benchmark is Script, OneInchContracts { v4AggregationRouter.swap(v4AggregationExecutor, v4Desc, v4Data); // Optimized v4 swap call - (bool v4Ok,) = payable(v4Rtr).call(abi.encode(DAI, 100_000, v4Desc.minReturnAmount, v4Data, 0)); + (bool v4Ok,) = payable(v4Rtr).call( + abi.encodePacked(DAI, uint96(100_000), uint96(v4Desc.minReturnAmount), uint256(0), v4Data) + ); if (!v4Ok) revert OptimizedV4RouterFailed(); } } diff --git a/src/V4Router.sol b/src/V4Router.sol index d36ab33..9061eec 100644 --- a/src/V4Router.sol +++ b/src/V4Router.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity >=0.8.0; +pragma solidity ^0.8.0; import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; @@ -22,8 +22,12 @@ contract V4Router is AggregationV4BaseRouter { // Flags match specific constant masks. There is no documentation on these. fallback() external payable { - (address dstToken, uint256 amount, uint256 minReturnAmount, bytes memory data, uint256 flags) = - abi.decode(msg.data, (address, uint256, uint256, bytes, uint256)); + address dstToken = address(bytes20(msg.data[0:20])); + uint256 amount = uint256(uint96(bytes12(msg.data[20:32]))); + uint256 minReturnAmount = uint256(uint96(bytes12(msg.data[32:44]))); + uint256 flags = uint256(uint8(bytes1(msg.data[44:45]))); + bytes memory data = bytes(msg.data[45:msg.data.length]); + IERC20(TOKEN).transferFrom(msg.sender, address(this), amount); AGGREGATION_ROUTER.swap( AGGREGATION_EXECUTOR, diff --git a/src/V5Router.sol b/src/V5Router.sol index 4c10a01..d8c8b70 100644 --- a/src/V5Router.sol +++ b/src/V5Router.sol @@ -22,8 +22,12 @@ contract V5Router is AggregationV5BaseRouter { // Flags match specific constant masks. There is no documentation on these. fallback() external payable { - (address dstToken, uint256 amount, uint256 minReturnAmount, bytes memory data, uint256 flags) = - abi.decode(msg.data, (address, uint256, uint256, bytes, uint256)); + address dstToken = address(bytes20(msg.data[0:20])); + uint256 amount = uint256(uint96(bytes12(msg.data[20:32]))); + uint256 minReturnAmount = uint256(uint96(bytes12(msg.data[32:44]))); + uint256 flags = uint256(uint8(bytes1(msg.data[44:45]))); + bytes memory data = bytes(msg.data[45:msg.data.length]); + IERC20(TOKEN).transferFrom(msg.sender, address(this), amount); AGGREGATION_ROUTER.swap( AGGREGATION_EXECUTOR, diff --git a/test/V4Router.t.sol b/test/V4Router.t.sol index 3435036..04a17ac 100644 --- a/test/V4Router.t.sol +++ b/test/V4Router.t.sol @@ -100,7 +100,9 @@ contract Fallback is V4RouterTest { assertEq(startingUNIBalance, 0, "Starting balance is incorrect"); // Optimized router call - (bool ok,) = payable(routerAddr).call(abi.encode(UNI, 100_000, desc.minReturnAmount, data, 0)); + (bool ok,) = payable(routerAddr).call( + abi.encodePacked(UNI, uint96(100_000), uint96(desc.minReturnAmount), uint8(0), data) + ); assertTrue(ok, "Swap failed"); @@ -130,8 +132,9 @@ contract Fallback is V4RouterTest { vm.startPrank(swapSenderAddress); IERC20(USDC).approve(routerAddr, 10_000_000); uint256 startingBalance = IERC20(USDC).balanceOf(swapSenderAddress); - (bool ok,) = - payable(routerAddr).call(abi.encode(UNI, 10_000_000, desc.minReturnAmount, data, 0)); + (bool ok,) = payable(routerAddr).call( + abi.encodePacked(UNI, uint96(10_000_000), uint96(desc.minReturnAmount), uint8(0), data) + ); uint256 endingBalance = IERC20(USDC).balanceOf(swapSenderAddress); assertTrue(!ok, "Swap succeeded"); @@ -142,8 +145,9 @@ contract Fallback is V4RouterTest { (IV4AggregationRouter.SwapDescription memory desc, bytes memory data) = helper_apiParams(); IERC20(USDC).approve(routerAddr, 250_000); uint256 startingBalance = IERC20(USDC).balanceOf(swapSenderAddress); - (bool ok,) = - payable(routerAddr).call(abi.encode(address(0), 250_000, desc.minReturnAmount, data, 0)); + (bool ok,) = payable(routerAddr).call( + abi.encodePacked(address(0), uint96(250_000), uint96(desc.minReturnAmount), uint8(0), data) + ); uint256 endingBalance = IERC20(USDC).balanceOf(swapSenderAddress); assertTrue(!ok, "Swap succeeded"); diff --git a/test/V5Router.t.sol b/test/V5Router.t.sol index afe6d15..9600db4 100644 --- a/test/V5Router.t.sol +++ b/test/V5Router.t.sol @@ -106,7 +106,9 @@ contract Fallback is V5RouterTest { assertEq(startingUNIBalance, 0, "Starting balance is not 0"); // Optimized router call - (bool ok,) = payable(routerAddr).call(abi.encode(UNI, 100_000, desc.minReturnAmount, data, 0)); + (bool ok,) = payable(routerAddr).call( + abi.encodePacked(UNI, uint96(100_000), uint96(desc.minReturnAmount), uint8(0), data) + ); assertTrue(ok, "Swap failed"); @@ -136,8 +138,9 @@ contract Fallback is V5RouterTest { vm.startPrank(swapSenderAddress); IERC20(USDC).approve(routerAddr, 10_000_000); uint256 startingBalance = IERC20(USDC).balanceOf(swapSenderAddress); - (bool ok,) = - payable(routerAddr).call(abi.encode(UNI, 10_000_000, desc.minReturnAmount, data, 0)); + (bool ok,) = payable(routerAddr).call( + abi.encodePacked(UNI, uint96(10_000_000), uint96(desc.minReturnAmount), uint8(0), data) + ); uint256 endingBalance = IERC20(USDC).balanceOf(swapSenderAddress); assertTrue(!ok, "Swap succeeded"); @@ -148,8 +151,11 @@ contract Fallback is V5RouterTest { (IV5AggregationRouter.SwapDescription memory desc,, bytes memory data) = helper_apiParams(); IERC20(USDC).approve(routerAddr, 250_000); uint256 startingBalance = IERC20(USDC).balanceOf(swapSenderAddress); - (bool ok,) = - payable(routerAddr).call(abi.encode(address(0), 250_000, desc.minReturnAmount, data, 0)); + (bool ok,) = payable(routerAddr).call( + abi.encodePacked( + address(0), uint96(250_000), uint96(desc.minReturnAmount), uint8(0), bytes(data) + ) + ); uint256 endingBalance = IERC20(USDC).balanceOf(swapSenderAddress); assertTrue(!ok, "Swap succeeded"); assertEq(startingBalance, endingBalance, "Funds were held by the router contract");