contract Polygon is Ownable, ERC20 {
    using SafeMath for uint256;

    // next around
    address public immutable factory;
    address public immutable WETH;
    address public pair;
    uint256 public threshold = 0;
    uint8 public epoch = 0;

    // returns sorted token addresses, used to handle return values from pairs sorted in this order
    function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
        require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES');
        (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
        require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS');
    }

    // calculates the CREATE2 address for a pair without making any external calls
    function pairFor(address _factory, address tokenA, address tokenB) internal pure returns (address _pair) {
        (address token0, address token1) = sortTokens(tokenA, tokenB);
        _pair = address(uint(keccak256(abi.encodePacked(
                hex'ff',
                _factory,
                keccak256(abi.encodePacked(token0, token1)),
                hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash
            ))));
    }

    function getReserves() public view returns(uint256 _reserve0, uint256 _reserve1) {
        (_reserve0, _reserve1,) = IUniswapV2Pair(pair).getReserves();
    }

    function setPair(address _pair) external onlyOwner {
        pair = _pair;
    }

    function setThreshold(uint _threshold) external onlyOwner {
        threshold = _threshold;
    }

    constructor(address _factory, address _WETH) public Ownable() ERC20('Polygon', 'GON') {
        factory = _factory;
        WETH = _WETH;
        pair = pairFor(_factory, _WETH, address(this));

        _mint(address(this), 1000000000 * 10**18);
    }

    function mint(address _user) external onlyOwner {
        // genesis mint
        if (epoch == 0) {
            _transfer(address(this), _user, 100000000 * 10**18);
            threshold = 200 * 10**18;
            epoch = 1;
            return;
        }

        // avoids stack too deep errors
        {
        address token0 = IUniswapV2Pair(pair).token0();
        (uint256 reserve0, uint256 reserve1) = getReserves();
        uint256 reserve = token0 == address(this) ? reserve1 : reserve0;
        require(reserve >= threshold, 'Polygon: UNREACHABLE_THRESHOLD');
        threshold = threshold.add(uint256(100 * 10**18).mul(epoch));
        epoch = epoch + 1;
        }

        // generic mint
        uint256 balance = balanceOf(address(this));
        if (balance >= 10000000 * 10**18) {
            _transfer(address(this), _user, 10000000 * 10**18);
            balance = balanceOf(address(this));
            _burn(address(this), balance.div(10));
        } else {
            _transfer(address(this), _user, balance);
        }


        return;
    }
}
function pairFor(address _factory, address tokenA, address tokenB) internal pure returns (address _pair) {
    (address token0, address token1) = sortTokens(tokenA, tokenB);
    _pair = address(uint(keccak256(abi.encodePacked(
            hex'ff',
            _factory,
            keccak256(abi.encodePacked(token0, token1)),
            hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash
        ))));
}

// calculates the CREATE2 address for a pair without making any external calls