Skip to content

Commit

Permalink
Implement Verification for Identical Royalty Policies When Registerin…
Browse files Browse the repository at this point in the history
…g Derivative with Multiple Parent IPs (#351)
  • Loading branch information
kingster-will authored Dec 12, 2024
1 parent fe111b6 commit 57ebf6a
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 4 deletions.
3 changes: 3 additions & 0 deletions contracts/lib/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,9 @@ library Errors {
uint32 newRoyaltyPercent
);

/// @notice register derivative require all parent IP to have the same royalty policy.
error LicensingModule__RoyaltyPolicyMismatch(address royaltyPolicy, address anotherRoyaltyPolicy);

////////////////////////////////////////////////////////////////////////////
// Dispute Module //
////////////////////////////////////////////////////////////////////////////
Expand Down
29 changes: 25 additions & 4 deletions contracts/modules/licensing/LicensingModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -534,9 +534,14 @@ contract LicensingModule is
ILicenseTemplate lct = ILicenseTemplate(licenseTemplate);
// Confirm that the royalty policies defined in all license terms of the parent IPs are identical.
address[] memory rPolicies = new address[](parentIpIds.length);
for (uint256 i = 0; i < parentIpIds.length; i++) {
(address royaltyPolicy, , , ) = lct.getRoyaltyPolicy(licenseTermsIds[i]);
(address royaltyPolicy, , , ) = lct.getRoyaltyPolicy(licenseTermsIds[0]);
rPolicies[0] = royaltyPolicy;
for (uint256 i = 1; i < parentIpIds.length; i++) {
(royaltyPolicy, , , ) = lct.getRoyaltyPolicy(licenseTermsIds[i]);
rPolicies[i] = royaltyPolicy;
if (rPolicies[i] != rPolicies[0]) {
revert Errors.LicensingModule__RoyaltyPolicyMismatch(rPolicies[0], rPolicies[1]);
}
}

if (rPolicies.length != 0 && rPolicies[0] != address(0)) {
Expand All @@ -559,9 +564,22 @@ contract LicensingModule is
) private returns (address[] memory royaltyPolicies, uint32[] memory royaltyPercents) {
royaltyPolicies = new address[](licenseTermsIds.length);
royaltyPercents = new uint32[](licenseTermsIds.length);
if (licenseTermsIds.length == 0) return (royaltyPolicies, royaltyPercents);

(address royaltyPolicy, uint32 royaltyPercent) = _executeLicensingHookAndPayMintingFee(
childIpId,
parentIpIds[0],
licenseTemplate,
licenseTermsIds[0],
royaltyContext,
maxMintingFee
);
royaltyPolicies[0] = royaltyPolicy;
royaltyPercents[0] = royaltyPercent;

// pay minting fee for all parent IPs
for (uint256 i = 0; i < parentIpIds.length; i++) {
(address royaltyPolicy, uint32 royaltyPercent) = _executeLicensingHookAndPayMintingFee(
for (uint256 i = 1; i < parentIpIds.length; i++) {
(royaltyPolicy, royaltyPercent) = _executeLicensingHookAndPayMintingFee(
childIpId,
parentIpIds[i],
licenseTemplate,
Expand All @@ -571,6 +589,9 @@ contract LicensingModule is
);
royaltyPolicies[i] = royaltyPolicy;
royaltyPercents[i] = royaltyPercent;
if (royaltyPolicies[i] != royaltyPolicies[0]) {
revert Errors.LicensingModule__RoyaltyPolicyMismatch(royaltyPolicies[0], royaltyPolicies[i]);
}
}
}

Expand Down
89 changes: 89 additions & 0 deletions test/foundry/modules/licensing/LicensingModule.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1245,6 +1245,95 @@ contract LicensingModuleTest is BaseTest {
licensingModule.registerDerivativeWithLicenseTokens(ipId3, licenseTokens, "", 100e6);
}

function test_LicensingModule_registerDerivativeWithLicenseTokens_revert_royaltyPolicyMismatch() public {
PILTerms memory terms = PILFlavors.commercialRemix({
mintingFee: 0,
commercialRevShare: 10,
royaltyPolicy: address(royaltyPolicyLAP),
currencyToken: address(erc20)
});
terms.derivativesReciprocal = false;

uint256 termsIdLAP = pilTemplate.registerLicenseTerms(terms);
vm.prank(ipOwner1);
licensingModule.attachLicenseTerms(ipId1, address(pilTemplate), termsIdLAP);

terms.royaltyPolicy = address(royaltyPolicyLRP);
uint256 termsIdLRP = pilTemplate.registerLicenseTerms(terms);
vm.prank(ipOwner2);
licensingModule.attachLicenseTerms(ipId2, address(pilTemplate), termsIdLRP);

uint256 lcTokenId1 = licensingModule.mintLicenseTokens({
licensorIpId: ipId1,
licenseTemplate: address(pilTemplate),
licenseTermsId: termsIdLAP,
amount: 1,
receiver: ipOwner3,
royaltyContext: "",
maxMintingFee: 0
});

uint256 lcTokenId2 = licensingModule.mintLicenseTokens({
licensorIpId: ipId2,
licenseTemplate: address(pilTemplate),
licenseTermsId: termsIdLRP,
amount: 1,
receiver: ipOwner3,
royaltyContext: "",
maxMintingFee: 0
});

uint256[] memory licenseTokens = new uint256[](2);
licenseTokens[0] = lcTokenId1;
licenseTokens[1] = lcTokenId2;
vm.prank(ipOwner3);
vm.expectRevert(
abi.encodeWithSelector(
Errors.LicensingModule__RoyaltyPolicyMismatch.selector,
address(royaltyPolicyLAP),
address(royaltyPolicyLRP)
)
);
licensingModule.registerDerivativeWithLicenseTokens(ipId3, licenseTokens, "", 100e6);
}

function test_LicensingModule_registerDerivative_revert_royaltyPolicyMismatch() public {
PILTerms memory terms = PILFlavors.commercialRemix({
mintingFee: 0,
commercialRevShare: 10,
royaltyPolicy: address(royaltyPolicyLAP),
currencyToken: address(erc20)
});
terms.derivativesReciprocal = false;

uint256 termsIdLAP = pilTemplate.registerLicenseTerms(terms);
vm.prank(ipOwner1);
licensingModule.attachLicenseTerms(ipId1, address(pilTemplate), termsIdLAP);

terms.royaltyPolicy = address(royaltyPolicyLRP);
uint256 termsIdLRP = pilTemplate.registerLicenseTerms(terms);
vm.prank(ipOwner2);
licensingModule.attachLicenseTerms(ipId2, address(pilTemplate), termsIdLRP);

address[] memory parentIpIds = new address[](2);
parentIpIds[0] = ipId1;
parentIpIds[1] = ipId2;

uint256[] memory licenseTermsIds = new uint256[](2);
licenseTermsIds[0] = termsIdLAP;
licenseTermsIds[1] = termsIdLRP;

vm.expectRevert(
abi.encodeWithSelector(
Errors.LicensingModule__RoyaltyPolicyMismatch.selector,
address(royaltyPolicyLAP),
address(royaltyPolicyLRP)
)
);
vm.prank(ipOwner3);
licensingModule.registerDerivative(ipId3, parentIpIds, licenseTermsIds, address(pilTemplate), "", 0, 100e6);
}

function test_LicensingModule_registerDerivativeWithLicenseTokens_ownedByDelegator() public {
vm.prank(ipOwner3);
accessController.setAllPermissions(ipId3, ipOwner2, AccessPermission.ALLOW);
Expand Down

0 comments on commit 57ebf6a

Please sign in to comment.