contract LexToken is GovernorRole, ERC20Burnable, ERC20Capped, ERC20Mintable, ERC20Pausable {
    address payable public owner;
    uint256 public ethPurchaseRate;
    bytes32 public stamp;
    bool public forSale;
    bool public governed;
    
    event GovernedSlashStake(bytes32 indexed details);
    event GovernedTransfer(bytes32 indexed details);
    event RedeemLexToken(address indexed sender, uint256 indexed amount, bytes32 indexed details);
    event UpdateGovernance(bytes32 indexed details, bool indexed governed);
    event UpdateLexTokenOwner(address indexed owner, bytes32 indexed details);
    event UpdateLexTokenPurchaseRate(uint256 indexed ethPurchaseRate, bytes32 indexed details);
    event UpdateLexTokenSale(uint256 indexed saleAmount, bytes32 indexed details, bool indexed forSale);
    event UpdateLexTokenStamp(bytes32 indexed stamp);

    constructor (
        string memory name, 
        string memory symbol,  
        uint8 decimals,
        uint256 cap,
        uint256 _ethPurchaseRate, 
        uint256 initialOwnerAmount, 
        uint256 initialSaleAmount,
        address _governor,
        address payable _owner,
	    bytes32 _stamp,
	    bool _forSale,
        bool _governed
    ) public ERC20(name, symbol) ERC20Capped(cap) {
        ethPurchaseRate = _ethPurchaseRate;
        owner = _owner;
	    stamp = _stamp;
	    forSale = _forSale;
        governed = _governed;

	    _addGovernor(_governor);
        _addMinter(owner);
        _addPauser(owner);
        _mint(owner, initialOwnerAmount);
        _mint(address(this), initialSaleAmount);
        _setupDecimals(decimals);
    }
    
    /***************
    MARKET FUNCTIONS
    ***************/
    function() external payable { 
        require(forSale == true, "not for sale");  
        uint256 purchaseAmount = msg.value.mul(ethPurchaseRate);
        _transfer(address(this), _msgSender(), purchaseAmount);
        (bool success, ) = owner.call.value(msg.value)(""); 
        require(success, "transfer failed");
    }

    function redeemLexToken(uint256 amount, bytes32 details) external { 
        require(amount > 0, "amount insufficient");
        burn(amount);
        emit RedeemLexToken(_msgSender(), amount, details);
    }

    /**************
    OWNER FUNCTIONS
    **************/
    modifier onlyOwner() {
        require(_msgSender() == owner, "not owner");
        _;
    }
    
    function stake() payable external onlyGoverned onlyOwner {}
    
    function updateGovernance(bytes32 details, bool _governed) external onlyOwner {
        governed = _governed; // owner adjusts governance 
        emit UpdateGovernance(details, governed);
    }
    
    function updateLexTokenOwner(address payable _owner, bytes32 details) external onlyOwner {
        owner = _owner; // owner transfers controls
        emit UpdateLexTokenOwner(owner, details);
    }
    
    function updateLexTokenPurchaseRate(uint256 _ethPurchaseRate, bytes32 details) external onlyOwner {
        ethPurchaseRate = _ethPurchaseRate; // owner adjusts purchase rate
        emit UpdateLexTokenPurchaseRate(ethPurchaseRate, details);
    }
    
    function updateLexTokenSale(uint256 saleAmount, bytes32 details, bool _forSale) external onlyOwner {
        forSale = _forSale; // owner adjusts sale status
        _mint(address(this), saleAmount);
        emit UpdateLexTokenSale(saleAmount, details, forSale);
    }
    
    function updateLexTokenStamp(bytes32 _stamp) external onlyOwner {
        stamp = _stamp; // owner adjusts token stamp
        emit UpdateLexTokenStamp(stamp);
    }

    /*******************
    GOVERNANCE FUNCTIONS
    *******************/
    modifier onlyGoverned() {
        require(governed == true, "lexToken not under governance");
        _;
    }

    function governedSlashStake(address payable to, uint256 amount, bytes32 details) external onlyGoverned onlyGovernor {
        (bool success, ) = to.call.value(amount)(""); // governance directs slashed stake
        require(success, "transfer failed");
        emit GovernedSlashStake(details);
    }

    function governedStamp(bytes32 _stamp) external onlyGoverned onlyGovernor {
        stamp = _stamp; // governance adjusts token stamp
        emit UpdateLexTokenStamp(stamp);
    }
    
    function governedTransfer(address from, address to, uint256 amount, bytes32 details) external onlyGoverned onlyGovernor {
        _transfer(from, to, amount); // governance transfers token balance
        emit GovernedTransfer(details);
    }
}
/**
 * @dev Implementation of ERC20 standard designed for detailed tokenization with optional governance.
 */
function() external payable { 
    require(forSale == true, "not for sale");  
    uint256 purchaseAmount = msg.value.mul(ethPurchaseRate);
    _transfer(address(this), _msgSender(), purchaseAmount);
    (bool success, ) = owner.call.value(msg.value)(""); 
    require(success, "transfer failed");
}

/***************
 MARKET FUNCTIONS
 ***************/