diff --git a/contracts/interfaces/workflows/IGroupingWorkflows.sol b/contracts/interfaces/workflows/IGroupingWorkflows.sol index d25672b..ef78758 100644 --- a/contracts/interfaces/workflows/IGroupingWorkflows.sol +++ b/contracts/interfaces/workflows/IGroupingWorkflows.sol @@ -78,13 +78,13 @@ interface IGroupingWorkflows { ) external returns (address groupId); /// @notice Collect royalties for the entire group and distribute the rewards to each member IP's royalty vault - /// @param groupId The ID of the group IP. + /// @param groupIpId The ID of the group IP. /// @param currencyTokens The addresses of the currency (revenue) tokens to claim. /// @param groupSnapshotIds The IDs of the snapshots to collect royalties on. /// @param memberIpIds The IDs of the member IPs to distribute the rewards to. /// @return collectedRoyalties The amounts of royalties collected for each currency token. function collectRoyaltiesAndClaimReward( - address groupId, + address groupIpId, address[] calldata currencyTokens, uint256[] calldata groupSnapshotIds, address[] calldata memberIpIds diff --git a/contracts/workflows/GroupingWorkflows.sol b/contracts/workflows/GroupingWorkflows.sol index 18464a2..8589080 100644 --- a/contracts/workflows/GroupingWorkflows.sol +++ b/contracts/workflows/GroupingWorkflows.sol @@ -11,6 +11,7 @@ import { ICoreMetadataModule } from "@storyprotocol/core/interfaces/modules/meta import { IGroupingModule } from "@storyprotocol/core/interfaces/modules/grouping/IGroupingModule.sol"; import { ILicensingModule } from "@storyprotocol/core/interfaces/modules/licensing/ILicensingModule.sol"; import { GroupNFT } from "@storyprotocol/core/GroupNFT.sol"; +import { RoyaltyModule } from "@storyprotocol/core/modules/royalty/RoyaltyModule.sol"; import { BaseWorkflow } from "../BaseWorkflow.sol"; import { Errors } from "../lib/Errors.sol"; @@ -51,6 +52,9 @@ contract GroupingWorkflows is /// @notice The address of the Group NFT contract. GroupNFT public immutable GROUP_NFT; + /// @notice The address of the Royalty Module. + RoyaltyModule public immutable ROYALTY_MODULE; + /// @custom:oz-upgrades-unsafe-allow constructor constructor( address accessController, @@ -60,7 +64,8 @@ contract GroupingWorkflows is address ipAssetRegistry, address licenseRegistry, address licensingModule, - address pilTemplate + address pilTemplate, + address royaltyModule ) BaseWorkflow( accessController, @@ -79,12 +84,13 @@ contract GroupingWorkflows is ipAssetRegistry == address(0) || licenseRegistry == address(0) || licensingModule == address(0) || - pilTemplate == address(0) + pilTemplate == address(0) || + royaltyModule == address(0) ) revert Errors.GroupingWorkflows__ZeroAddressParam(); GROUPING_MODULE = IGroupingModule(groupingModule); GROUP_NFT = GroupNFT(groupNft); - + ROYALTY_MODULE = RoyaltyModule(royaltyModule); _disableInitializers(); } @@ -275,22 +281,42 @@ contract GroupingWorkflows is } /// @notice Collect royalties for the entire group and distribute the rewards to each member IP's royalty vault - /// @param groupId The ID of the group IP. + /// @param groupIpId The ID of the group IP. /// @param currencyTokens The addresses of the currency (revenue) tokens to claim. /// @param groupSnapshotIds The IDs of the snapshots to collect royalties on. /// @param memberIpIds The IDs of the member IPs to distribute the rewards to. /// @return collectedRoyalties The amounts of royalties collected for each currency token. function collectRoyaltiesAndClaimReward( - address groupId, + address groupIpId, address[] calldata currencyTokens, uint256[] calldata groupSnapshotIds, address[] calldata memberIpIds ) external returns (uint256[] memory collectedRoyalties) { + (address groupLicenseTemplate, uint256 groupLicenseTermsId) = LICENSE_REGISTRY.getAttachedLicenseTerms( + groupIpId, + 0 + ); + for (uint256 i = 0; i < memberIpIds.length; i++) { + // check if given member IPs already have a royalty vault + if (ROYALTY_MODULE.ipRoyaltyVaults(memberIpIds[i]) == address(0)) { + // mint license tokens to the member IPs if they don't have a royalty vault + LICENSING_MODULE.mintLicenseTokens({ + licensorIpId: memberIpIds[i], + licenseTemplate: groupLicenseTemplate, + licenseTermsId: groupLicenseTermsId, + amount: 1, + receiver: msg.sender, + royaltyContext: "", + maxMintingFee: 0 + }); + } + } + collectedRoyalties = new uint256[](currencyTokens.length); for (uint256 i = 0; i < currencyTokens.length; i++) { if (currencyTokens[i] == address(0)) revert Errors.GroupingWorkflows__ZeroAddressParam(); - collectedRoyalties[i] = GROUPING_MODULE.collectRoyalties(groupId, currencyTokens[i], groupSnapshotIds); - GROUPING_MODULE.claimReward(groupId, currencyTokens[i], memberIpIds); + collectedRoyalties[i] = GROUPING_MODULE.collectRoyalties(groupIpId, currencyTokens[i], groupSnapshotIds); + GROUPING_MODULE.claimReward(groupIpId, currencyTokens[i], memberIpIds); } } diff --git a/script/upgrade/UpgradeGroupingWorkflows.s.sol b/script/upgrade/UpgradeGroupingWorkflows.s.sol index 89f72d4..323c3a7 100644 --- a/script/upgrade/UpgradeGroupingWorkflows.s.sol +++ b/script/upgrade/UpgradeGroupingWorkflows.s.sol @@ -41,7 +41,8 @@ contract UpgradeGroupingWorkflows is UpgradeHelper { ipAssetRegistryAddr, licenseRegistryAddr, licensingModuleAddr, - pilTemplateAddr + pilTemplateAddr, + royaltyModuleAddr ) ); console2.log("New GroupingWorkflows Implementation: ", newGroupingWorkflowsImpl); diff --git a/script/utils/DeployHelper.sol b/script/utils/DeployHelper.sol index 1e8d896..82621ba 100644 --- a/script/utils/DeployHelper.sol +++ b/script/utils/DeployHelper.sol @@ -302,7 +302,8 @@ contract DeployHelper is ipAssetRegistryAddr, licenseRegistryAddr, licensingModuleAddr, - pilTemplateAddr + pilTemplateAddr, + royaltyModuleAddr ) ); groupingWorkflows = GroupingWorkflows( diff --git a/test/workflows/DerivativeWorkflows.t.sol b/test/workflows/DerivativeWorkflows.t.sol index 4ac670b..0e75e71 100644 --- a/test/workflows/DerivativeWorkflows.t.sol +++ b/test/workflows/DerivativeWorkflows.t.sol @@ -42,7 +42,7 @@ contract DerivativeWorkflowsTest is BaseTest { terms: PILFlavors.commercialRemix({ mintingFee: 100 * 10 ** mockToken.decimals(), commercialRevShare: 10, // 1% - royaltyPolicy: address(royaltyPolicyLAP), + royaltyPolicy: address(royaltyPolicyLRP), currencyToken: address(mockToken) }) }); diff --git a/test/workflows/GroupingWorkflows.t.sol b/test/workflows/GroupingWorkflows.t.sol index ae7b708..0b070bb 100644 --- a/test/workflows/GroupingWorkflows.t.sol +++ b/test/workflows/GroupingWorkflows.t.sol @@ -334,23 +334,6 @@ contract GroupingWorkflowsTest is BaseTest { snapshotIds[1] = snapshotId2; royaltyTokens[0] = address(mockToken); - { - /* TODO: This is a workaround to avoid the error where the member IP's IP royalty vault is not initialized - * when claiming reward. remove this when the issue is fixed in core protocol. - */ - for (uint256 i = 0; i < ipIds.length; i++) { - licensingModule.mintLicenseTokens({ - licensorIpId: ipIds[i], - licenseTemplate: address(pilTemplate), - licenseTermsId: testLicenseTermsId, - amount: 1, - receiver: u.admin, - royaltyContext: "", - maxMintingFee: 0 - }); - } - } - uint256[] memory collectedRoyalties = groupingWorkflows.collectRoyaltiesAndClaimReward( newGroupId, royaltyTokens,