Skip to content

Commit e644c3e

Browse files
committed
fix(licensing-hook): check tot supply b4 set limit
1 parent 68bc52d commit e644c3e

File tree

2 files changed

+78
-10
lines changed

2 files changed

+78
-10
lines changed

contracts/hooks/TotalLicenseTokenLimitHook.sol

+23-6
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,27 @@ contract TotalLicenseTokenLimitHook is BaseModule, AccessControlled, ILicensingH
3333
/// @param totalSupply The total supply of the license tokens
3434
/// @param amount The amount of license tokens to mint
3535
/// @param limit The total license token limit
36-
error TotalLicenseTokenLimitExceeded(uint256 totalSupply, uint256 amount, uint256 limit);
36+
error TotalLicenseTokenLimitHook_TotalLicenseTokenLimitExceeded(uint256 totalSupply, uint256 amount, uint256 limit);
37+
38+
/// @notice Emitted when the limit is lower than the existing supply
39+
/// @param totalSupply The total supply of the license tokens
40+
/// @param limit The total license token limit
41+
error TotalLicenseTokenLimitHook_LimitLowerThanTotalSupply(uint256 totalSupply, uint256 limit);
42+
43+
/// @notice Emitted when the license registry is the zero address
44+
error TotalLicenseTokenLimitHook_ZeroLicenseRegistry();
45+
46+
/// @notice Emitted when the license token is the zero address
47+
error TotalLicenseTokenLimitHook_ZeroLicenseToken();
3748

3849
constructor(
3950
address licenseRegistry,
4051
address licenseToken,
4152
address accessController,
4253
address ipAssetRegistry
4354
) AccessControlled(accessController, ipAssetRegistry) {
44-
require(licenseRegistry != address(0), "TotalLicenseTokenLimitHook: licenseRegistry is the zero address");
45-
require(licenseToken != address(0), "TotalLicenseTokenLimitHook: licenseToken is the zero address");
55+
if (licenseRegistry == address(0)) revert TotalLicenseTokenLimitHook_ZeroLicenseRegistry();
56+
if (licenseToken == address(0)) revert TotalLicenseTokenLimitHook_ZeroLicenseToken();
4657
LICENSE_REGISTRY = ILicenseRegistry(licenseRegistry);
4758
LICENSE_TOKEN = ILicenseToken(licenseToken);
4859
}
@@ -59,6 +70,8 @@ contract TotalLicenseTokenLimitHook is BaseModule, AccessControlled, ILicensingH
5970
uint256 limit
6071
) external verifyPermission(licensorIpId) {
6172
bytes32 key = keccak256(abi.encodePacked(licensorIpId, licenseTemplate, licenseTermsId));
73+
uint256 totalSupply = _getTotalSupply(licensorIpId);
74+
if (limit < totalSupply) revert TotalLicenseTokenLimitHook_LimitLowerThanTotalSupply(totalSupply, limit);
6275
totalLicenseTokenLimit[key] = limit;
6376
emit SetTotalLicenseTokenLimit(licensorIpId, licenseTemplate, licenseTermsId, limit);
6477
}
@@ -163,10 +176,9 @@ contract TotalLicenseTokenLimitHook is BaseModule, AccessControlled, ILicensingH
163176
uint256 limit = totalLicenseTokenLimit[key];
164177
if (limit != 0) {
165178
// derivative IPs are also considered as minted license tokens
166-
uint256 totalSupply = LICENSE_REGISTRY.getDerivativeIpCount(licensorIpId) +
167-
LICENSE_TOKEN.getTotalTokensByLicensor(licensorIpId);
179+
uint256 totalSupply = _getTotalSupply(licensorIpId);
168180
if (totalSupply + amount > limit) {
169-
revert TotalLicenseTokenLimitExceeded(totalSupply, amount, limit);
181+
revert TotalLicenseTokenLimitHook_TotalLicenseTokenLimitExceeded(totalSupply, amount, limit);
170182
}
171183
}
172184
}
@@ -179,4 +191,9 @@ contract TotalLicenseTokenLimitHook is BaseModule, AccessControlled, ILicensingH
179191
(, , uint256 mintingFee, ) = ILicenseTemplate(licenseTemplate).getRoyaltyPolicy(licenseTermsId);
180192
return amount * mintingFee;
181193
}
194+
195+
function _getTotalSupply(address licensorIpId) internal view returns (uint256) {
196+
return
197+
LICENSE_REGISTRY.getDerivativeIpCount(licensorIpId) + LICENSE_TOKEN.getTotalTokensByLicensor(licensorIpId);
198+
}
182199
}

test/hooks/TotalLicenseTokenLimitHook.t.sol

+55-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ pragma solidity 0.8.26;
33

44
import { PILFlavors } from "@storyprotocol/core/lib/PILFlavors.sol";
55
import { Licensing } from "@storyprotocol/core/lib/Licensing.sol";
6-
import "@storyprotocol/core/lib/Errors.sol";
76

87
import { TotalLicenseTokenLimitHook } from "contracts/hooks/TotalLicenseTokenLimitHook.sol";
98

@@ -73,12 +72,22 @@ contract TotalLicenseTokenLimitHookTest is BaseTest {
7372
licensingModule.mintLicenseTokens(ipId3, address(pilTemplate), socialRemixTermsId, 10, u.alice, "");
7473

7574
vm.expectRevert(
76-
abi.encodeWithSelector(TotalLicenseTokenLimitHook.TotalLicenseTokenLimitExceeded.selector, 10, 5, 10)
75+
abi.encodeWithSelector(
76+
TotalLicenseTokenLimitHook.TotalLicenseTokenLimitHook_TotalLicenseTokenLimitExceeded.selector,
77+
10,
78+
5,
79+
10
80+
)
7781
);
7882
licensingModule.mintLicenseTokens(ipId1, address(pilTemplate), socialRemixTermsId, 5, u.alice, "");
7983

8084
vm.expectRevert(
81-
abi.encodeWithSelector(TotalLicenseTokenLimitHook.TotalLicenseTokenLimitExceeded.selector, 20, 5, 20)
85+
abi.encodeWithSelector(
86+
TotalLicenseTokenLimitHook.TotalLicenseTokenLimitHook_TotalLicenseTokenLimitExceeded.selector,
87+
20,
88+
5,
89+
20
90+
)
8291
);
8392
licensingModule.mintLicenseTokens(ipId2, address(pilTemplate), socialRemixTermsId, 5, u.alice, "");
8493
}
@@ -108,8 +117,50 @@ contract TotalLicenseTokenLimitHookTest is BaseTest {
108117
vm.stopPrank();
109118

110119
vm.startPrank(ipOwner2);
111-
vm.expectRevert(abi.encodeWithSelector(Errors.AccessController__PermissionDenied.selector, ipId1, ipOwner2, address(totalLimitHook), totalLimitHook.setTotalLicenseTokenLimit.selector));
120+
vm.expectRevert(
121+
abi.encodeWithSelector(
122+
Errors.AccessController__PermissionDenied.selector,
123+
ipId1,
124+
ipOwner2,
125+
address(totalLimitHook),
126+
totalLimitHook.setTotalLicenseTokenLimit.selector
127+
)
128+
);
112129
totalLimitHook.setTotalLicenseTokenLimit(ipId1, address(pilTemplate), socialRemixTermsId, 20);
130+
}
113131

132+
function test_TotalLicenseTokenLimitHook_revert_limitLowerThanTotalSupply_setLimit() public {
133+
uint256 socialRemixTermsId = pilTemplate.registerLicenseTerms(PILFlavors.nonCommercialSocialRemixing());
134+
TotalLicenseTokenLimitHook totalLimitHook = new TotalLicenseTokenLimitHook(
135+
address(licenseRegistry),
136+
address(licenseToken),
137+
address(accessController),
138+
address(ipAssetRegistry)
139+
);
140+
141+
vm.prank(u.admin);
142+
moduleRegistry.registerModule("TotalLicenseTokenLimitHook", address(totalLimitHook));
143+
Licensing.LicensingConfig memory licensingConfig = Licensing.LicensingConfig({
144+
isSet: true,
145+
mintingFee: 100,
146+
licensingHook: address(totalLimitHook),
147+
hookData: ""
148+
});
149+
150+
vm.startPrank(ipOwner1);
151+
licensingModule.setLicensingConfig(ipId1, address(pilTemplate), socialRemixTermsId, licensingConfig);
152+
totalLimitHook.setTotalLicenseTokenLimit(ipId1, address(pilTemplate), socialRemixTermsId, 10);
153+
assertEq(totalLimitHook.getTotalLicenseTokenLimit(ipId1, address(pilTemplate), socialRemixTermsId), 10);
154+
155+
licensingModule.mintLicenseTokens(ipId1, address(pilTemplate), socialRemixTermsId, 10, u.alice, "");
156+
157+
vm.expectRevert(
158+
abi.encodeWithSelector(
159+
TotalLicenseTokenLimitHook.TotalLicenseTokenLimitHook_LimitLowerThanTotalSupply.selector,
160+
10,
161+
5
162+
)
163+
);
164+
totalLimitHook.setTotalLicenseTokenLimit(ipId1, address(pilTemplate), socialRemixTermsId, 5);
114165
}
115166
}

0 commit comments

Comments
 (0)