diff --git a/contracts/interfaces/workflows/IGroupingWorkflows.sol b/contracts/interfaces/workflows/IGroupingWorkflows.sol index b82858f..e90140e 100644 --- a/contracts/interfaces/workflows/IGroupingWorkflows.sol +++ b/contracts/interfaces/workflows/IGroupingWorkflows.sol @@ -51,6 +51,17 @@ interface IGroupingWorkflows { WorkflowStructs.SignatureData calldata sigAddToGroup ) external returns (address ipId); + /// @notice Register a group IP with a group reward pool and attach license terms to the group IP + /// @param groupPool The address of the group reward pool. + /// @param licenseTemplate The address of the license template to be attached to the new group IP. + /// @param licenseTermsId The ID of the registered license terms that will be attached to the new group IP. + /// @return groupId The ID of the newly registered group IP. + function registerGroupAndAttachLicense( + address groupPool, + address licenseTemplate, + uint256 licenseTermsId + ) external returns (address groupId); + /// @notice Register a group IP with a group reward pool, attach license terms to the group IP, /// and add individual IPs to the group IP. /// @dev ipIds must be have the same license terms as the group IP. diff --git a/contracts/workflows/GroupingWorkflows.sol b/contracts/workflows/GroupingWorkflows.sol index c3286e0..51f04a1 100644 --- a/contracts/workflows/GroupingWorkflows.sol +++ b/contracts/workflows/GroupingWorkflows.sol @@ -220,6 +220,30 @@ contract GroupingWorkflows is GROUPING_MODULE.addIp(groupId, ipIds); } + /// @notice Register a group IP with a group reward pool and attach license terms to the group IP + /// @param groupPool The address of the group reward pool. + /// @param licenseTemplate The address of the license template to be attached to the new group IP. + /// @param licenseTermsId The ID of the registered license terms that will be attached to the new group IP. + /// @return groupId The ID of the newly registered group IP. + function registerGroupAndAttachLicense( + address groupPool, + address licenseTemplate, + uint256 licenseTermsId + ) external returns (address groupId) { + groupId = GROUPING_MODULE.registerGroup(groupPool); + + // attach license terms to the group IP, do nothing if already attached + LicensingHelper.attachLicenseTerms( + groupId, + address(LICENSING_MODULE), + address(LICENSE_REGISTRY), + licenseTemplate, + licenseTermsId + ); + + GROUP_NFT.safeTransferFrom(address(this), msg.sender, GROUP_NFT.totalSupply() - 1); + } + /// @notice Register a group IP with a group reward pool, attach license terms to the group IP, /// and add individual IPs to the group IP. /// @dev ipIds must have the same PIL terms as the group IP. diff --git a/docs/WORKFLOWS.md b/docs/WORKFLOWS.md index 77a1ff7..0568d05 100644 --- a/docs/WORKFLOWS.md +++ b/docs/WORKFLOWS.md @@ -37,6 +37,8 @@ - Mints a NFT → Registers it as an IP → Attaches the given license terms to the IP → Adds the IP to a group IP - `registerIpAndAttachLicenseAndAddToGroup`: - Registers an IP → Attaches the given license terms to the IP → Adds the IP to a group IP +- `registerGroupAndAttachLicense`: + - Registers a group IP → Attaches the given license terms to the group IP - `registerGroupAndAttachLicenseAndAddIps`: - Registers a group IP → Attaches the given license terms to the group IP → Adds existing IPs to the group IP diff --git a/test/integration/workflows/GroupingIntegration.t.sol b/test/integration/workflows/GroupingIntegration.t.sol index 7eea2ac..1c64347 100644 --- a/test/integration/workflows/GroupingIntegration.t.sol +++ b/test/integration/workflows/GroupingIntegration.t.sol @@ -34,6 +34,7 @@ contract GroupingIntegration is BaseIntegration { _setUpTest(); _test_GroupingIntegration_mintAndRegisterIpAndAttachLicenseAndAddToGroup(); _test_GroupingIntegration_registerIpAndAttachLicenseAndAddToGroup(); + _test_GroupingIntegration_registerGroupAndAttachLicense(); _test_GroupingIntegration_registerGroupAndAttachLicenseAndAddIps(); _test_GroupingIntegration_multicall_mintAndRegisterIpAndAttachLicenseAndAddToGroup(); _test_GroupingIntegration_multicall_registerIpAndAttachLicenseAndAddToGroup(); @@ -147,6 +148,25 @@ contract GroupingIntegration is BaseIntegration { assertEq(licenseTermsId, testLicenseTermsId); } + function _test_GroupingIntegration_registerGroupAndAttachLicense() + private + logTest("test_GroupingIntegration_registerGroupAndAttachLicense") + { + address newGroupId = groupingWorkflows.registerGroupAndAttachLicense({ + groupPool: groupRewardPool, + licenseTemplate: testLicenseTemplate, + licenseTermsId: testLicenseTermsId + }); + + // check the group IPA is registered + assertTrue(IGroupIPAssetRegistry(ipAssetRegistryAddr).isRegisteredGroup(newGroupId)); + + // check the license terms is correctly attached to the group IPA + (address licenseTemplate, uint256 licenseTermsId) = licenseRegistry.getAttachedLicenseTerms(newGroupId, 0); + assertEq(licenseTemplate, testLicenseTemplate); + assertEq(licenseTermsId, testLicenseTermsId); + } + function _test_GroupingIntegration_registerGroupAndAttachLicenseAndAddIps() private logTest("test_GroupingIntegration_registerGroupAndAttachLicenseAndAddIps") diff --git a/test/workflows/GroupingWorkflows.t.sol b/test/workflows/GroupingWorkflows.t.sol index db96cdf..e00dc5d 100644 --- a/test/workflows/GroupingWorkflows.t.sol +++ b/test/workflows/GroupingWorkflows.t.sol @@ -173,6 +173,28 @@ contract GroupingWorkflowsTest is BaseTest { assertEq(licenseTermsId, testLicenseTermsId); } + // Register group IP → Attach license terms to group IPA + function test_GroupingWorkflows_registerGroupAndAttachLicense() public { + vm.startPrank(groupOwner); + address newGroupId = groupingWorkflows.registerGroupAndAttachLicense({ + groupPool: address(mockRewardPool), + licenseTemplate: address(pilTemplate), + licenseTermsId: testLicenseTermsId + }); + vm.stopPrank(); + + // check the group IPA is registered + assertTrue(IGroupIPAssetRegistry(ipAssetRegistry).isRegisteredGroup(newGroupId)); + + // check the license terms is correctly attached to the group IPA + (address licenseTemplate, uint256 licenseTermsId) = ILicenseRegistry(licenseRegistry).getAttachedLicenseTerms( + newGroupId, + 0 + ); + assertEq(licenseTemplate, address(pilTemplate)); + assertEq(licenseTermsId, testLicenseTermsId); + } + // Register group IP → Attach license terms to group IPA → Add existing IPs to the new group IPA function test_GroupingWorkflows_registerGroupAndAttachLicenseAndAddIps() public { vm.startPrank(groupOwner); diff --git a/yarn.lock b/yarn.lock index fbd4b8f..1cae3ba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -441,7 +441,7 @@ "@story-protocol/protocol-core@github:storyprotocol/protocol-core-v1#main": version "1.1.0" - resolved "https://codeload.github.com/storyprotocol/protocol-core-v1/tar.gz/0aed667579299c8a263a60236cb6d93f0ac8aa72" + resolved "https://codeload.github.com/storyprotocol/protocol-core-v1/tar.gz/7834ac522e8b0e3f95adffe15815c4b9b0412377" dependencies: "@openzeppelin/contracts" "5.0.2" "@openzeppelin/contracts-upgradeable" "5.0.2" @@ -495,9 +495,9 @@ integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== "@types/node@*": - version "22.7.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.3.tgz#7ddf1ddf13078692b4cfadb835852b2a718ee1ef" - integrity sha512-qXKfhXXqGTyBskvWEzJZPUxSslAiLaB6JGP1ic/XTH9ctGgzdgYguuLP1C601aRTSDNlLb0jbKqXjZ48GNraSA== + version "22.7.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.4.tgz#e35d6f48dca3255ce44256ddc05dee1c23353fcc" + integrity sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg== dependencies: undici-types "~6.19.2"