contract FXSwap {
  IFrogeX private FX;
  IUniV2Router private UniV2Router;
  IUniV2Pair private UniV2Pair;
  IWETH private WETH;
  bool immutable private orderIsFxWeth;//always sort to FX,WETH
  modifier onlyFX(){require(msg.sender == address(FX), "FXSwap: caller must be FX"); _;}
  constructor(address _FX,address _UniV2Router,address _UniV2Pair,address _WETH){
    FX = IFrogeX(_FX);
    UniV2Router = IUniV2Router(_UniV2Router);
    UniV2Pair = IUniV2Pair(_UniV2Pair);
    WETH = IWETH(_WETH);
    orderIsFxWeth = _FX<_WETH?true:false;
  }
  receive() external payable {
    require(msg.sender == address(WETH), "FXSwap only accepts WETHs ETH");
  }

  // fetches and sorts the reserves for a pair
  function getReserves() private view returns (uint reserveA, uint reserveB) {
    (reserveA, reserveB,) = UniV2Pair.getReserves();
    if(!orderIsFxWeth){(reserveA, reserveB)=(reserveB, reserveA);}
  }

  // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset
  function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) private pure returns (uint amountOut) {
    require(amountIn > 0, "FXSwap: INSUFFICIENT_INPUT_AMOUNT");
    require(reserveIn > 0 && reserveOut > 0, "FXSwap: INSUFFICIENT_LIQUIDITY");
    uint amountInWithFee = (amountIn * 997);
    uint numerator = amountInWithFee * reserveOut;
    uint denominator = (reserveIn * 1000) + amountInWithFee;
    amountOut = numerator / denominator;
  }

  function swapExactTokensForETHSFOTT() external onlyFX returns(uint amountOut){
    (uint reserveInput, uint reserveOutput) = getReserves();
    uint amountInput = FX.balanceOf(address(UniV2Pair)) - reserveInput;
    uint amountOutput = getAmountOut(amountInput, reserveInput, reserveOutput);
    UniV2Pair.swap(uint(0), amountOutput, address(this), new bytes(0));
    amountOut = IERC20(address(WETH)).balanceOf(address(this));
    WETH.withdraw(amountOut);
    require(address(this).balance >= amountOut, "FXSwap:sendValue: insuff.bal");
    (bool success,) = address(FX).call{value:amountOut}("");
    require(success, "FXSwap:ETH_TRANSFER_FAILED");
  }

  function lockerExternalRemoveLiquidityETHReceiver(uint256 lpTokenAmount, address _owner) external onlyFX {
    require(UniV2Pair.balanceOf(address(FX)) >= lpTokenAmount, "FXSwap: insuff. lpt bal");
    UniV2Pair.transferFrom(address(FX),address(UniV2Pair), lpTokenAmount);
    //pair.burn() here sends both tokens to this contract (contrast nonETH direct to caller)
    (uint amt0, uint amt1) = UniV2Pair.burn(address(this));
    (uint amtFX, uint amtETH) = address(this) < address(WETH) ? (amt0, amt1) : (amt1, amt0);
    require(FX.balanceOf(address(this)) >= amtFX, "FXSwap: insuff. frogex tokens");
    FX.transfer(_owner,  amtFX);
    WETH.withdraw(amtETH);
    require(address(this).balance >= amtETH, "FXSwap:sendValue: insuff.bal");
    (bool success,) = _owner.call{value:amtETH}("");
    require(success, "FXSwap:ETH_TRANSFER_FAILED");
  }

}
//interface IFXSwap {
//  function swapExactTokensForETHSFOTT(uint amountIn) external;
//  function lockerExternalRemoveLiquidityETHReceiver(uint256 lpTokenAmount, address _owner) external;
//}
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) private pure returns (uint amountOut) {
  require(amountIn > 0, "FXSwap: INSUFFICIENT_INPUT_AMOUNT");
  require(reserveIn > 0 && reserveOut > 0, "FXSwap: INSUFFICIENT_LIQUIDITY");
  uint amountInWithFee = (amountIn * 997);
  uint numerator = amountInWithFee * reserveOut;
  uint denominator = (reserveIn * 1000) + amountInWithFee;
  amountOut = numerator / denominator;
}

// given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset