// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "../../../liquidity/interfaces/ILiquidityProvider.sol"; import "../RouteTypesV2.sol"; import "../interfaces/IRouteExecutorAdapter.sol"; contract DodoRouteExecutorAdapter is IRouteExecutorAdapter { using SafeERC20 for IERC20; function validate( RouteTypesV2.RouteLeg calldata leg ) external view override returns (bool ok, string memory reason) { if (leg.provider != RouteTypesV2.Provider.Dodo) { return (false, "DodoRouteExecutorAdapter: invalid provider"); } if (leg.target == address(0)) { return (false, "DodoRouteExecutorAdapter: zero target"); } if (leg.tokenIn == address(0) || leg.tokenOut == address(0)) { return (false, "DodoRouteExecutorAdapter: zero token"); } if (leg.providerData.length != 32) { return (false, "DodoRouteExecutorAdapter: invalid providerData"); } address poolAddress = abi.decode(leg.providerData, (address)); if (poolAddress == address(0)) { return (false, "DodoRouteExecutorAdapter: zero pool"); } if (!ILiquidityProvider(leg.target).supportsTokenPair(leg.tokenIn, leg.tokenOut)) { return (false, "DodoRouteExecutorAdapter: unsupported pair"); } return (true, ""); } function quote( RouteTypesV2.RouteLeg calldata leg, uint256 amountIn ) external view override returns (uint256 amountOut, uint256 gasEstimate) { (amountOut,) = ILiquidityProvider(leg.target).getQuote(leg.tokenIn, leg.tokenOut, amountIn); gasEstimate = ILiquidityProvider(leg.target).estimateGas(leg.tokenIn, leg.tokenOut, amountIn); } function execute( RouteTypesV2.RouteLeg calldata leg, uint256 amountIn ) external override returns (uint256 amountOut) { IERC20(leg.tokenIn).forceApprove(leg.target, 0); IERC20(leg.tokenIn).forceApprove(leg.target, amountIn); amountOut = ILiquidityProvider(leg.target).executeSwap( leg.tokenIn, leg.tokenOut, amountIn, leg.minAmountOut ); IERC20(leg.tokenOut).safeTransfer(msg.sender, amountOut); } }