contract Wabipunks is ERC721Enumerable, Pausable, AccessControl {
  using Strings for uint256;
  using Counters for Counters.Counter;

  Counters.Counter private _babiesIds;
  uint256 public _supply = 10000;
  string private _uri;
  string private _extension;
  mapping(address => bool) private _whitelist;
  bytes32 public constant MINTER_ROLE = keccak256("WABIMINTER");
  bytes32 public constant BURNER_ROLE = keccak256("WABIBURNER");
  address payable private wabiWallet;

  constructor(
    string memory uri_,
    address payable wabiWallet_
  )
    ERC721("WabiPunks", "WPKS")
  {
    _uri = uri_;
    _extension = "";
    wabiWallet = wabiWallet_;
    _setupRole(DEFAULT_ADMIN_ROLE, 0xC3f3dd9c23264607F703edC1638aCc307b66a375);
    _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
  }

  function transfer(address to, uint256 tokenId) external {
    _transfer(msg.sender, to, tokenId);
  }

  /**
        @dev Mint new token and maps to receiver
    */
  function mint(uint256 amount, address to)
    external
    payable
    whenNotPaused
    onlyRole(MINTER_ROLE)
  {
    for (uint256 i = 0; i < amount; i++) {
      _babiesIds.increment();
      _safeMint(to, _babiesIds.current());
    }
  }

  function allTokensByOwner(address _owner)
    public
    view
    returns (uint256[] memory)
  {
    uint256 ownerBalance = balanceOf(_owner);
    uint256[] memory tokenIds = new uint256[](ownerBalance);
    for (uint256 i; i < ownerBalance; i++) {
      tokenIds[i] = tokenOfOwnerByIndex(_owner, i);
    }
    return tokenIds;
  }

  /**
        @dev Base URI getter
        @return Base URI
    */
  function _baseURI() internal view virtual override returns (string memory) {
    return _uri;
  }

  /**
        @dev Get token URI by token ID, adds .json extension
        @return URI of the token metadata 
    */
  function tokenURI(uint256 tokenId)
    public
    view
    virtual
    override
    returns (string memory)
  {
    string memory baseURI = _baseURI();
    return
      bytes(baseURI).length > 0
        ? string(abi.encodePacked(baseURI, tokenId.toString(), _extension))
        : "";
  }

  function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721Enumerable, AccessControl) returns (bool) {
    return super.supportsInterface(interfaceId);
  }

  function burn(uint256 tokenId) external onlyRole(BURNER_ROLE) {
    require(
      _isApprovedOrOwner(_msgSender(), tokenId),
      "ERC721Burnable: caller is not owner nor approved"
    );
    _burn(tokenId);
  }

  /**
    @dev Change Base URI can be used to reveal NFTs
    @param uri_ String of the new uri
     */
  function changeBaseURI(string memory uri_) external onlyRole(DEFAULT_ADMIN_ROLE) {
    _uri = uri_;
  }

  function changeExtension(string memory extension_) external onlyRole(DEFAULT_ADMIN_ROLE) {
    _extension = extension_;
  }

  function changewabiWallet(address payable newWallet) external onlyRole(DEFAULT_ADMIN_ROLE) {
    wabiWallet = newWallet;
  }
  /**
    @dev Withdraw ETH balance to the owner
     */
  function withdraw() external onlyRole(DEFAULT_ADMIN_ROLE) {
    wabiWallet.transfer(address(this).balance);
  }

  /**
    @dev Change supply
    @param supply_ New supply
     */
  function changeSupply(uint256 supply_) external onlyRole(DEFAULT_ADMIN_ROLE) {
    require(supply_ >= totalSupply(), "Wabipunks: New Supply is below totalSupply");
    _supply = supply_;
  }

  function pause() external onlyRole(DEFAULT_ADMIN_ROLE) {
    _pause();
  }

  function unPause() external onlyRole(DEFAULT_ADMIN_ROLE) {
    _unpause();
  }
}
function changeSupply(uint256 supply_) external onlyRole(DEFAULT_ADMIN_ROLE) {
  require(supply_ >= totalSupply(), "Wabipunks: New Supply is below totalSupply");
  _supply = supply_;
}

/**
 @dev Change supply
 @param supply_ New supply
 */