// Contract: SuperBean
// Target function: function stake(uint chance) external payable
// SPDX-License-Identifier: MIT
pragma solidity >=0.7.3;
pragma experimental ABIEncoderV2;

library SafeMath {
    function add(uint x, uint y) internal pure returns (uint z) {
        require((z = x + y) >= x, "SafeMath: add overflow");
    }

    function sub(uint x, uint y) internal pure returns (uint z) {
        require((z = x - y) <= x, "SafeMath: sub underflow");
    }

    function mul(uint x, uint y) internal pure returns (uint z) {
        require(y == 0 || (z = x * y) / y == x, "SafeMath: mul overflow");
    }

    function div(uint a, uint b) internal pure returns (uint) {
        require(b > 0, "SafeMath: division by zero");
        uint c = a / b;
        return c;
    }
}

contract SuperBean {
    using SafeMath for uint;

    string public constant name = "SuperBean";
    string public constant symbol = "SBT";
    uint8 public constant decimals = 18;
    uint public totalSupply;
    mapping(address => uint) public balanceOf;
    mapping(address => mapping(address => uint)) public allowance;

    address public rainmaker;
    uint public FEEDING_END_BLOCK = 11688888;
    uint public MIN_STAKE_VALUE = 50000000000000000;
    uint public MAX_STAKE_VALUE = 10000000000000000000;
    uint public MIN_TIER_1 = 10000000000000000000;
    uint public MIN_TIER_2 = 50000000000000000000;
    uint public MIN_TIER_3 = 100000000000000000000;

    uint constant MATURITY = 300;
    uint constant MIN_CHANCE = 1;
    uint constant MAX_CHANCE = 95;
    uint8 constant LEFT_MASK = 0xf0;
    uint8 constant RIGHT_MASK = 0xf;

    struct Stake {
      uint blockNumber;
      uint8 rnd;
      uint8 chance;
      uint value;
      uint reward;
    }

    mapping (address => Stake[]) StakeMap;

    constructor() {
      rainmaker = msg.sender;
    }

    // events
    event Approval(
        address indexed owner,
        address indexed spender,
        uint value
    );
    event Transfer(address indexed from, address indexed to, uint value);

    event StakeEvent(address sender, uint8 chance, uint value, uint amount);
    event HarvestEvent(uint rnd, uint chance, uint value, uint reward);
    event UnstakeEvent(address sender, uint beans, uint amount);
    event SwapEvent(address sender, uint value, uint amount);
    event FeedEvent(address sender, uint value, uint amount);

    // modifiers
    modifier onlyRainmaker {
        require( msg.sender == rainmaker, "SuperBeans: onlyRainmaker methods called by non-rainmaker." );
        _;
    }

    function _mint(address to, uint value) internal {
        totalSupply = totalSupply.add(value);
        balanceOf[to] = balanceOf[to].add(value);
        emit Transfer(address(0), to, value);
    }

    function _burn(address from, uint value) internal {
        balanceOf[from] = balanceOf[from].sub(value);
        totalSupply = totalSupply.sub(value);
        emit Transfer(from, address(0), value);
    }

    function _approve( address owner, address spender, uint value ) private {
        allowance[owner][spender] = value;
        emit Approval(owner, spender, value);
    }

    function _transfer( address from, address to, uint value ) private {
        balanceOf[from] = balanceOf[from].sub(value);
        balanceOf[to] = balanceOf[to].add(value);
        emit Transfer(from, to, value);
    }

    function approve(address spender, uint value) external returns (bool) {
        _approve(msg.sender, spender, value);
        return true;
    }

    function transfer(address to, uint value) external returns (bool) {
        _transfer(msg.sender, to, value);
        return true;
    }

    function transferFrom( address from, address to, uint value ) external returns (bool) {
        if (allowance[from][msg.sender] != uint(-1)) {
            allowance[from][msg.sender] = allowance[from][msg.sender].sub( value );
        }
        _transfer(from, to, value);
        return true;
    }

    // configuration
    function setRainmaker(address newRainmaker) external onlyRainmaker {
        rainmaker = newRainmaker;
    }
    function setStake(uint typ, uint value) external onlyRainmaker {
        if (typ == 0) {
            MIN_STAKE_VALUE = value;
        } else if (typ == 1) {
            MAX_STAKE_VALUE = value;
        }
    }
    function setTier(uint tier, uint value) external onlyRainmaker {
        if (tier == 1) {
            MIN_TIER_1 = value;
        } else if (tier == 2) {
            MIN_TIER_2 = value;
        } else if (tier == 3) {
            MIN_TIER_3 = value;
        }
    }
    function setFeedingEndBlock(uint value) external onlyRainmaker {
        require( block.number + MATURITY < value, 'SuperBean: invalid feeding end block');
        FEEDING_END_BLOCK = value;
    }