diff --git a/contracts/LicenseToken.sol b/contracts/LicenseToken.sol index 424b4851..0eb6f877 100644 --- a/contracts/LicenseToken.sol +++ b/contracts/LicenseToken.sol @@ -27,6 +27,9 @@ contract LicenseToken is ILicenseToken, ERC721EnumerableUpgradeable, AccessManag /// @custom:oz-upgrades-unsafe-allow state-variable-immutable IDisputeModule public immutable DISPUTE_MODULE; + /// @notice Max Royalty percentage is 100_000_000 means 100%. + uint32 public constant MAX_COMMERCIAL_REVENUE_SHARE = 100_000_000; + /// @notice Emitted for metadata updates, per EIP-4906 event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId); @@ -102,6 +105,14 @@ contract LicenseToken is ILicenseToken, ERC721EnumerableUpgradeable, AccessManag commercialRevShare: LICENSE_REGISTRY.getRoyaltyPercent(licensorIpId, licenseTemplate, licenseTermsId) }); + if (ltm.commercialRevShare > MAX_COMMERCIAL_REVENUE_SHARE) { + revert Errors.LicenseToken__InvalidRoyaltyPercent( + ltm.commercialRevShare, + licensorIpId, + licenseTemplate, + licenseTermsId + ); + } LicenseTokenStorage storage $ = _getLicenseTokenStorage(); startLicenseTokenId = $.totalMintedTokens; $.totalMintedTokens += amount; diff --git a/contracts/lib/Errors.sol b/contracts/lib/Errors.sol index 04940039..938972e9 100644 --- a/contracts/lib/Errors.sol +++ b/contracts/lib/Errors.sol @@ -289,6 +289,14 @@ library Errors { address anotherLicenseTemplate ); + /// @notice Royalty percentage is invalid that over 100%. + error LicenseToken__InvalidRoyaltyPercent( + uint32 invalidRoyaltyPercent, + address ipId, + address licenseTemplate, + uint256 licenseTermsId + ); + //////////////////////////////////////////////////////////////////////////// // Licensing Module // //////////////////////////////////////////////////////////////////////////// diff --git a/test/foundry/LicenseToken.t.sol b/test/foundry/LicenseToken.t.sol index 7a0eac5c..98645a6a 100644 --- a/test/foundry/LicenseToken.t.sol +++ b/test/foundry/LicenseToken.t.sol @@ -243,4 +243,44 @@ contract LicenseTokenTest is BaseTest { assertEq(lmt.commercialRevShare, 20_000_000); assertEq(lmt.transferable, true); } + + function test_LicenseToken_mintLicenseToken_revert_InvalidRoyaltyPercentage() public { + uint256 licenseTermsId = pilTemplate.registerLicenseTerms( + PILFlavors.commercialRemix(0, 100_000_000, address(royaltyPolicyLAP), address(USDC)) + ); + + // attach license terms to the ipAcct + Licensing.LicensingConfig memory licensingConfig = Licensing.LicensingConfig({ + isSet: true, + mintingFee: 0, + licensingHook: address(0), + hookData: "", + commercialRevShare: 200_000_000, + disabled: false, + expectMinimumGroupRewardShare: 0, + expectGroupRewardPool: address(0) + }); + vm.startPrank(ipOwner[1]); + licensingModule.attachLicenseTerms(ipAcct[1], address(pilTemplate), licenseTermsId); + licensingModule.setLicensingConfig(ipAcct[1], address(pilTemplate), licenseTermsId, licensingConfig); + vm.stopPrank(); + vm.prank(address(licensingModule)); + vm.expectRevert( + abi.encodeWithSelector( + Errors.LicenseToken__InvalidRoyaltyPercent.selector, + 200_000_000, + ipAcct[1], + address(pilTemplate), + licenseTermsId + ) + ); + uint256 licenseTokenId = licenseToken.mintLicenseTokens({ + licensorIpId: ipAcct[1], + licenseTemplate: address(pilTemplate), + licenseTermsId: licenseTermsId, + amount: 1, + minter: ipOwner[1], + receiver: ipOwner[1] + }); + } }