diff --git a/contracts/mainnet/connectors/uniswap/v3_auto_router/events.sol b/contracts/mainnet/connectors/uniswap/v3_auto_router/events.sol index 829fadd2..363e8054 100644 --- a/contracts/mainnet/connectors/uniswap/v3_auto_router/events.sol +++ b/contracts/mainnet/connectors/uniswap/v3_auto_router/events.sol @@ -1,34 +1,7 @@ pragma solidity ^0.7.0; contract Events { - event LogMint( - uint256 indexed tokenId, - uint256 liquidity, - uint256 amtA, - uint256 amtB, - int24 tickLower, - int24 tickUpper + event LogSwapExactTokensForTokens( + uint256 amountOut ); - - event LogDeposit( - uint256 indexed tokenId, - uint256 liquidity, - uint256 amountA, - uint256 amountB - ); - - event LogWithdraw( - uint256 indexed tokenId, - uint256 liquidity, - uint256 amountA, - uint256 amountB - ); - - event LogCollect( - uint256 tokenId, - uint256 amountA, - uint256 amountB - ); - - event LogBurnPosition(uint256 tokenId); } diff --git a/contracts/mainnet/connectors/uniswap/v3_auto_router/helpers.sol b/contracts/mainnet/connectors/uniswap/v3_auto_router/helpers.sol index 08a3e303..8edb4bb7 100644 --- a/contracts/mainnet/connectors/uniswap/v3_auto_router/helpers.sol +++ b/contracts/mainnet/connectors/uniswap/v3_auto_router/helpers.sol @@ -16,8 +16,17 @@ abstract contract Helpers is DSMath, Basic { */ INonfungiblePositionManager constant nftManager = INonfungiblePositionManager(0xC36442b4a4522E871399CD717aBDD847Ab11FE88); - ISwapRouter constant swapRouter = + ISwapRouter internal constant swapRouter = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564); + bytes32 internal constant POOL_INIT_CODE_HASH = + 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54; + + address constant COMMON_ADDRESSES = [ + 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, // WETH + 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48, // USDC + 0xdAC17F958D2ee523a2206206994597C13D831ec7, // USDT + 0x6b175474e89094c44da98b954eedeac495271d0f, // DAI + ] struct MintParams { address tokenA; @@ -43,6 +52,85 @@ abstract contract Helpers is DSMath, Basic { tokenId = nftManager.tokenOfOwnerByIndex(user, len - 1); } + function getPrice(address tokenIn, address tokenOut, uint24 fee) + external + view + returns (uint256 price) + { + IUniswapV3Pool pool = IUniswapV3Pool(factory.getPool(tokenIn, tokenOut, fee); + (uint160 sqrtPriceX96,,,,,,) = pool.slot0(); + return uint(sqrtPriceX96).mul(uint(sqrtPriceX96)).mul(1e18) >> (96 * 2); + } + + function getPoolAddress( + address tokenA, + address tokenB, + uint24 fee + ) internal pure returns (address pool) { + if (tokenA > tokenB) (tokenA, tokenB) = (tokenB, tokenA); + return + computeAddress( + 0x1F98431c8aD98523631AE4a59f267346ea31F984, + PoolKey({token0: tokenA, token1: tokenB, fee: fee}) + ); + } + + function computeAddress(address factory, PoolKey memory key) + internal + pure + returns (address pool) + { + require(key.token0 < key.token1); + pool = address( + uint160( + uint256( + keccak256( + abi.encodePacked( + hex"ff", + factory, + keccak256( + abi.encode(key.token0, key.token1, key.fee) + ), + POOL_INIT_CODE_HASH + ) + ) + ) + ) + ); + } + function getParams( + address tokenIn, + address tokenOut, + address recipient, + uint24 fee, + uint256 amountIn, + uint256 amountOutMinimum + ) internal view returns (ISwapRouter.ExactInputSingleParams memory params) { + params = ISwapRouter.ExactInputSingleParams({ + tokenIn: tokenIn, + tokenOut: tokenOut, + fee: fee, + recipient: recipient, + deadline: block.timestamp + 1, + amountIn: amountIn, + amountOutMinimum: amountOutMinimum, + sqrtPriceLimitX96: getPriceLimit( + amountIn, + tokenIn < tokenOut, + tokenIn, + tokenOut, + fee + ) + }); + } + + function swapSingleInput(ISwapRouter.ExactInputSingleParams memory params) + internal + returns (uint256) + { + return (uint256(swapRouter.exactInputSingle(params))); + } + function getMinAmount( TokenInterface token, uint256 amt, diff --git a/contracts/mainnet/connectors/uniswap/v3_auto_router/main.sol b/contracts/mainnet/connectors/uniswap/v3_auto_router/main.sol index 3107ad60..320cc497 100644 --- a/contracts/mainnet/connectors/uniswap/v3_auto_router/main.sol +++ b/contracts/mainnet/connectors/uniswap/v3_auto_router/main.sol @@ -12,33 +12,65 @@ import {Events} from "./events.sol"; abstract contract UniswapResolver is Helpers, Events { function swapExactTokensForTokens( - uint amountIn, - uint amountOutMin, - bytes path, - address to, - uint deadline - ) external virtual override ensure(deadline) returns (uint[] memory amounts) { - amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path); - require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'); - TransferHelper.safeTransferFrom( - path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0] - ); - _swap(amounts, path, to); - } + address tokenIn, + address tokenOut, + address recipient, + uint256 deadline, + uint24 fee, + uint256 amountIn, + uint256 amountOutMinimum + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + address poolAddr = getPoolAddress(tokenIn, tokenOut, fee); + uint256 maxPrice = 0; + uint pathIndex = 0; - function swapTokensForExactTokens( - uint amountOut, - uint amountInMax, - bytes path, - address to, - uint deadline - ) external virtual override ensure(deadline) returns (uint[] memory amounts) { - amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path); - require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT'); - TransferHelper.safeTransferFrom( - path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0] + for (uint i = 0; i < COMMON_ADDRESSES.length; i++) { + uint256 price1 = getPrice(tokenIn, COMMON_ADDRESSES[i], fee); + uint256 price2 = getPrice(COMMON_ADDRESSES[i], tokenOut, fee); + uint256 price = (price1 + price2) / 2; + + if (maxPrice < price) { + maxPrice = price; + pathIndex = i; + } + } + + if (poolAddr != address(0)) { + uint256 price = getPrice(tokenIn, tokenOut, fee); + + if (maxPrice < price) { + maxPrice = price; + } + } + + IERC20(tokenIn).safeApprove(address(swapRouter), amountIn); + uint256 amountOut1 = swapSingleInput( + getParams( + tokenIn, + COMMON_ADDRESSES[pathIndex], + recipient, + fee, + amountIn, + amountOutMinimum + ) ); - _swap(amounts, path, to); + uint256 amountOut = swapSingleInput( + getParams( + COMMON_ADDRESSES[pathIndex], + tokenOut + recipient, + fee, + amountOut1, + amountOutMinimum + ) + ); + + _eventName = "LogSwapExactTokensForTokens(uint256)"; + _eventParam = abi.encode(amountOut); } }