// SPDX-License-Identifier: MIT // Copyright (c) 2022 the ethier authors (github.com/divergencetech/ethier) pragma solidity >=0.8.0 <0.9.0; import {ERC721A} from "erc721a/contracts/ERC721A.sol"; import {ERC2981} from "@openzeppelin/contracts/token/common/ERC2981.sol"; import {AccessControlEnumerable} from "../utils/AccessControlEnumerable.sol"; import {AccessControlPausable} from "../utils/AccessControlPausable.sol"; import {ERC4906} from "./ERC4906.sol"; /** @notice An ERC721A contract with common functionality: - Pausable with toggling functions exposed to Owner only - ERC2981 royalties */ contract ERC721ACommon is ERC721A, AccessControlPausable, ERC2981, ERC4906 { constructor( address admin, address steerer, string memory name, string memory symbol, address payable royaltyReciever, uint96 royaltyBasisPoints ) ERC721A(name, symbol) { _setDefaultRoyalty(royaltyReciever, royaltyBasisPoints); _grantRole(DEFAULT_ADMIN_ROLE, admin); _grantRole(DEFAULT_STEERING_ROLE, steerer); } /// @notice Requires that the token exists. modifier tokenExists(uint256 tokenId) { require(ERC721A._exists(tokenId), "ERC721ACommon: Token doesn't exist"); _; } /// @notice Requires that msg.sender owns or is approved for the token. modifier onlyApprovedOrOwner(uint256 tokenId) { require( _ownershipOf(tokenId).addr == _msgSender() || getApproved(tokenId) == _msgSender(), "ERC721ACommon: Not approved nor owner" ); _; } function _beforeTokenTransfers( address from, address to, uint256 startTokenId, uint256 quantity ) internal virtual override { require(!paused(), "ERC721ACommon: paused"); super._beforeTokenTransfers(from, to, startTokenId, quantity); } /// @notice Overrides supportsInterface as required by inheritance. function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721A, AccessControlEnumerable, ERC2981, ERC4906) returns (bool) { return ERC721A.supportsInterface(interfaceId) || ERC2981.supportsInterface(interfaceId) || AccessControlEnumerable.supportsInterface(interfaceId) || ERC4906.supportsInterface(interfaceId); } /// @notice Sets the royalty receiver and percentage (in units of basis /// points = 0.01%). function setDefaultRoyalty(address receiver, uint96 basisPoints) public virtual onlyRole(DEFAULT_STEERING_ROLE) { _setDefaultRoyalty(receiver, basisPoints); } function emitMetadataUpdateForAll() external onlyRole(DEFAULT_STEERING_ROLE) { // EIP4906 is unfortunately quite vague on whether the `toTokenId` in // the following event is included or not. We hence use `totalSupply()` // to ensure that the last actual `tokenId` is included in any case. _refreshMetadata(0, totalSupply()); } }