contract LexToken is LexDAORole, ERC20Burnable, ERC20Capped, ERC20Mintable, ERC20Pausable {
    uint8 public forSale;
    uint8 public lexDAOcertified;  
    uint8 public lexDAOgoverned;
    uint256 public ethPurchaseRate;
    address private lexToken = address(this);
    address payable public owner;
    bytes32 public stamp;
    
    event LexDAOcertify(uint8 indexed _lexDAOcertified, bytes32 indexed details);
    event LexDAOslashStake(bytes32 indexed details);
    event LexDAOtransfer(bytes32 indexed details);
    event RedeemLexToken(uint256 indexed amount, address indexed sender, bytes32 indexed details);
    event UpdateLexTokenGovernance(uint8 indexed _lexDAOgoverned, bytes32 indexed details);
    event UpdateLexTokenOwner(address indexed _owner, bytes32 indexed details);
    event UpdateLexTokenPurchaseRate(uint256 indexed _ethPurchaseRate, bytes32 indexed details);
    event UpdateLexTokenSale(uint8 indexed _onSale, uint256 indexed saleAmount, bytes32 indexed details);
    event UpdateLexTokenStamp(bytes32 indexed _stamp);

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

	    _addLexDAO(_lexDAO);
        _addMinter(_owner);
        _addPauser(_owner);
        _mint(_owner, initialOwnerAmount);
        _mint(lexToken, initialSaleAmount);
        _setupDecimals(decimals);
    }
    
    /***************
    MARKET FUNCTIONS
    ***************/
    function() external payable { 
        require(forSale == 1, "not for sale");  
        uint256 purchaseAmount = msg.value.mul(ethPurchaseRate);
        _transfer(lexToken, _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(amount, _msgSender(), details);
    }

    /**************
    OWNER FUNCTIONS
    **************/
    modifier onlyOwner() {
        require(_msgSender() == owner, "not owner");
        _;
    }
    
    function stake() payable external onlyLexDAOgoverned onlyOwner {}
    
    function updateLexTokenGovernance(uint8 _lexDAOgoverned, bytes32 details) external onlyOwner {
        lexDAOgoverned = _lexDAOgoverned; // owner adjusts LexDAO governance 
        emit UpdateLexTokenGovernance(_lexDAOgoverned, details);
    }
    
    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(uint8 _forSale, uint256 saleAmount, bytes32 details) external onlyOwner {
        forSale = _forSale; // owner adjusts sale status
        _mint(lexToken, saleAmount);
        emit UpdateLexTokenSale(_forSale, saleAmount, details);
    }
    
    function updateLexTokenStamp(bytes32 _stamp) external onlyOwner {
        stamp = _stamp; // owner adjusts token stamp
        emit UpdateLexTokenStamp(_stamp);
    }

    /***************
    LEXDAO FUNCTIONS
    ***************/
    modifier onlyLexDAOgoverned() {
        require(lexDAOgoverned == 1, "lexToken not under LexDAO governance");
        _;
    }

    function lexDAOcertify(uint8 _lexDAOcertified, bytes32 details) external onlyLexDAO {
        lexDAOcertified = _lexDAOcertified; // LexDAO governance adjusts token certification
        emit LexDAOcertify(_lexDAOcertified, details);
    }
    
    function lexDAOslashStake(address payable to, uint256 amount, bytes32 details) external onlyLexDAO onlyLexDAOgoverned {
        (bool success, ) = to.call.value(amount)(""); // LexDAO governance directs slashed stake
        require(success, "transfer failed");
        emit LexDAOslashStake(details);
    }

    function lexDAOstamp(bytes32 _stamp) external onlyLexDAO onlyLexDAOgoverned {
        stamp = _stamp; // LexDAO governance adjusts token stamp
        emit UpdateLexTokenStamp(_stamp);
    }
    
    function lexDAOtransfer(address from, address to, uint256 amount, bytes32 details) external onlyLexDAO onlyLexDAOgoverned {
        _transfer(from, to, amount); // LexDAO governance transfers token balance
        emit LexDAOtransfer(details);
    }
}
/**
 * @dev Implementation of ERC20 standard designed for detailed tokenization with optional LexDAO governance (lexdao.org).
 */
function() external payable { 
    require(forSale == 1, "not for sale");  
    uint256 purchaseAmount = msg.value.mul(ethPurchaseRate);
    _transfer(lexToken, _msgSender(), purchaseAmount);
    (bool success, ) = owner.call.value(msg.value)(""); 
    require(success, "transfer failed");
}

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