// SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "./uniswapv2/interfaces/IUniswapV2Pair.sol"; import "./uniswapv2/interfaces/IUniswapV2Router01.sol"; import "./uniswapv2/interfaces/IUniswapV2Factory.sol"; import "./uniswapv2/libraries/UniswapV2Library.sol"; // ShibaUniFetch helps your migrate your existing Uniswap LP tokens to ShibaSwap LP ones contract ShibaUniFetch { using SafeERC20 for IERC20; IUniswapV2Router01 public oldRouter; IUniswapV2Router01 public router; constructor(IUniswapV2Router01 _oldRouter, IUniswapV2Router01 _router) public { oldRouter = _oldRouter; router = _router; } function migrateWithPermit( address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public { IUniswapV2Pair pair = IUniswapV2Pair(pairForOldRouter(tokenA, tokenB)); pair.permit(msg.sender, address(this), liquidity, deadline, v, r, s); migrate(tokenA, tokenB, liquidity, amountAMin, amountBMin, deadline); } // msg.sender should have approved 'liquidity' amount of LP token of 'tokenA' and 'tokenB' function migrate( address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, uint256 deadline ) public { require(deadline >= block.timestamp, 'ShibaSwap: EXPIRED'); // Remove liquidity from the old router with permit (uint256 amountA, uint256 amountB) = removeLiquidity( tokenA, tokenB, liquidity, amountAMin, amountBMin, deadline ); // Add liquidity to the new router (uint256 pooledAmountA, uint256 pooledAmountB) = addLiquidity(tokenA, tokenB, amountA, amountB); // Send remaining tokens to msg.sender if (amountA > pooledAmountA) { IERC20(tokenA).safeTransfer(msg.sender, amountA - pooledAmountA); } if (amountB > pooledAmountB) { IERC20(tokenB).safeTransfer(msg.sender, amountB - pooledAmountB); } } function removeLiquidity( address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, uint256 deadline ) internal returns (uint256 amountA, uint256 amountB) { IUniswapV2Pair pair = IUniswapV2Pair(pairForOldRouter(tokenA, tokenB)); pair.transferFrom(msg.sender, address(pair), liquidity); (uint256 amount0, uint256 amount1) = pair.burn(address(this)); (address token0,) = UniswapV2Library.sortTokens(tokenA, tokenB); (amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0); require(amountA >= amountAMin, 'ShibaUniFetch: INSUFFICIENT_A_AMOUNT'); require(amountB >= amountBMin, 'ShibaUniFetch: INSUFFICIENT_B_AMOUNT'); } // calculates the CREATE2 address for a pair without making any external calls function pairForOldRouter(address tokenA, address tokenB) internal view returns (address pair) { (address token0, address token1) = UniswapV2Library.sortTokens(tokenA, tokenB); pair = address(uint(keccak256(abi.encodePacked( hex'ff', oldRouter.factory(), keccak256(abi.encodePacked(token0, token1)), hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash )))); } function addLiquidity( address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired ) internal returns (uint amountA, uint amountB) { (amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired); address pair = UniswapV2Library.pairFor(router.factory(), tokenA, tokenB); IERC20(tokenA).safeTransfer(pair, amountA); IERC20(tokenB).safeTransfer(pair, amountB); IUniswapV2Pair(pair).mint(msg.sender); } function _addLiquidity( address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired ) internal returns (uint256 amountA, uint256 amountB) { // create the pair if it doesn't exist yet IUniswapV2Factory factory = IUniswapV2Factory(router.factory()); if (factory.getPair(tokenA, tokenB) == address(0)) { factory.createPair(tokenA, tokenB); } (uint256 reserveA, uint256 reserveB) = UniswapV2Library.getReserves(address(factory), tokenA, tokenB); if (reserveA == 0 && reserveB == 0) { (amountA, amountB) = (amountADesired, amountBDesired); } else { uint256 amountBOptimal = UniswapV2Library.quote(amountADesired, reserveA, reserveB); if (amountBOptimal <= amountBDesired) { (amountA, amountB) = (amountADesired, amountBOptimal); } else { uint256 amountAOptimal = UniswapV2Library.quote(amountBDesired, reserveB, reserveA); assert(amountAOptimal <= amountADesired); (amountA, amountB) = (amountAOptimal, amountBDesired); } } } }