abstract contract NFTOasis is AccessControl, ERC721URIStorage, Ownable {
    using Strings for uint256;

    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

    string private baseURI;
    IApprovalProxy public approvalProxy;

    event UpdateApprovalProxy(address _newProxyContract);

    constructor(string memory _name, string memory _symbol)
        ERC721(_name, _symbol)
    {
        _setRoleAdmin(MINTER_ROLE, MINTER_ROLE);
        _setupRole(MINTER_ROLE, _msgSender());
    }

    // mintable
    function mint(address to, uint256 tokenId) public {
        require(
            hasRole(MINTER_ROLE, _msgSender()),
            "ERC721Mintble: must have minter role to mint"
        );

        _mint(to, tokenId);
    }

    function mint(address[] memory _toList, uint256[] memory _tokenIdList)
        external
    {
        require(
            _toList.length == _tokenIdList.length,
            "input length must be same"
        );
        for (uint256 i = 0; i < _tokenIdList.length; i++) {
            mint(_toList[i], _tokenIdList[i]);
        }
    }

    function mintFor(
        address to,
        uint256 tokenId
    ) public {
        mint(to, tokenId);
    }

    function exists(uint256 tokenId) public view returns (bool) {
        return _exists(tokenId);
    }

    function setBaseURI(string memory __baseURI) external onlyOwner {
        baseURI = __baseURI;
    }

    function _baseURI() internal view override returns (string memory) {
        if (bytes(baseURI).length > 0) {
            return baseURI;
        }
        return
            string(
                abi.encodePacked(
                    "https://metadata-oasis.financie.jp/metadata/",
                    symbol(),
                    "/"
                )
            );
    }

    function setApprovalProxy(address _new) public onlyOwner {
        approvalProxy = IApprovalProxy(_new);
        emit UpdateApprovalProxy(_new);
    }

    function setApprovalForAll(address _spender, bool _approved)
        public
        virtual
        override
    {
        if (
            address(approvalProxy) != address(0x0) &&
            Address.isContract(_spender)
        ) {
            approvalProxy.setApprovalForAll(msg.sender, _spender, _approved);
        }
        super.setApprovalForAll(_spender, _approved);
    }

    function isApprovedForAll(address _owner, address _spender)
        public
        view
        override
        returns (bool)
    {
        bool original = super.isApprovedForAll(_owner, _spender);
        if (address(approvalProxy) != address(0x0)) {
            return approvalProxy.isApprovedForAll(_owner, _spender, original);
        }
        return original;
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override(AccessControl, ERC721)
        returns (bool)
    {
        return
            AccessControl.supportsInterface(interfaceId) ||
            ERC721.supportsInterface(interfaceId);
    }
}
function mint(address to, uint256 tokenId) public {
    require(
        hasRole(MINTER_ROLE, _msgSender()),
        "ERC721Mintble: must have minter role to mint"
    );

    _mint(to, tokenId);
}

// mintable