diff --git a/contracts/modules/licensing/PILicenseTemplate.sol b/contracts/modules/licensing/PILicenseTemplate.sol index 2964ce7ab..e9011fbdc 100644 --- a/contracts/modules/licensing/PILicenseTemplate.sol +++ b/contracts/modules/licensing/PILicenseTemplate.sol @@ -88,7 +88,11 @@ contract PILicenseTemplate is /// @param terms The PILTerms to register. /// @return id The ID of the newly registered license terms. function registerLicenseTerms(PILTerms calldata terms) external nonReentrant returns (uint256 id) { - if (terms.royaltyPolicy != address(0) && !ROYALTY_MODULE.isWhitelistedRoyaltyPolicy(terms.royaltyPolicy)) { + if ( + terms.royaltyPolicy != address(0) && + !ROYALTY_MODULE.isWhitelistedRoyaltyPolicy(terms.royaltyPolicy) && + !ROYALTY_MODULE.isRegisteredExternalRoyaltyPolicy(terms.royaltyPolicy) + ) { revert PILicenseTemplateErrors.PILicenseTemplate__RoyaltyPolicyNotWhitelisted(); } diff --git a/test/foundry/integration/flows/royalty/Royalty.t.sol b/test/foundry/integration/flows/royalty/Royalty.t.sol index 88e622bc2..b57fccbb7 100644 --- a/test/foundry/integration/flows/royalty/Royalty.t.sol +++ b/test/foundry/integration/flows/royalty/Royalty.t.sol @@ -4,13 +4,13 @@ pragma solidity 0.8.26; // external import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; -// import { ERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; // contracts import { IRoyaltyModule } from "../../../../../contracts/interfaces/modules/royalty/IRoyaltyModule.sol"; import { IpRoyaltyVault } from "../../../../../contracts/modules/royalty/policies/IpRoyaltyVault.sol"; import { Errors } from "../../../../../contracts/lib/Errors.sol"; import { PILFlavors } from "../../../../../contracts/lib/PILFlavors.sol"; +import { MockExternalRoyaltyPolicy1 } from "../../../mocks/policy/MockExternalRoyaltyPolicy1.sol"; // test import { BaseIntegration } from "../../BaseIntegration.t.sol"; @@ -196,5 +196,49 @@ contract Flows_Integration_Disputes is BaseIntegration { earningsFromMintingFees + (1 ether * (10_000_000 + 20_000_000)) / royaltyModule.maxPercent() ); } + + // A derivation occurs using an external royalty policy + { + // Register an external royalty policy + MockExternalRoyaltyPolicy1 mockExternalRoyaltyPolicy1 = new MockExternalRoyaltyPolicy1(); + royaltyModule.registerExternalRoyaltyPolicy(address(mockExternalRoyaltyPolicy1)); + + vm.startPrank(u.alice); + erc20.approve(address(royaltyModule), type(uint256).max); + + mockNFT.mintId(u.alice, 4); + ipAcct[4] = registerIpAccount(mockNFT, 4, u.alice); + vm.label(ipAcct[4], "IPAccount4"); + + uint256 commRemixExternalTermsId = registerSelectedPILicenseTerms( + "commercial_remix_external", + PILFlavors.commercialRemix({ + mintingFee: mintingFee, + commercialRevShare: defaultCommRevShare, + royaltyPolicy: address(mockExternalRoyaltyPolicy1), + currencyToken: address(erc20) + }) + ); + + licensingModule.attachLicenseTerms(ipAcct[4], address(pilTemplate), commRemixExternalTermsId); + + uint256[] memory licenseId = new uint256[](1); + licenseId[0] = licensingModule.mintLicenseTokens({ + licensorIpId: ipAcct[4], + licenseTemplate: address(pilTemplate), + licenseTermsId: commRemixExternalTermsId, + amount: 1, + receiver: u.alice, + royaltyContext: "" + }); + + mockNFT.mintId(u.alice, 5); + ipAcct[5] = registerIpAccount(mockNFT, 5, u.alice); + vm.label(ipAcct[5], "IPAccount5"); + + licensingModule.registerDerivativeWithLicenseTokens(ipAcct[5], licenseId, ""); + + vm.stopPrank(); + } } }