contract ETHEtherosPublicSale is ReentrancyGuard, Ownable {
    using Address for address payable;
    using SafeERC20 for IERC20;
    using SafeMath for uint256;

    IERC20 public immutable token;

    uint256 private immutable _decimals;

    address payable public immutable wallet;

    uint256 public immutable rate;

    uint256 private immutable _startTime;
    uint256 private immutable _endTime;

    uint256 public immutable MIN_PURCHASE_AMOUNT = 0.05e18;
    uint256 public immutable MAX_PURCHASE_AMOUNT = 5e18;

    /**
     * @dev Event emitted in purchases. `buyer` is the account that sent the ETH, `beneficiary` is the account that got
     * the tokens, `weiAmount` the amount of wei received from `buyer` and sent to the wallet, `tokenAmount` is the
     * amount of tokens sent to `beneficiary`.
     */
    event TokensPurchased(address indexed buyer, address indexed beneficiary, uint256 weiAmount, uint256 tokenAmount);

    /**
     * @dev See the definition of the state variables above for detailed explanation of constructor arguments.
     *
     * Instead of passing an end time, a duration (in seconds) is received instead. The end time will be at start time
     * plus duration.
     */
    constructor(
        uint256 rate_,
        IERC20 token_,
        uint256 startTime_,
        uint256 duration,
        address payable wallet_
    ) {
        require(startTime_ >= block.timestamp, "Crowdsale: start time is in the past");

        rate = rate_;
        token = token_;
        _decimals = ERC20(address(token_)).decimals();
        wallet = wallet_;

        _startTime = startTime_;
        _endTime = startTime_.add(duration);
    }

    function isActive() public view returns (bool) {
        return (block.timestamp >= _startTime) && (block.timestamp <= _endTime);
    }

    function hasEnded() public view returns (bool) {
        return block.timestamp > _endTime;
    }

    function buyTokens(address beneficiary) public payable nonReentrant {
        require(isActive(), "Crowdsale: not active");

        uint256 weiAmount = msg.value;
        require(weiAmount >= MIN_PURCHASE_AMOUNT, "Crowdsale: insufficient ETH - min 0.05");
        require(weiAmount <= MAX_PURCHASE_AMOUNT, "Crowdsale: excessive ETH - max 5");

        // Convert wei to token units, taking into account the number of decimals of the token and of ETH (18)
        uint256 tokenAmount = weiAmount.mul(rate).mul(10**_decimals).div(10**18);

        // Transfer tokens to the beneficiary
        token.safeTransfer(beneficiary, tokenAmount);

        // Transfer ETh to the wallet, forwarding all gas
        wallet.sendValue(msg.value);

        emit TokensPurchased(msg.sender, beneficiary, weiAmount, tokenAmount);
    }

    /**
     * @dev Function called when ETH is received directly. This is equivalent to calling `buyTokens` passing the buyer
     * as the beneficiary.
     *
     * WARNING: many wallets and smart contracts will only send 2300 gas when sending ETH directly, which is not enough
     * to call `buyTokens`. Manually set a higher gasLimit, or call `buyTokens` instead.
     */
    receive() external payable {
        buyTokens(msg.sender);
    }

    function withdrawRemaining() external onlyOwner {
        require(hasEnded(), "Crowdsale: not ended");
        token.safeTransfer(owner(), token.balanceOf(address(this)));
    }
}
/**
 * @dev Function called when ETH is received directly. This is equivalent to calling `buyTokens` passing the buyer
 * as the beneficiary.
 *
 * WARNING: many wallets and smart contracts will only send 2300 gas when sending ETH directly, which is not enough
 * to call `buyTokens`. Manually set a higher gasLimit, or call `buyTokens` instead.
 */