/**
 ▄         ▄  ▄▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▄▄▄▄▄  ▄         ▄  ▄▄▄▄▄▄▄▄▄▄▄  ▄▄       ▄▄  ▄▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▄▄▄▄▄  ▄         ▄ 
▐░▌       ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌       ▐░▌▐░░░░░░░░░░░▌▐░░▌     ▐░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌       ▐░▌
▐░▌       ▐░▌▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░▌       ▐░▌ ▀▀▀▀█░█▀▀▀▀ ▐░▌░▌   ▐░▐░▌ ▀▀▀▀█░█▀▀▀▀  ▀▀▀▀█░█▀▀▀▀ ▐░▌       ▐░▌
▐░▌       ▐░▌▐░▌       ▐░▌▐░▌          ▐░▌       ▐░▌     ▐░▌     ▐░▌▐░▌ ▐░▌▐░▌     ▐░▌          ▐░▌     ▐░▌       ▐░▌
▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌     ▐░▌     ▐░▌ ▐░▐░▌ ▐░▌     ▐░▌          ▐░▌     ▐░▌       ▐░▌
▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌     ▐░▌     ▐░▌  ▐░▌  ▐░▌     ▐░▌          ▐░▌     ▐░▌       ▐░▌
 ▀▀▀▀█░█▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌ ▀▀▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌     ▐░▌     ▐░▌   ▀   ▐░▌     ▐░▌          ▐░▌     ▐░▌       ▐░▌
     ▐░▌     ▐░▌       ▐░▌          ▐░▌▐░▌       ▐░▌     ▐░▌     ▐░▌       ▐░▌     ▐░▌          ▐░▌     ▐░▌       ▐░▌
     ▐░▌     ▐░▌       ▐░▌ ▄▄▄▄▄▄▄▄▄█░▌▐░▌       ▐░▌ ▄▄▄▄█░█▄▄▄▄ ▐░▌       ▐░▌ ▄▄▄▄█░█▄▄▄▄      ▐░▌     ▐░█▄▄▄▄▄▄▄█░▌
     ▐░▌     ▐░▌       ▐░▌▐░░░░░░░░░░░▌▐░▌       ▐░▌▐░░░░░░░░░░░▌▐░▌       ▐░▌▐░░░░░░░░░░░▌     ▐░▌     ▐░░░░░░░░░░░▌
      ▀       ▀         ▀  ▀▀▀▀▀▀▀▀▀▀▀  ▀         ▀  ▀▀▀▀▀▀▀▀▀▀▀  ▀         ▀  ▀▀▀▀▀▀▀▀▀▀▀       ▀       ▀▀▀▀▀▀▀▀▀▀▀ 
                                                                                                                     
 ▄▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▄▄▄▄▄  ▄            ▄▄▄▄▄▄▄▄▄▄                                                                   
▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌          ▐░░░░░░░░░░▌                                                                  
▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌▐░▌          ▐░█▀▀▀▀▀▀▀█░▌                                                                 
▐░▌          ▐░▌       ▐░▌▐░▌          ▐░▌       ▐░▌                                                                 
▐░▌ ▄▄▄▄▄▄▄▄ ▐░▌       ▐░▌▐░▌          ▐░▌       ▐░▌                                                                 
▐░▌▐░░░░░░░░▌▐░▌       ▐░▌▐░▌          ▐░▌       ▐░▌                                                                 
▐░▌ ▀▀▀▀▀▀█░▌▐░▌       ▐░▌▐░▌          ▐░▌       ▐░▌                                                                 
▐░▌       ▐░▌▐░▌       ▐░▌▐░▌          ▐░▌       ▐░▌                                                                 
▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌                                                                 
▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░▌                                                                  
 ▀▀▀▀▀▀▀▀▀▀▀  ▀▀▀▀▀▀▀▀▀▀▀  ▀▀▀▀▀▀▀▀▀▀▀  ▀▀▀▀▀▀▀▀▀▀                                                                   
                                                                                                                     
*/

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

interface IERC20 {
    function totalSupply() external view returns (uint256);

    function decimals() external view returns (uint8);

    function symbol() external view returns (string memory);

    function name() external view returns (string memory);

    function balanceOf(address account) external view returns (uint256);

    function transfer(address recipient, uint256 amount)
        external
        returns (bool);

    function allowance(address _owner, address spender)
        external
        view
        returns (uint256);

    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
    );
}

interface IDexRouter {
    function factory() external pure returns (address);

    function WETH() external pure returns (address);

    function addLiquidityETH(
        address token,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    )
        external
        payable
        returns (
            uint256 amountToken,
            uint256 amountETH,
            uint256 liquidity
        );

    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable;

    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external;
}

abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
    );

    constructor() {
        _transferOwnership(_msgSender());
    }

    function owner() public view virtual returns (address) {
        return _owner;
    }

    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(
            newOwner != address(0),
            "Ownable: new owner is the zero address"
        );
        _transferOwnership(newOwner);
    }

    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

contract YashimituGold is Ownable {
    using SafeMath for uint256;

    address payable public dev;
    address public token;
    IDexRouter public router;

    uint256 public SPOILS_TO_HIRE_WARRIOR = 1728000;
    uint256 public REFERRAL = 30;
    uint256 public PERCENTS_DIVIDER = 1000;
    uint256 public BUYBACK_TAX = 10;
    uint256 public DEV_TAX_BUY = 40;
    uint256 public DEV_TAX_SELL = 90;
    uint256 public MARKET_SPOILS_DIVISOR = 2;

    uint256 public MIN_DEPOSIT_LIMIT = 0.005 ether;
    uint256 public MAX_WITHDRAW_LIMIT = 2 ether;
    uint256[5] public ROI_MAP = [
        20 ether,
        40 ether,
        60 ether,
        80 ether,
        100 ether
    ];

    uint256 public COMPOUND_BONUS = 5;
    uint256 public COMPOUND_MAX_TIMES = 10;
    uint256 public COMPOUND_DURATION = 12 * 60 * 60;
    uint256 public PROOF_OF_LIFE = 48 * 60 * 60;
    uint256 public WITHDRAWAL_TAX = 700;
    uint256 public COMPOUND_FOR_NO_TAX_WITHDRAWAL = 10;

    uint256 public totalStaked;
    uint256 public totalSuttles;
    uint256 public totalDeposits;
    uint256 public totalCompound;
    uint256 public totalRefBonus;
    uint256 public totalWithdrawn;
    uint256 public whitelisTime = 1672596000;
    uint256 public publicTime = 1672599600;

    uint256 public marketSpoils = 144000000000;
    uint256 PSN = 10000;
    uint256 PSNH = 5000;

    bool public whitelistStart;
    bool public publicStart;

    struct User {
        uint256 initialDeposit;
        uint256 userDeposit;
        uint256 warriors;
        uint256 claimedSpoils;
        uint256 lastHatch;
        address referrer;
        uint256 referralsCount;
        uint256 referralRewards;
        uint256 totalWithdrawn;
        uint256 dailyCompoundBonus;
        uint256 warriorsCompoundCount;
        uint256 lastWithdrawTime;
    }

    mapping(address => User) public users;

    constructor() {
        dev = payable(0x5d8BCfEAD5b1d02eeE6129477Df619eAf3939026);
        router = IDexRouter(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
        token = 0xFa548DC8b1ec4De65e36b155F352e33ef6257260;
    }

    function isContract(address addr) internal view returns (bool) {
        uint256 size;
        assembly {
            size := extcodesize(addr)
        }
        return size > 0;
    }

    function startPublicJourney() public onlyOwner {
        require(!publicStart, "Already started");
        publicStart = true;
    }

    function startWhitelistJourney() public onlyOwner {
        require(!whitelistStart, "Already started");
        whitelistStart = true;
    }

    function setTimesOfLaunch(uint256 _pub, uint256 _wl) public onlyOwner {
        publicTime = _pub;
        whitelisTime = _wl;
    }

    function buyMoreWarriors() public {
        if (whitelistStart) {
            require(
                IERC20(token).balanceOf(msg.sender) > 0,
                "Not whitelsited."
            );
        } else {
            require(publicStart, "Contract not yet Started.");
        }
        User storage user = users[msg.sender];
        require(
            block.timestamp.sub(user.lastHatch) >= COMPOUND_DURATION,
            "Wait for next compound"
        );
        compound(true);
    }

    function compound(bool isCompound) internal {
        User storage user = users[msg.sender];

        uint256 spoilsUsed = getMySpoils(msg.sender);
        uint256 spoilsForCompound = spoilsUsed;

        if (isCompound) {
            uint256 dailyCompoundBonus = getDailyCompoundBonus(
                msg.sender,
                spoilsForCompound
            );
            spoilsForCompound = spoilsForCompound.add(dailyCompoundBonus);
            uint256 spoilsUsedValue = calculateSpoilsSell(spoilsForCompound);
            user.userDeposit = user.userDeposit.add(spoilsUsedValue);
            totalCompound = totalCompound.add(spoilsUsedValue);
            if (user.dailyCompoundBonus <= COMPOUND_MAX_TIMES) {
                user.dailyCompoundBonus = user.dailyCompoundBonus.add(1);
            }
        }

        //add compoundCount for monitoring purposes.
        user.warriorsCompoundCount = user.warriorsCompoundCount.add(1);
        user.warriors = user.warriors.add(
            spoilsForCompound.div(SPOILS_TO_HIRE_WARRIOR)
        );
        totalSuttles = totalSuttles.add(
            spoilsForCompound.div(SPOILS_TO_HIRE_WARRIOR)
        );
        user.claimedSpoils = 0;
        user.lastHatch = block.timestamp;

        marketSpoils = marketSpoils.add(spoilsUsed.div(MARKET_SPOILS_DIVISOR));
    }

    function sellSpoils() public {
        if (whitelistStart) {
            require(
                IERC20(token).balanceOf(msg.sender) > 0,
                "Not whitelsited."
            );
        } else {
            require(publicStart, "Contract not yet Started.");
        }

        User storage user = users[msg.sender];
        uint256 hasSpoils = getMySpoils(msg.sender);
        uint256 spoilsValue = calculateSpoilsSell(hasSpoils);

        /** 
            if user compound < to mandatory compound days**/
        if (user.dailyCompoundBonus < COMPOUND_FOR_NO_TAX_WITHDRAWAL) {
            //daily compound bonus count will not reset and spoilsValue will be deducted with x% feedback tax.
            spoilsValue = spoilsValue.sub(
                spoilsValue.mul(WITHDRAWAL_TAX).div(PERCENTS_DIVIDER)
            );
        } else {
            //set daily compound bonus count to 0 and spoilsValue will remain without deductions
            user.dailyCompoundBonus = 0;
            user.warriorsCompoundCount = 0;
        }

        user.lastWithdrawTime = block.timestamp;
        user.claimedSpoils = 0;
        user.lastHatch = block.timestamp;
        marketSpoils = marketSpoils.add(hasSpoils.div(MARKET_SPOILS_DIVISOR));

        // Antiwhale limit
        if (spoilsValue > MAX_WITHDRAW_LIMIT) {
            buy(msg.sender, address(0), spoilsValue.sub(MAX_WITHDRAW_LIMIT));
            spoilsValue = MAX_WITHDRAW_LIMIT;
        }
        if (spoilsValue > getBalance()) {
            buy(msg.sender, address(0), spoilsValue.sub(getBalance()));
            spoilsValue = getBalance();
        }

        uint256 spoilsPayout = spoilsValue.sub(takeFees(spoilsValue, false));
        payable(msg.sender).transfer(spoilsPayout);
        user.totalWithdrawn = user.totalWithdrawn.add(spoilsPayout);
        totalWithdrawn = totalWithdrawn.add(spoilsPayout);
    }

    /** Deposit **/
    function buyWarriors(address ref) public payable {
        if (whitelistStart) {
            require(
                IERC20(token).balanceOf(msg.sender) > 0,
                "Not whitelsited."
            );
        } else {
            require(publicStart, "Contract not yet Started.");
        }
        require(msg.value >= MIN_DEPOSIT_LIMIT, "Less than min limit");
        buy(msg.sender, ref, msg.value);
    }

    function buy(
        address _user,
        address ref,
        uint256 amount
    ) internal {
        User storage user = users[_user];
        uint256 spoilsBought = calculateSpoilsBuy(
            amount,
            getBalance().sub(amount)
        );
        user.userDeposit = user.userDeposit.add(amount);
        user.initialDeposit = user.initialDeposit.add(amount);
        user.claimedSpoils = user.claimedSpoils.add(spoilsBought);

        if (user.referrer == address(0)) {
            if (ref != _user) {
                user.referrer = ref;
            }

            address upline1 = user.referrer;
            if (upline1 != address(0)) {
                users[upline1].referralsCount = users[upline1]
                    .referralsCount
                    .add(1);
            }
        }

        if (user.referrer != address(0)) {
            address upline = user.referrer;
            if (upline != address(0)) {
                uint256 refRewards = amount.mul(REFERRAL).div(PERCENTS_DIVIDER);
                payable(upline).transfer(refRewards);
                users[upline].referralRewards = users[upline]
                    .referralRewards
                    .add(refRewards);
                totalRefBonus = totalRefBonus.add(refRewards);
            }
        }

        uint256 spoilsPayout = takeFees(amount, true);
        totalStaked = totalStaked.add(amount.sub(spoilsPayout));
        totalDeposits = totalDeposits.add(1);
        compound(false);

        if (getBalance() < ROI_MAP[0]) {
            SPOILS_TO_HIRE_WARRIOR = 1728000;
        } else if (getBalance() >= ROI_MAP[0] && getBalance() < ROI_MAP[1]) {
            SPOILS_TO_HIRE_WARRIOR = 1584000;
        } else if (getBalance() >= ROI_MAP[1] && getBalance() < ROI_MAP[2]) {
            SPOILS_TO_HIRE_WARRIOR = 1440000;
        } else if (getBalance() >= ROI_MAP[2] && getBalance() < ROI_MAP[3]) {
            SPOILS_TO_HIRE_WARRIOR = 1320000;
        } else if (getBalance() >= ROI_MAP[3] && getBalance() < ROI_MAP[4]) {
            SPOILS_TO_HIRE_WARRIOR = 1200000;
        } else if (getBalance() >= ROI_MAP[4]) {
            SPOILS_TO_HIRE_WARRIOR = 1140000;
        }
    }

    function takeFees(uint256 spoilsValue, bool isBuy)
        internal
        returns (uint256)
    {
        uint256 devTax;
        if (isBuy) {
            devTax = spoilsValue.mul(DEV_TAX_BUY).div(PERCENTS_DIVIDER);
        } else {
            devTax = spoilsValue.mul(DEV_TAX_SELL).div(PERCENTS_DIVIDER);
        }
        payable(dev).transfer(devTax);

        uint256 buybackTax = spoilsValue.mul(BUYBACK_TAX).div(PERCENTS_DIVIDER);
        if (buybackTax > 0) {
            address[] memory path = new address[](2);
            path[0] = router.WETH();
            path[1] = token;

            router.swapExactETHForTokensSupportingFeeOnTransferTokens{
                value: buybackTax
            }(0, path, dev, block.timestamp);
        }

        return devTax.add(buybackTax);
    }

    function getDailyCompoundBonus(address _adr, uint256 amount)
        public
        view
        returns (uint256)
    {
        if (users[_adr].dailyCompoundBonus == 0) {
            return 0;
        } else {
            uint256 totalBonus = users[_adr].dailyCompoundBonus.mul(
                COMPOUND_BONUS
            );
            uint256 result = amount.mul(totalBonus).div(PERCENTS_DIVIDER);
            return result;
        }
    }

    function getUserInfo(address _adr)
        public
        view
        returns (
            uint256 _initialDeposit,
            uint256 _userDeposit,
            uint256 _warriors,
            uint256 _claimedSpoils,
            uint256 _lastHatch,
            address _referrer,
            uint256 _referrals,
            uint256 _totalWithdrawn,
            uint256 _referralRewards,
            uint256 _dailyCompoundBonus,
            uint256 _warriorsCompoundCount,
            uint256 _lastWithdrawTime
        )
    {
        _initialDeposit = users[_adr].initialDeposit;
        _userDeposit = users[_adr].userDeposit;
        _warriors = users[_adr].warriors;
        _claimedSpoils = users[_adr].claimedSpoils;
        _lastHatch = users[_adr].lastHatch;
        _referrer = users[_adr].referrer;
        _referrals = users[_adr].referralsCount;
        _totalWithdrawn = users[_adr].totalWithdrawn;
        _referralRewards = users[_adr].referralRewards;
        _dailyCompoundBonus = users[_adr].dailyCompoundBonus;
        _warriorsCompoundCount = users[_adr].warriorsCompoundCount;
        _lastWithdrawTime = users[_adr].lastWithdrawTime;
    }

    function getBalance() public view returns (uint256) {
        return (address(this)).balance;
    }

    function getAvailableEarnings(address _adr) public view returns (uint256) {
        uint256 userSpoils = users[_adr].claimedSpoils.add(
            getSpoilsSinceLastHatch(_adr)
        );
        return calculateSpoilsSell(userSpoils);
    }

    function calculateTrade(
        uint256 rt,
        uint256 rs,
        uint256 bs
    ) public view returns (uint256) {
        return
            SafeMath.div(
                SafeMath.mul(PSN, bs),
                SafeMath.add(
                    PSNH,
                    SafeMath.div(
                        SafeMath.add(
                            SafeMath.mul(PSN, rs),
                            SafeMath.mul(PSNH, rt)
                        ),
                        rt
                    )
                )
            );
    }

    function calculateSpoilsSell(uint256 spoils) public view returns (uint256) {
        return calculateTrade(spoils, marketSpoils, getBalance());
    }

    function calculateSpoilsBuy(uint256 amount, uint256 contractBalance)
        public
        view
        returns (uint256)
    {
        return calculateTrade(amount, contractBalance, marketSpoils);
    }

    function calculateSpoilsBuySimple(uint256 amount)
        public
        view
        returns (uint256)
    {
        return calculateSpoilsBuy(amount, getBalance());
    }

    /** How many warriors and Spoils per day user will recieve based on deposit amount **/
    function getSpoilsYield(uint256 amount)
        public
        view
        returns (uint256, uint256)
    {
        uint256 spoilsAmount = calculateSpoilsBuy(
            amount,
            getBalance().add(amount).sub(amount)
        );
        uint256 warriors = spoilsAmount.div(SPOILS_TO_HIRE_WARRIOR);
        uint256 day = 1 days;
        uint256 spoilsPerDay = day.mul(warriors);
        uint256 earningsPerDay = calculateSpoilsSellForYield(
            spoilsPerDay,
            amount
        );
        return (warriors, earningsPerDay);
    }

    function calculateSpoilsSellForYield(uint256 spoils, uint256 amount)
        public
        view
        returns (uint256)
    {
        return calculateTrade(spoils, marketSpoils, getBalance().add(amount));
    }

    function getSiteInfo()
        public
        view
        returns (
            uint256 _totalStaked,
            uint256 _totalSuttles,
            uint256 _totalDeposits,
            uint256 _totalCompound,
            uint256 _totalRefBonus
        )
    {
        return (
            totalStaked,
            totalSuttles,
            totalDeposits,
            totalCompound,
            totalRefBonus
        );
    }

    function getMywarriors(address userAddress) public view returns (uint256) {
        return users[userAddress].warriors;
    }

    function getMySpoils(address userAddress) public view returns (uint256) {
        return
            users[userAddress].claimedSpoils.add(
                getSpoilsSinceLastHatch(userAddress)
            );
    }

    function getSpoilsSinceLastHatch(address adr)
        public
        view
        returns (uint256)
    {
        uint256 secondsSinceLastHatch = block.timestamp.sub(
            users[adr].lastHatch
        );
        uint256 cutoffTime = min(secondsSinceLastHatch, PROOF_OF_LIFE);
        uint256 secondsPassed = min(SPOILS_TO_HIRE_WARRIOR, cutoffTime);
        return secondsPassed.mul(users[adr].warriors);
    }

    function min(uint256 a, uint256 b) private pure returns (uint256) {
        return a < b ? a : b;
    }

    function SET_WALLETS(address payable _dev) external onlyOwner {
        require(!isContract(_dev));
        dev = _dev;
    }

    function SET_TAX(
        uint256 _buyback,
        uint256 _devBuy,
        uint256 _devSell
    ) external onlyOwner {
        BUYBACK_TAX = _buyback;
        DEV_TAX_BUY = _devBuy;
        DEV_TAX_SELL = _devSell;
        require(_buyback + _devBuy < 100, "Less than 10%");
        require(_buyback + _devSell < 150, "Less than 15%");
    }

    function SET_TOKEN(address _token) external onlyOwner {
        token = _token;
    }

    function SET_ROUTER(address _router) external onlyOwner {
        router = IDexRouter(_router);
    }

    function PRC_MARKET_SPOILS_DIVISOR(uint256 value) external onlyOwner {
        require(value > 0 && value <= 10);
        MARKET_SPOILS_DIVISOR = value;
    }

    function SET_EARLY_WITHDRAWAL_TAX(uint256 value) external onlyOwner {
        require(value <= 700);
        WITHDRAWAL_TAX = value;
    }

    function BONUS_DAILY_COMPOUND(uint256 value) external onlyOwner {
        require(value >= 1 && value <= 100);
        COMPOUND_BONUS = value;
    }

    function BONUS_DAILY_COMPOUND_MAX_TIMES(uint256 value) external onlyOwner {
        require(value > 5 && value <= 10);
        COMPOUND_MAX_TIMES = value;
    }

    function BONUS_COMPOUND_DURATION(uint256 value) external onlyOwner {
        require(value <= 24);
        COMPOUND_DURATION = value * 60 * 60;
    }

    function SET_PROOF_OF_LIFE(uint256 value) external onlyOwner {
        require(value >= 24);
        PROOF_OF_LIFE = value * 60 * 60;
    }

    function SET_MAX_WITHDRAW_LIMIT(uint256 value) external onlyOwner {
        require(value >= 1 ether);
        MAX_WITHDRAW_LIMIT = value;
    }

    function SET_MIN_DEPOSIT_LIMIT(uint256 value) external onlyOwner {
        MIN_DEPOSIT_LIMIT = value;
    }

    function SET_COMPOUND_FOR_NO_TAX_WITHDRAWAL(uint256 value)
        external
        onlyOwner
    {
        require(value <= 12);
        COMPOUND_FOR_NO_TAX_WITHDRAWAL = value;
    }

    function UPDATE_ROI_MAP1(uint256 value) external onlyOwner {
        ROI_MAP[0] = value;
    }

    function UPDATE_ROI_MAP2(uint256 value) external onlyOwner {
        ROI_MAP[1] = value;
    }

    function UPDATE_ROI_MAP3(uint256 value) external onlyOwner {
        ROI_MAP[2] = value;
    }

    function UPDATE_ROI_MAP4(uint256 value) external onlyOwner {
        ROI_MAP[3] = value;
    }

    function UPDATE_ROI_MAP5(uint256 value) external onlyOwner {
        ROI_MAP[4] = value;
    }
}

library SafeMath {
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }
        uint256 c = a * b;
        assert(c / a == b);
        return c;
    }

    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a / b;
        return c;
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        assert(b <= a);
        return a - b;
    }

    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        assert(c >= a);
        return c;
    }

    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0);
        return a % b;
    }
}