diff --git a/contracts/core/SoundEditionV2_1.sol b/contracts/core/SoundEditionV2_1.sol index 6751dcae..901d79a9 100644 --- a/contracts/core/SoundEditionV2_1.sol +++ b/contracts/core/SoundEditionV2_1.sol @@ -78,11 +78,21 @@ contract SoundEditionV2_1 is ISoundEditionV2_1, ERC721AQueryableUpgradeable, ERC */ uint16 public constant BPS_DENOMINATOR = LibOps.BPS_DENOMINATOR; + /** + * @dev For making the the interface ID different. + */ + bool public constant V2_1 = true; + /** * @dev The interface ID for EIP-2981 (royaltyInfo) */ bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a; + /** + * @dev The interface ID for SoundEditionV2. + */ + bytes4 private constant _INTERFACE_ID_SOUND_EDITION_V2 = 0x7888cfe1; + /** * @dev The boolean flag on whether the metadata is frozen. */ @@ -219,10 +229,9 @@ contract SoundEditionV2_1 is ISoundEditionV2_1, ERC721AQueryableUpgradeable, ERC address to, uint256 quantity ) external payable onlyRolesOrOwner(ADMIN_ROLE | MINTER_ROLE) returns (uint256 fromTokenId) { - uint32 fromTierTokenIdIndex; - (fromTokenId, fromTierTokenIdIndex) = _beforeTieredMint(tier, quantity); + (fromTokenId, ) = _beforeTieredMint(tier, quantity); _batchMint(to, quantity); - emit Minted(tier, to, quantity, fromTokenId, fromTierTokenIdIndex); + emit Minted(tier, to, quantity, fromTokenId); } /** @@ -233,17 +242,16 @@ contract SoundEditionV2_1 is ISoundEditionV2_1, ERC721AQueryableUpgradeable, ERC address[] calldata to, uint256 quantity ) external payable onlyRolesOrOwner(ADMIN_ROLE | MINTER_ROLE) returns (uint256 fromTokenId) { - uint32 fromTierTokenIdIndex; unchecked { // Multiplication overflow is not possible due to the max block gas limit. // If `quantity` is too big (e.g. 2**64), the loop in `_batchMint` will run out of gas. // If `to.length` is too big (e.g. 2**64), the airdrop mint loop will run out of gas. - (fromTokenId, fromTierTokenIdIndex) = _beforeTieredMint(tier, to.length * quantity); + (fromTokenId, ) = _beforeTieredMint(tier, to.length * quantity); for (uint256 i; i != to.length; ++i) { _batchMint(to[i], quantity); } } - emit Airdropped(tier, to, quantity, fromTokenId, fromTierTokenIdIndex); + emit Airdropped(tier, to, quantity, fromTokenId); } /** @@ -718,6 +726,7 @@ contract SoundEditionV2_1 is ISoundEditionV2_1, ERC721AQueryableUpgradeable, ERC LibOps.or( interfaceId == type(ISoundEditionV2_1).interfaceId, ERC721AUpgradeable.supportsInterface(interfaceId), + interfaceId == _INTERFACE_ID_SOUND_EDITION_V2, interfaceId == _INTERFACE_ID_ERC2981 ); } diff --git a/contracts/core/interfaces/ISoundEditionV2_1.sol b/contracts/core/interfaces/ISoundEditionV2_1.sol index 85b7ee12..0164090a 100644 --- a/contracts/core/interfaces/ISoundEditionV2_1.sol +++ b/contracts/core/interfaces/ISoundEditionV2_1.sol @@ -234,9 +234,8 @@ interface ISoundEditionV2_1 is IERC721AUpgradeable, IERC2981Upgradeable { * @param to The address to mint to. * @param quantity The number of minted. * @param fromTokenId The first token ID minted. - * @param fromTierTokenIdIndex The first token index in the tier. */ - event Minted(uint8 tier, address to, uint256 quantity, uint256 fromTokenId, uint32 fromTierTokenIdIndex); + event Minted(uint8 tier, address to, uint256 quantity, uint256 fromTokenId); /** * @dev Emitted upon an airdrop. @@ -244,9 +243,8 @@ interface ISoundEditionV2_1 is IERC721AUpgradeable, IERC2981Upgradeable { * @param to The recipients of the airdrop. * @param quantity The number of tokens airdropped to each address in `to`. * @param fromTokenId The first token ID minted to the first address in `to`. - * @param fromTierTokenIdIndex The first token index in the tier. */ - event Airdropped(uint8 tier, address[] to, uint256 quantity, uint256 fromTokenId, uint32 fromTierTokenIdIndex); + event Airdropped(uint8 tier, address[] to, uint256 quantity, uint256 fromTokenId); /** * @dev EIP-4906 event to signal marketplaces to refresh the metadata. @@ -810,4 +808,10 @@ interface ISoundEditionV2_1 is IERC721AUpgradeable, IERC2981Upgradeable { view override(IERC721AUpgradeable, IERC165Upgradeable) returns (bool); + + /** + * @dev Filler function to make the interface ID different. + * @return True. + */ + function V2_1() external view returns (bool); } diff --git a/tests/core/SoundEditionV2_1.t.sol b/tests/core/SoundEditionV2_1.t.sol index 1c24a847..d2426564 100644 --- a/tests/core/SoundEditionV2_1.t.sol +++ b/tests/core/SoundEditionV2_1.t.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; +import { ISoundEditionV2 } from "@core/SoundEditionV2.sol"; import { IERC721AUpgradeable, ISoundEditionV2_1, SoundEditionV2_1 } from "@core/SoundEditionV2_1.sol"; import { Ownable, OwnableRoles } from "solady/auth/OwnableRoles.sol"; import { LibSort } from "solady/utils/LibSort.sol"; @@ -25,8 +26,8 @@ contract SoundEditionV2_1Tests is TestConfigV2_1 { event TierFrozen(uint8 tier); event ETHWithdrawn(address recipient, uint256 amount, address caller); event ERC20Withdrawn(address recipient, address[] tokens, uint256[] amounts, address caller); - event Minted(uint8 tier, address to, uint256 quantity, uint256 fromTokenId, uint32 fromTierTokenIdIndex); - event Airdropped(uint8 tier, address[] to, uint256 quantity, uint256 fromTokenId, uint32 fromTierTokenIdIndex); + event Minted(uint8 tier, address to, uint256 quantity, uint256 fromTokenId); + event Airdropped(uint8 tier, address[] to, uint256 quantity, uint256 fromTokenId); event BatchMetadataUpdate(uint256 fromTokenId, uint256 toTokenId); uint16 public constant BPS_DENOMINATOR = 10000; @@ -143,10 +144,10 @@ contract SoundEditionV2_1Tests is TestConfigV2_1 { ) internal { uint256 r = _random() % 3; uint256 expectedFromTokenId = edition.nextTokenId(); - uint32 expectedFromTierTokenIdIndex = edition.tierInfo(tier).minted; + if (r == 0) { vm.expectEmit(true, true, true, true); - emit Minted(tier, to, quantity, expectedFromTokenId, expectedFromTierTokenIdIndex); + emit Minted(tier, to, quantity, expectedFromTokenId); edition.mint(tier, to, quantity); } else if (r == 1) { address[] memory recipients = new address[](quantity); @@ -154,13 +155,13 @@ contract SoundEditionV2_1Tests is TestConfigV2_1 { recipients[i] = to; } vm.expectEmit(true, true, true, true); - emit Airdropped(tier, recipients, 1, expectedFromTokenId, expectedFromTierTokenIdIndex); + emit Airdropped(tier, recipients, 1, expectedFromTokenId); edition.airdrop(tier, recipients, 1); } else { address[] memory recipients = new address[](1); recipients[0] = to; vm.expectEmit(true, true, true, true); - emit Airdropped(tier, recipients, quantity, expectedFromTokenId, expectedFromTierTokenIdIndex); + emit Airdropped(tier, recipients, quantity, expectedFromTokenId); edition.airdrop(tier, recipients, quantity); } } @@ -441,6 +442,7 @@ contract SoundEditionV2_1Tests is TestConfigV2_1 { assertTrue(edition.supportsInterface(0x80ac58cd)); // IERC721. assertTrue(edition.supportsInterface(0x01ffc9a7)); // IERC165. assertTrue(edition.supportsInterface(0x5b5e139f)); // IERC721Metadata. + assertTrue(edition.supportsInterface(type(ISoundEditionV2).interfaceId)); assertTrue(edition.supportsInterface(type(ISoundEditionV2_1).interfaceId)); assertFalse(edition.supportsInterface(0x11223344)); // Some random ID.