contract ArtCirculationGovernanceToken is
            ERC20VotesComp,
            ERC20Snapshot,
            ERC20Pausable,
            AccessControl,
            Ownable
{
    /// @notice using safe math for uints
    using SafeMath for uint;

    /// @notice contract version
    string private _version;

    /// @notice constant hashed roles for access control
    bytes32 public constant SNAPSHOT_ROLE = keccak256("SNAPSHOT_ROLE");
    bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");

    /**
     * @notice constructor
    **/
    constructor() ERC20("ArtCirculationGovernanceToken", "ACG") ERC20Permit("ArtCirculationGovernanceToken") Ownable() {
        __ArtCirculationGovernanceToken_init(_msgSender());
    }

    /**
     * @notice internal initialize function for contract setup
     * @param admin address of the contract admin
    **/
    function __ArtCirculationGovernanceToken_init(address admin) internal{
        _setupRole(DEFAULT_ADMIN_ROLE, admin);
        _setupRole(SNAPSHOT_ROLE, admin);
        _setupRole(PAUSER_ROLE, admin);
        _mint(admin, 1000000 * 10 ** decimals()); // 1 million tokens
        _version = "1";
    }

    /// @notice gets the contract version
    function version() public view returns (string memory) {
        return _version;
    }

    /**
     * @notice grants the pauser role to a specified address
     * @param pauser address
    **/
    function grantPauser(address pauser) public onlyRole(DEFAULT_ADMIN_ROLE) {
        grantRole(PAUSER_ROLE, pauser);
    }

    /**
     * @notice checks if address has the pauser role
     * @param pauser address
    **/
    function isPauser(address pauser) public view returns (bool){
        return hasRole(PAUSER_ROLE, pauser);
    }

    /**
     * @notice revokes the pauser role for the specified address
     * @param pauser address
    **/
    function revokePauser(address pauser) public onlyRole(DEFAULT_ADMIN_ROLE) {
        revokeRole(PAUSER_ROLE, pauser);
    }

    /// @notice pauses the token contract
    function pause() public onlyRole(PAUSER_ROLE) {
        _pause();
    }

    /// @notice unpauses the token contract
    function unpause() public onlyRole(PAUSER_ROLE) {
        _unpause();
    }

    /**
     * @notice grants the snapshot role to a specified address
     * @param _snapshot address
    **/
    function grantSnapshot(address _snapshot) public onlyRole(DEFAULT_ADMIN_ROLE) {
        grantRole(SNAPSHOT_ROLE, _snapshot);
    }

    /**
     * @notice checks if address has the snapshot role
     * @param _snapshot address
    **/
    function isSnapshoter(address _snapshot) public view returns (bool){
        return hasRole(SNAPSHOT_ROLE, _snapshot);
    }

    /**
    * @notice revokes the snapshot role for the specified address
    * @param _snapshot address
    **/
    function revokeSnapshot(address _snapshot) public onlyRole(DEFAULT_ADMIN_ROLE) {
        revokeRole(SNAPSHOT_ROLE, _snapshot);
    }

    /// @notice takes a snapshot of the token contract
    function snapshot() public onlyRole(SNAPSHOT_ROLE) {
        _snapshot();
    }

    /**
     * @dev neccesarry override
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount)
        internal
        whenNotPaused
        override(ERC20, ERC20Snapshot, ERC20Pausable)
    {
        /// @notice call to parent before transfer hook
        super._beforeTokenTransfer(from, to, amount);
    }

    /**
     * @dev neccesarry override
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual override(ERC20, ERC20Votes) {
        /// @notice call to parent after transfer hook
        super._afterTokenTransfer(from, to, amount);
    }

    /**
     * @dev neccesarry override
     */
    function _mint(address account, uint256 amount) internal virtual override(ERC20, ERC20Votes) {
        /// @notice call to parent _mint
        super._mint(account, amount);
    }

    /**
     * @dev neccesarry override
     */
    function _burn(address account, uint256 amount) internal virtual override(ERC20, ERC20Votes) {
        /// @notice call to parent _burn
        super._burn(account, amount);
    }
}
/**
 * @title Art Circulation Governance Token
 * @notice ERC20-compliant+GovernorAlphaToken-style smart contract for ACG token
 * @author Jad A. Jabbour @ NFT Contemporary
 **/
function _mint(address account, uint256 amount) internal virtual override(ERC20, ERC20Votes) {
    /// @notice call to parent _mint
    super._mint(account, amount);
}

/**
 * @dev neccesarry override
 */