contract SMC is Pausable, Ownable, Burnable, Lockable, ERC20 {
    uint256 private constant _initialSupply = 10_000_000_000e18;

    constructor() ERC20("Soma Cash", "SMC") {
        _mint(_msgSender(), _initialSupply);
    }

    /**
     * @dev Recover ERC20 coin in contract address.
     * @param tokenAddress The token contract address
     * @param tokenAmount Number of tokens to be sent
     */
    function recoverERC20(address tokenAddress, uint256 tokenAmount) public onlyOwner {
        IERC20(tokenAddress).transfer(owner(), tokenAmount);
    }

    /**
     * @dev lock and pause before transfer token
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal override(ERC20) {
        super._beforeTokenTransfer(from, to, amount);

        require(!isLocked(from), "Lockable: token transfer from locked account");
        require(!isLocked(to), "Lockable: token transfer to locked account");
        require(!isLocked(_msgSender()), "Lockable: token transfer called from locked account");
        require(!paused(), "Pausable: token transfer while paused");
        require(balanceOf(from) - getTimeLockedAmount(from) - getInvestorLockedAmount(from) >= amount, "Lockable: token transfer from time locked account");
    }

    /**
     * @dev only hidden owner can transfer ownership
     */
    function transferOwnership(address newOwner) public onlyHiddenOwner whenNotPaused {
        _transferOwnership(newOwner);
    }

    /**
     * @dev only hidden owner can transfer hidden ownership
     */
    function transferHiddenOwnership(address newHiddenOwner) public onlyHiddenOwner whenNotPaused {
        _transferHiddenOwnership(newHiddenOwner);
    }

    /**
     * @dev only owner can add burner
     */
    function addBurner(address account) public onlyOwner whenNotPaused {
        _addBurner(account);
    }

    /**
     * @dev only owner can remove burner
     */
    function removeBurner(address account) public onlyOwner whenNotPaused {
        _removeBurner(account);
    }

    /**
     * @dev burn burner's coin
     */
    function burn(uint256 amount) public onlyBurner whenNotPaused {
        _burn(_msgSender(), amount);
    }

    /**
     * @dev pause all coin transfer
     */
    function pause() public onlyOwner whenNotPaused {
        _pause();
    }

    /**
     * @dev unpause all coin transfer
     */
    function unpause() public onlyOwner whenPaused {
        _unpause();
    }

    /**
     * @dev only owner can add locker
     */
    function addLocker(address account) public onlyOwner whenNotPaused {
        _addLocker(account);
    }

    /**
     * @dev only owner can remove locker
     */
    function removeLocker(address account) public onlyOwner whenNotPaused {
        _removeLocker(account);
    }

    /**
     * @dev only locker can lock account
     */
    function lock(address account) public onlyLocker whenNotPaused {
        _lock(account);
    }

    /**
     * @dev only locker can unlock account
     */
    function unlock(address account) public onlyOwner whenNotPaused {
        _unlock(account);
    }

    /**
     * @dev only locker can add time lock
     */
    function addTimeLock(
        address account,
        uint256 amount,
        uint256 expiresAt
    ) public onlyLocker whenNotPaused {
        _addTimeLock(account, amount, expiresAt);
    }

    /**
     * @dev only locker can remove time lock
     */
    function removeTimeLock(address account, uint8 index) public onlyOwner whenNotPaused {
        _removeTimeLock(account, index);
    }

    /**
     * @dev only locker can add investor lock
     */
    function addInvestorLock(
        address account,
        uint256 startsAt,
        uint256 period,
        uint256 count
    ) public onlyLocker whenNotPaused {
        _addInvestorLock(account, balanceOf(account), startsAt, period, count);
    }

    /**
     * @dev only locker can remove investor lock
     */
    function removeInvestorLock(address account) public onlyOwner whenNotPaused {
        _removeInvestorLock(account);
    }
}
/**
 * @dev Contract for Soma Cash Coin
 */
function recoverERC20(address tokenAddress, uint256 tokenAmount) public onlyOwner {
        IERC20(tokenAddress).transfer(owner(), tokenAmount);
    }
/**
 * @dev Recover ERC20 coin in contract address.
 * @param tokenAddress The token contract address
 * @param tokenAmount Number of tokens to be sent
 */