```\n// **** ADD LIQUIDITY ****\nfunction _addLiquidity(\n address tokenA,\n address tokenB,\n uint amountADesired,\n uint amountBDesired,\n uint amountAMin,\n uint amountBMin\n) internal virtual returns (uint amountA, uint amountB) {\n // create the pair if it doesn't exist yet\n if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) {\n  IUniswapV2Factory(factory).createPair(tokenA, tokenB);\n }\n (uint reserveA, uint reserveB) = UniswapV2Library.getReserves(factory, tokenA, tokenB);\n if (reserveA == 0 && reserveB == 0) {\n  (amountA, amountB) = (amountADesired, amountBDesired);\n } else {\n  uint amountBOptimal = UniswapV2Library.quote(amountADesired, reserveA, reserveB);\n  if (amountBOptimal <= amountBDesired) {\n   require(amountBOptimal >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT');\n   (amountA, amountB) = (amountADesired, amountBOptimal);\n  } else {\n   uint amountAOptimal = UniswapV2Library.quote(amountBDesired, reserveB, reserveA);\n   assert(amountAOptimal <= amountADesired);\n   require(amountAOptimal >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT');\n   (amountA, amountB) = (amountAOptimal, amountBDesired);\n  }\n }\n}\n\nfunction addLiquidity(\n address tokenA,\n address tokenB,\n uint amountADesired,\n uint amountBDesired,\n uint amountAMin,\n uint amountBMin,\n address to,\n uint deadline\n) external virtual override ensure(deadline) returns (uint amountA, uint amountB, uint liquidity) {\n (amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);\n address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);\n TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA);\n TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB);\n liquidity = IUniswapV2Pair(pair).mint(to);\n}\n```\n