diff --git a/contracts/interfaces/workflows/IRegistrationWorkflows.sol b/contracts/interfaces/workflows/IRegistrationWorkflows.sol index cefecd1..5fe30a7 100644 --- a/contracts/interfaces/workflows/IRegistrationWorkflows.sol +++ b/contracts/interfaces/workflows/IRegistrationWorkflows.sol @@ -44,4 +44,16 @@ interface IRegistrationWorkflows { WorkflowStructs.IPMetadata calldata ipMetadata, WorkflowStructs.SignatureData calldata sigMetadata ) external returns (address ipId); + + //////////////////////////////////////////////////////////////////////////// + // DEPRECATED, WILL BE REMOVED IN V1.4 // + //////////////////////////////////////////////////////////////////////////// + + /// @notice Mint an NFT from a SPGNFT collection and register it with metadata as an IP. + /// @notice THIS VERSION OF THE FUNCTION IS DEPRECATED, WILL BE REMOVED IN V1.4 + function mintAndRegisterIp( + address spgNftContract, + address recipient, + WorkflowStructs.IPMetadata calldata ipMetadata + ) external returns (address ipId, uint256 tokenId); } diff --git a/contracts/workflows/RegistrationWorkflows.sol b/contracts/workflows/RegistrationWorkflows.sol index 7cb366e..6cdec49 100644 --- a/contracts/workflows/RegistrationWorkflows.sol +++ b/contracts/workflows/RegistrationWorkflows.sol @@ -165,4 +165,26 @@ contract RegistrationWorkflows is /// @dev Hook to authorize the upgrade according to UUPSUpgradeable /// @param newImplementation The address of the new implementation function _authorizeUpgrade(address newImplementation) internal override restricted {} + + //////////////////////////////////////////////////////////////////////////// + // DEPRECATED, WILL BE REMOVED IN V1.4 // + //////////////////////////////////////////////////////////////////////////// + /// @notice Mint an NFT from a SPGNFT collection and register it with metadata as an IP. + /// @notice THIS VERSION OF THE FUNCTION IS DEPRECATED, WILL BE REMOVED IN V1.4 + function mintAndRegisterIp( + address spgNftContract, + address recipient, + WorkflowStructs.IPMetadata calldata ipMetadata + ) external onlyMintAuthorized(spgNftContract) returns (address ipId, uint256 tokenId) { + tokenId = ISPGNFT(spgNftContract).mintByPeriphery({ + to: address(this), + payer: msg.sender, + nftMetadataURI: ipMetadata.nftMetadataURI, + nftMetadataHash: "", + allowDuplicates: true + }); + ipId = IP_ASSET_REGISTRY.register(block.chainid, spgNftContract, tokenId); + MetadataHelper.setMetadata(ipId, address(CORE_METADATA_MODULE), ipMetadata); + ISPGNFT(spgNftContract).safeTransferFrom(address(this), recipient, tokenId, ""); + } } diff --git a/test/integration/workflows/GroupingIntegration.t.sol b/test/integration/workflows/GroupingIntegration.t.sol index ad2dcee..f40caf6 100644 --- a/test/integration/workflows/GroupingIntegration.t.sol +++ b/test/integration/workflows/GroupingIntegration.t.sol @@ -518,7 +518,7 @@ contract GroupingIntegration is BaseIntegration { bytes[] memory data = new bytes[](numIps); for (uint256 i = 0; i < numIps; i++) { data[i] = abi.encodeWithSelector( - registrationWorkflows.mintAndRegisterIp.selector, + bytes4(keccak256("mintAndRegisterIp(address,address,(string,bytes32,string,bytes32),bool)")), address(spgNftContract), testSender, testIpMetadata diff --git a/test/integration/workflows/RegistrationIntegration.t.sol b/test/integration/workflows/RegistrationIntegration.t.sol index 30d3f23..6ced099 100644 --- a/test/integration/workflows/RegistrationIntegration.t.sol +++ b/test/integration/workflows/RegistrationIntegration.t.sol @@ -182,7 +182,7 @@ contract RegistrationIntegration is BaseIntegration { bytes[] memory data = new bytes[](totalIps); for (uint256 i = 0; i < totalIps; i++) { data[i] = abi.encodeWithSelector( - registrationWorkflows.mintAndRegisterIp.selector, + bytes4(keccak256("mintAndRegisterIp(address,address,(string,bytes32,string,bytes32),bool)")), address(spgNftContract), testSender, testIpMetadata diff --git a/test/workflows/GroupingWorkflows.t.sol b/test/workflows/GroupingWorkflows.t.sol index 630cad3..c73ae28 100644 --- a/test/workflows/GroupingWorkflows.t.sol +++ b/test/workflows/GroupingWorkflows.t.sol @@ -612,7 +612,7 @@ contract GroupingWorkflowsTest is BaseTest, ERC721Holder { bytes[] memory data = new bytes[](10); for (uint256 i = 0; i < 10; i++) { data[i] = abi.encodeWithSelector( - registrationWorkflows.mintAndRegisterIp.selector, + bytes4(keccak256("mintAndRegisterIp(address,address,(string,bytes32,string,bytes32),bool)")), address(spgNftPublic), minter, ipMetadataDefault, diff --git a/test/workflows/RegistrationWorkflows.t.sol b/test/workflows/RegistrationWorkflows.t.sol index 8a26b69..bf473c1 100644 --- a/test/workflows/RegistrationWorkflows.t.sol +++ b/test/workflows/RegistrationWorkflows.t.sol @@ -245,7 +245,7 @@ contract RegistrationWorkflowsTest is BaseTest { bytes[] memory data = new bytes[](10); for (uint256 i = 0; i < 10; i++) { data[i] = abi.encodeWithSelector( - registrationWorkflows.mintAndRegisterIp.selector, + bytes4(keccak256("mintAndRegisterIp(address,address,(string,bytes32,string,bytes32),bool)")), address(nftContract), u.bob, ipMetadataDefault, @@ -263,4 +263,128 @@ contract RegistrationWorkflowsTest is BaseTest { assertMetadata(ipIds[i], ipMetadataDefault); } } + + //////////////////////////////////////////////////////////////////////////// + // DEPRECATED, WILL BE REMOVED IN V1.4 // + //////////////////////////////////////////////////////////////////////////// + function test_RegistrationWorkflows_revert_mintAndRegisterIp_callerNotAuthorizedToMint_DEPR() public { + vm.prank(u.alice); // minter and admin of nftContract + nftContract = ISPGNFT( + registrationWorkflows.createCollection( + ISPGNFT.InitParams({ + name: "Test Private Collection", + symbol: "TESTPRIV", + baseURI: testBaseURI, + contractURI: testContractURI, + maxSupply: 100, + mintFee: 100 * 10 ** mockToken.decimals(), + mintFeeToken: address(mockToken), + mintFeeRecipient: feeRecipient, + owner: minter, + mintOpen: true, + isPublicMinting: false // not public minting + }) + ) + ); + + vm.expectRevert(Errors.Workflow__CallerNotAuthorizedToMint.selector); + vm.prank(u.bob); // caller does not have minter role + registrationWorkflows.mintAndRegisterIp({ + spgNftContract: address(nftContract), + recipient: u.bob, + ipMetadata: ipMetadataEmpty + }); + } + + function test_RegistrationWorkflows_mintAndRegisterIp_publicMint_DEPR() public { + vm.prank(u.alice); // minter and admin of nftContract + nftContract = ISPGNFT( + registrationWorkflows.createCollection( + ISPGNFT.InitParams({ + name: "Test Public Collection", + symbol: "TESTPUB", + baseURI: testBaseURI, + contractURI: testContractURI, + maxSupply: 100, + mintFee: 1 * 10 ** mockToken.decimals(), + mintFeeToken: address(mockToken), + mintFeeRecipient: feeRecipient, + owner: minter, + mintOpen: true, + isPublicMinting: true // public minting is enabled + }) + ) + ); + + vm.startPrank(u.bob); // caller does not have minter role + mockToken.mint(address(u.bob), 1000 * 10 ** mockToken.decimals()); + mockToken.approve(address(nftContract), 1000 * 10 ** mockToken.decimals()); + + // caller has minter role and public minting is enabled + (address ipId, uint256 tokenId) = registrationWorkflows.mintAndRegisterIp({ + spgNftContract: address(nftContract), + recipient: u.bob, + ipMetadata: ipMetadataEmpty + }); + vm.stopPrank(); + + assertTrue(ipAssetRegistry.isRegistered(ipId)); + assertEq(tokenId, 1); + assertEq(nftContract.tokenURI(tokenId), string.concat(testBaseURI, tokenId.toString())); + assertMetadata(ipId, ipMetadataEmpty); + } + + function test_RegistrationWorkflows_mintAndRegisterIp_DEPR() public withCollection whenCallerHasMinterRole { + mockToken.mint(address(caller), 1000 * 10 ** mockToken.decimals()); + mockToken.approve(address(nftContract), 1000 * 10 ** mockToken.decimals()); + + (address ipId1, uint256 tokenId1) = registrationWorkflows.mintAndRegisterIp({ + spgNftContract: address(nftContract), + recipient: u.bob, + ipMetadata: ipMetadataEmpty + }); + assertEq(tokenId1, 1); + assertTrue(ipAssetRegistry.isRegistered(ipId1)); + assertEq(nftContract.tokenURI(tokenId1), string.concat(testBaseURI, tokenId1.toString())); + assertMetadata(ipId1, ipMetadataEmpty); + + (address ipId2, uint256 tokenId2) = registrationWorkflows.mintAndRegisterIp({ + spgNftContract: address(nftContract), + recipient: u.bob, + ipMetadata: ipMetadataDefault + }); + assertEq(tokenId2, 2); + assertTrue(ipAssetRegistry.isRegistered(ipId2)); + assertEq(nftContract.tokenURI(tokenId2), string.concat(testBaseURI, ipMetadataDefault.nftMetadataURI)); + assertMetadata(ipId2, ipMetadataDefault); + } + + function test_RegistrationWorkflows_multicall_mintAndRegisterIp_DEPR() + public + withCollection + whenCallerHasMinterRole + { + mockToken.mint(address(caller), 1000 * 10 * 10 ** mockToken.decimals()); + mockToken.approve(address(nftContract), 1000 * 10 * 10 ** mockToken.decimals()); + + bytes[] memory data = new bytes[](10); + for (uint256 i = 0; i < 10; i++) { + data[i] = abi.encodeWithSelector( + bytes4(keccak256("mintAndRegisterIp(address,address,(string,bytes32,string,bytes32))")), + address(nftContract), + u.bob, + ipMetadataDefault + ); + } + bytes[] memory results = registrationWorkflows.multicall(data); + address[] memory ipIds = new address[](10); + uint256[] memory tokenIds = new uint256[](10); + + for (uint256 i = 0; i < 10; i++) { + (ipIds[i], tokenIds[i]) = abi.decode(results[i], (address, uint256)); + assertTrue(ipAssetRegistry.isRegistered(ipIds[i])); + assertEq(nftContract.tokenURI(tokenIds[i]), string.concat(testBaseURI, ipMetadataDefault.nftMetadataURI)); + assertMetadata(ipIds[i], ipMetadataDefault); + } + } }