// File: contracts/KaijuAugmintsBatchMintExtension.sol



// SPDX-License-Identifier: Unlicense

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/IAccessControl.sol";

interface IKaijuAugmints is IAccessControl {
    function mint(address to, uint256 id, uint256 amount) external;
    function mintBatch(address to, uint256[] calldata ids, uint256[] calldata amounts) external;
}

error KaijuAugmintsBatchMintExtension_NotAllowed();

/**
                        .             :++-
                       *##-          +####*          -##+
                       *####-      :%######%.      -%###*
                       *######:   =##########=   .######*
                       *#######*-#############*-*#######*
                       *################################*
                       *################################*
                       *################################*
                       *################################*
                       *################################*
                       :*******************************+.

                .:.
               *###%*=:
              .##########+-.
              +###############=:
              %##################%+
             =######################
             -######################++++++++++++++++++=-:
              =###########################################*:
               =#############################################.
  +####%#*+=-:. -#############################################:
  %############################################################=
  %##############################################################
  %##############################################################%=----::.
  %#######################################################################%:
  %##########################################+:    :+%#######################:
  *########################################*          *#######################
   -%######################################            %######################
     -%###################################%            #######################
       =###################################-          :#######################
     ....+##################################*.      .+########################
  +###########################################%*++*%##########################
  %#########################################################################*.
  %#######################################################################+
  ########################################################################-
  *#######################################################################-
  .######################################################################%.
     :+#################################################################-
         :=#####################################################:.....
             :--:.:##############################################+
   ::             +###############################################%-
  ####%+-.        %##################################################.
  %#######%*-.   :###################################################%
  %###########%*=*####################################################=
  %####################################################################
  %####################################################################+
  %#####################################################################.
  %#####################################################################%
  %######################################################################-
  .+*********************************************************************.
 * @title Kaiju Augmints Batch Mint Extension
 * @author Augminted Labs, LLC
 * @notice Additional functions used for mass minting/airdropping Kaiju Augmints more efficiently
 */
contract KaijuAugmintsBatchMintExtension {
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

    IKaijuAugmints public immutable AUGMINTS;

    constructor(IKaijuAugmints augmints) {
        AUGMINTS = augmints;
    }

    /**
     * @notice Modifier that requires the sender to have the `MINTER_ROLE` role
     */
    modifier onlyMinter() {
        if (!AUGMINTS.hasRole(MINTER_ROLE, msg.sender)) revert KaijuAugmintsBatchMintExtension_NotAllowed();
        _;
    }

    /**
     * @notice Mass mint tokens to specified addresses
     * @param receivers Addresses receiving the minted tokens
     * @param ids Token identifiers to mint
     * @param amounts Amounts of the tokens to mint
     */
    function multiMint(
        address[] calldata receivers,
        uint256[] calldata ids,
        uint256[] calldata amounts
    )
        public
        onlyMinter
    {
        uint256 length = receivers.length;
        for (uint i; i < length;) {
            AUGMINTS.mint(receivers[i], ids[i], amounts[i]);
            unchecked { ++i; }
        }
    }

    /**
     * @notice Mass mint batches of tokens to specified addresses
     * @param receivers Addresses receiving the minted tokens
     * @param idsBatches Batches of token identifiers to mint
     * @param amountsBatches Batches of amounts of the tokens to mint
     */
    function multiMintBatch(
        address[] calldata receivers,
        uint256[][] calldata idsBatches,
        uint256[][] calldata amountsBatches
    )
        public
        onlyMinter
    {
        uint256 length = receivers.length;
        for (uint i; i < length;) {
            AUGMINTS.mintBatch(receivers[i], idsBatches[i], amountsBatches[i]);
            unchecked { ++i; }
        }
    }
}
// File: @openzeppelin/contracts/access/IAccessControl.sol



// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}