diff --git a/foundry/src/ExecutionDispatcher.sol b/foundry/src/ExecutionDispatcher.sol index eae85dc..1283b41 100644 --- a/foundry/src/ExecutionDispatcher.sol +++ b/foundry/src/ExecutionDispatcher.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.26; import "@interfaces/IExecutor.sol"; +import "forge-std/console.sol"; error ExecutionDispatcher__UnapprovedExecutor(); error ExecutionDispatcher__NonContractExecutor(); @@ -80,19 +81,25 @@ contract ExecutionDispatcher { calculatedAmount = abi.decode(result, (uint256)); } - function _handleCallback(bytes calldata data) internal { - // Take last 20 bytes (excluding the final byte) - address executor = - address(bytes20(data[data.length - 21:data.length - 1])); + function _handleCallback(bytes4 selector, bytes memory data) internal { + // Access the last 20 bytes of the bytes memory data using assembly + address executor; + // slither-disable-next-line assembly + assembly { + let pos := sub(add(add(data, 0x20), mload(data)), 20) + executor := mload(pos) + executor := shr(96, executor) + } if (!executors[executor]) { revert ExecutionDispatcher__UnapprovedExecutor(); } + selector = + selector == bytes4(0) ? IExecutor.handleCallback.selector : selector; // slither-disable-next-line controlled-delegatecall,low-level-calls - (bool success, bytes memory result) = executor.delegatecall( - abi.encodeWithSelector(IExecutor.handleCallback.selector, data) - ); + (bool success, bytes memory result) = + executor.delegatecall(abi.encodeWithSelector(selector, data)); if (!success) { revert( diff --git a/foundry/src/TychoRouter.sol b/foundry/src/TychoRouter.sol index 15e45c3..8084afc 100644 --- a/foundry/src/TychoRouter.sol +++ b/foundry/src/TychoRouter.sol @@ -15,6 +15,7 @@ import "./ExecutionDispatcher.sol"; import {LibSwap} from "../lib/LibSwap.sol"; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol"; +import "forge-std/console.sol"; error TychoRouter__WithdrawalFailed(); error TychoRouter__AddressZero(); @@ -228,9 +229,10 @@ contract TychoRouter is * This function will static call a verifier contract and should revert if the * caller is not a pool. */ - fallback() external { - _handleCallback(msg.data); - } + // fallback() external { + // bytes4 selector = bytes4(msg.data[:4]); + // _handleCallback(selector, msg.data[4:]); + // } /** * @dev Pauses the contract @@ -388,6 +390,20 @@ contract TychoRouter is */ receive() external payable {} + /** + * @dev Called by UniswapV3 pool when swapping on it. + * See in IUniswapV3SwapCallback for documentation. + */ + function uniswapV3SwapCallback( + int256 amount0Delta, + int256 amount1Delta, + bytes calldata msgData + ) external { + _handleCallback( + bytes4(0), abi.encodePacked(amount0Delta, amount1Delta, msgData) + ); + } + function _unlockCallback(bytes calldata data) internal override diff --git a/foundry/src/executors/UniswapV3Executor.sol b/foundry/src/executors/UniswapV3Executor.sol index f5b6c06..906c771 100644 --- a/foundry/src/executors/UniswapV3Executor.sol +++ b/foundry/src/executors/UniswapV3Executor.sol @@ -5,6 +5,7 @@ import "@interfaces/IExecutor.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; import "@uniswap/v3-updated/CallbackValidationV2.sol"; +import "forge-std/console.sol"; error UniswapV3Executor__InvalidDataLength(); error UniswapV3Executor__InvalidFactory(); @@ -69,11 +70,10 @@ contract UniswapV3Executor is IExecutor { external returns (bytes memory result) { - // Skip first 4 bytes of function selector and decode the two int256 values (int256 amount0Delta, int256 amount1Delta) = - abi.decode(msgData[4:68], (int256, int256)); + abi.decode(msgData[:64], (int256, int256)); - bytes calldata remainingData = msgData[68:]; + bytes calldata remainingData = msgData[64:]; (uint256 amountOwed, address tokenOwed) = _verifyUSV3Callback(amount0Delta, amount1Delta, remainingData); @@ -87,9 +87,6 @@ contract UniswapV3Executor is IExecutor { int256 amount1Delta, bytes calldata data ) internal view returns (uint256 amountIn, address tokenIn) { - // Skip the first 64 bytes (32 bytes offset + 32 bytes length) - data = data[64:]; - tokenIn = address(bytes20(data[0:20])); address tokenOut = address(bytes20(data[20:40])); uint24 poolFee = uint24(bytes3(data[40:43]));