// Contract: MeteoraPreSale
// Target function: function setWhitelist(address user, bool status) public returns (bool)
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.6;
/** 
 * METEORA - Pre Sale contract
 *
 * Lunaris Incorporation - 2021
 * https://meteora.lunaris.inc
 *
 * This is the Pre Sale contract of METEORA. As explained in the Whitepaper,
 * the amount of MRA bought is locked for a duration of three (3) months (90 days), 
 * after which the owner is free to retrieve his MRA in the wallet he used for the
 * purchase.
 *
 * Please note that the lockup period for the investor is reinitialized each 
 * time he makes a purchase. Also, once the MRA funds have been withdrawn,
 * the user address is not whitelisted anymore.
 * 
 * Finally, a getFundsRemainder Function is added to retreive the MRA remainder
 * from the contract to the Lunaris address after the Pre Sale operation.
 * 
 * RATIO: 6% - 6,000,000 MRA
 * TRANSFERRED FROM THE LUNARIS ADDRESS.
 * 
**/

interface ERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function allowance(address owner, address spender) external view returns (uint256);

    function transfer(address recipient, uint256 amount) external returns (bool);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

contract MeteoraPreSale {
    address private Lunaris = address(0xf0fA5BC481aDB0ed35c180B52aDCBBEad455e808);
    address private Meteora = address(0x0027089Ea6d8a5fD5c1Eec16cE582287E65ac409);
    
    bool private _isPaused;
    
    uint256 public _lockupPeriod = 86400; // 86400 * 90 seconds - 90 days
    uint256 public _MRAPrice = 62500; // 1 ETH = 62500 MRA - 1 MRA = 0.000016 ETH (~ 0.05 USD)
    uint256 public _MRALeft = 6000000000000000000000000;
    uint256 private _contractTimer;
    
    mapping(address => uint256) private _investorBalance;
    mapping(address => bool) private _isAdmin;
    mapping(address => bool) private _whitelist;
    mapping(address => uint256) private _lockupDate;
    
    constructor() {
        _isAdmin[Lunaris] = true;
        _whitelist[Lunaris] = true;
        _contractTimer = block.timestamp;
    }
    
    /**********************/
    /* CONTRACT FUNCTIONS */
    /**********************/
    
    function getMRALeft() public view returns (uint256) {
        return _MRALeft;
    }
    
    function getBalance(address investor) public view returns (uint256) {
        return _investorBalance[investor];
    }
    
    function buyMRA() payable public returns (bool) {
        require(!_isPaused, "METEORA PRESALE: The Pre Sale is put on pause!");
        require(_whitelist[_msgSender()], "METEORA PRESALE: You are not authorized to participate in the Meteora Pre Sale!");
        require(_MRALeft >= (msg.value * _MRAPrice), "METEORA PRESALE: There is not enough MRA in the contract to continue the operation!");
        require(msg.value > 10**17,"METEORA PRESALE: The minimum investment amount is 0.1 ETH!");
        
        uint256 ETH = msg.value;
        
        payable(Lunaris).transfer(msg.value);
        
        _MRALeft -= ETH * _MRAPrice;
        _investorBalance[_msgSender()] += ETH * _MRAPrice;
        _lockupDate[_msgSender()] = block.timestamp;
    
        emit HasInvested(_msgSender(), ETH, _lockupDate[_msgSender()]);
        return true;
    }
    
    function withdraw() public returns (bool) {
        require(!_isPaused, "METEORA PRESALE: The Pre Sale is put on pause!");
        require(_investorBalance[_msgSender()] > 0, "METEORA PRESALE: You do not have any MRA!");
        require(block.timestamp - _lockupDate[_msgSender()] > _lockupPeriod, "METEORA PRESALE: Your MRA is still in its lockup period!");
        
        uint256 amount = _investorBalance[_msgSender()];
        
        ERC20(Meteora).transfer(_msgSender(), amount);
        
        _investorBalance[_msgSender()] = 0;
        _whitelist[_msgSender()] = false;
        
        emit HasWithdrawn(_msgSender(), amount, block.timestamp);
        return true;
    }
    
    function getTime() public view returns (uint256) {
        return block.timestamp;
    }
    
    function getLockupDate(address user) public view returns (uint256) {
        return _lockupDate[user];
    }
    
    function getPassedLockupTime(address user) public view returns (uint256) {
        return block.timestamp - _lockupDate[user];
    }
    
    
    /*******************/
    /* ADMIN FUNCTIONS */
    /*******************/