diff --git a/foundry/interfaces/IExecutor.sol b/foundry/interfaces/IExecutor.sol index 0a60022..0316e08 100644 --- a/foundry/interfaces/IExecutor.sol +++ b/foundry/interfaces/IExecutor.sol @@ -24,6 +24,10 @@ interface IExecutor { uint256 givenAmount, bytes calldata data ) external payable returns (uint256 calculatedAmount); + + function handleCallback( + bytes calldata callbackData + ) external returns (address tokenOwed, uint256 amountOwed); } interface IExecutorErrors { diff --git a/foundry/src/TychoRouter.sol b/foundry/src/TychoRouter.sol index 9d77dec..374a427 100644 --- a/foundry/src/TychoRouter.sol +++ b/foundry/src/TychoRouter.sol @@ -11,7 +11,6 @@ import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import "@openzeppelin/contracts/utils/Pausable.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "@permit2/src/interfaces/IAllowanceTransfer.sol"; -import "@uniswap/v3-updated/CallbackValidationV2.sol"; import "./ExecutionDispatcher.sol"; import "./CallbackVerificationDispatcher.sol"; import {LibSwap} from "../lib/LibSwap.sol"; @@ -66,24 +65,15 @@ contract TychoRouter is ); event FeeSet(uint256 indexed oldFee, uint256 indexed newFee); - address private immutable _usv3Factory; - - constructor( - IPoolManager _poolManager, - address _permit2, - address weth, - address usv3Factory - ) SafeCallback(_poolManager) { - if ( - _permit2 == address(0) || weth == address(0) - || usv3Factory == address(0) - ) { + constructor(IPoolManager _poolManager, address _permit2, address weth) + SafeCallback(_poolManager) + { + if (_permit2 == address(0) || weth == address(0)) { revert TychoRouter__AddressZero(); } permit2 = IAllowanceTransfer(_permit2); _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); _weth = IWETH(weth); - _usv3Factory = usv3Factory; } /** @@ -409,40 +399,6 @@ 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 { - (uint256 amountOwed, address tokenOwed) = - _verifyUSV3Callback(amount0Delta, amount1Delta, msgData); - IERC20(tokenOwed).safeTransfer(msg.sender, amountOwed); - } - - function _verifyUSV3Callback( - int256 amount0Delta, - int256 amount1Delta, - bytes calldata data - ) internal view returns (uint256 amountIn, address tokenIn) { - tokenIn = address(bytes20(data[0:20])); - address tokenOut = address(bytes20(data[20:40])); - uint24 poolFee = uint24(bytes3(data[40:43])); - - // slither-disable-next-line unused-return - CallbackValidationV2.verifyCallback( - _usv3Factory, tokenIn, tokenOut, poolFee - ); - - amountIn = - amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta); - - return (amountIn, tokenIn); - } - function _unlockCallback(bytes calldata data) internal override diff --git a/foundry/src/executors/UniswapV3Executor.sol b/foundry/src/executors/UniswapV3Executor.sol index ac986c5..cc1058e 100644 --- a/foundry/src/executors/UniswapV3Executor.sol +++ b/foundry/src/executors/UniswapV3Executor.sol @@ -4,14 +4,23 @@ pragma solidity ^0.8.26; 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"; error UniswapV3Executor__InvalidDataLength(); contract UniswapV3Executor is IExecutor { + using SafeERC20 for IERC20; + uint160 private constant MIN_SQRT_RATIO = 4295128739; uint160 private constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342; + address public immutable factory; + + constructor(address factory_) { + factory = factory_; + } + // slither-disable-next-line locked-ether function swap(uint256 amountIn, bytes calldata data) external @@ -50,6 +59,40 @@ contract UniswapV3Executor is IExecutor { } } + function handleCallback(bytes calldata msgData) + external + returns (address tokenOwed, uint256 amountOwed) + { + int256 amount0Delta; + int256 amount1Delta; + + (amount0Delta, amount1Delta) = + abi.decode(msgData[:64], (int256, int256)); + + bytes calldata remainingData = msgData[64:]; + (amountOwed, tokenOwed) = + _verifyUSV3Callback(amount0Delta, amount1Delta, remainingData); + IERC20(tokenOwed).safeTransfer(msg.sender, amountOwed); + } + + function _verifyUSV3Callback( + int256 amount0Delta, + int256 amount1Delta, + bytes calldata data + ) internal view returns (uint256 amountIn, address tokenIn) { + tokenIn = address(bytes20(data[0:20])); + address tokenOut = address(bytes20(data[20:40])); + uint24 poolFee = uint24(bytes3(data[40:43])); + + // slither-disable-next-line unused-return + CallbackValidationV2.verifyCallback(factory, tokenIn, tokenOut, poolFee); + + amountIn = + amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta); + + return (amountIn, tokenIn); + } + function _decodeData(bytes calldata data) internal pure