Skip to content
This repository has been archived by the owner on Apr 30, 2024. It is now read-only.

Commit

Permalink
Fix Caller Parameter in PFM verify (#119)
Browse files Browse the repository at this point in the history
* fix: pass in licensee (license holder) to verify calls in PFM
* test: Commercializer checker test in Integration
* fix: verifyMint caller parameter in license minting
  • Loading branch information
jdubpark authored Feb 18, 2024
1 parent 03b8c2b commit ef6f71c
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ interface IPolicyFrameworkManager is IERC165 {

/// @notice Verify policy parameters for minting a license.
/// @dev Enforced to be only callable by LicenseRegistry
/// @param caller the address executing the mint
/// @param licensee the address that holds the license and is executing the mint
/// @param mintingFromADerivative true if we verify minting a license from a derivative IP ID
/// @param receiver the address receiving the license
/// @param licensorIpId the IP id of the licensor
/// @param mintAmount the amount of licenses to mint
/// @param policyData the encoded framework policy data to verify
/// @return verified True if the link is verified
function verifyMint(
address caller,
address licensee,
bool mintingFromADerivative,
address licensorIpId,
address receiver,
Expand All @@ -56,14 +56,14 @@ interface IPolicyFrameworkManager is IERC165 {
/// @notice Verify policy parameters for linking a child IP to a parent IP (licensor) by burning a license NFT.
/// @dev Enforced to be only callable by LicenseRegistry
/// @param licenseId the license id to burn
/// @param caller the address executing the link
/// @param licensee the address that holds the license and is executing the link
/// @param ipId the IP id of the IP being linked
/// @param parentIpId the IP id of the parent IP
/// @param policyData the encoded framework policy data to verify
/// @return verified True if the link is verified
function verifyLink(
uint256 licenseId,
address caller,
address licensee,
address ipId,
address parentIpId,
bytes calldata policyData
Expand Down
12 changes: 7 additions & 5 deletions contracts/modules/licensing/LicensingModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,9 @@ contract LicensingModule is AccessControlled, ILicensingModule, BaseModule, Reen
}

// If a policy is set, then is only up to the policy params.
// Verify minting param
if (!pfm.verifyMint(msg.sender, isInherited, licensorIpId, receiver, amount, pol.frameworkData)) {
// When verifying mint via PFM, pass in `receiver` as the `licensee` since the receiver is the one who will own
// the license NFT after minting.
if (!pfm.verifyMint(receiver, isInherited, licensorIpId, receiver, amount, pol.frameworkData)) {
revert Errors.LicensingModule__MintLicenseParamFailed();
}

Expand Down Expand Up @@ -298,7 +299,7 @@ contract LicensingModule is AccessControlled, ILicensingModule, BaseModule, Reen
revert Errors.LicensingModule__IncompatibleLicensorCommercialPolicy();
}

_linkIpToParent(i, licenseId, licenseData.policyId, pol, licenseData.licensorIpId, childIpId);
_linkIpToParent(i, licenseId, licenseData.policyId, pol, licenseData.licensorIpId, childIpId, holder);
return (licenseData.licensorIpId, pol.royaltyPolicy, pol.royaltyData);
}

Expand Down Expand Up @@ -485,7 +486,8 @@ contract LicensingModule is AccessControlled, ILicensingModule, BaseModule, Reen
uint256 policyId,
Licensing.Policy memory pol,
address licensor,
address childIpId
address childIpId,
address licensee
) private {
// TODO: check licensor not part of a branch tagged by disputer
if (licensor == childIpId) {
Expand All @@ -495,7 +497,7 @@ contract LicensingModule is AccessControlled, ILicensingModule, BaseModule, Reen
if (
!IPolicyFrameworkManager(pol.policyFramework).verifyLink(
licenseId,
msg.sender,
licensee,
childIpId,
licensor,
pol.frameworkData
Expand Down
12 changes: 6 additions & 6 deletions contracts/modules/licensing/PILPolicyFrameworkManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,14 @@ contract PILPolicyFrameworkManager is
/// @notice Verify policy parameters for linking a child IP to a parent IP (licensor) by burning a license NFT.
/// @dev Enforced to be only callable by LicenseRegistry
/// @param licenseId the license id to burn
/// @param caller the address executing the link
/// @param licensee the address that holds the license and is executing the linking
/// @param ipId the IP id of the IP being linked
/// @param parentIpId the IP id of the parent IP
/// @param policyData the encoded framework policy data to verify
/// @return verified True if the link is verified
function verifyLink(
uint256 licenseId,
address caller,
address licensee,
address ipId,
address parentIpId,
bytes calldata policyData
Expand All @@ -104,7 +104,7 @@ contract PILPolicyFrameworkManager is
if (policy.commercializerChecker != address(0)) {
// No need to check if the commercializerChecker supports the IHookModule interface, as it was checked
// when the policy was registered.
if (!IHookModule(policy.commercializerChecker).verify(caller, policy.commercializerCheckerData)) {
if (!IHookModule(policy.commercializerChecker).verify(licensee, policy.commercializerCheckerData)) {
return false;
}
}
Expand All @@ -113,15 +113,15 @@ contract PILPolicyFrameworkManager is

/// @notice Verify policy parameters for minting a license.
/// @dev Enforced to be only callable by LicenseRegistry
/// @param caller the address executing the mint
/// @param licensee the address that holds the license and is executing the mint
/// @param mintingFromADerivative true if the license is minting from a derivative IPA
/// @param licensorIpId the IP id of the licensor
/// @param receiver the address receiving the license
/// @param mintAmount the amount of licenses to mint
/// @param policyData the encoded framework policy data to verify
/// @return verified True if the link is verified
function verifyMint(
address caller,
address licensee,
bool mintingFromADerivative,
address licensorIpId,
address receiver,
Expand All @@ -138,7 +138,7 @@ contract PILPolicyFrameworkManager is
if (policy.commercializerChecker != address(0)) {
// No need to check if the commercializerChecker supports the IHookModule interface, as it was checked
// when the policy was registered.
if (!IHookModule(policy.commercializerChecker).verify(caller, policy.commercializerCheckerData)) {
if (!IHookModule(policy.commercializerChecker).verify(licensee, policy.commercializerCheckerData)) {
return false;
}
}
Expand Down
58 changes: 48 additions & 10 deletions test/foundry/integration/big-bang/SingleNftCollection.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,16 @@ import { IRoyaltyPolicyLAP } from "../../../../contracts/interfaces/modules/roya

// test
import { BaseIntegration } from "../BaseIntegration.t.sol";
import { MockTokenGatedHook } from "../../mocks/MockTokenGatedHook.sol";
import { MockERC721 } from "../../mocks/token/MockERC721.sol";

contract BigBang_Integration_SingleNftCollection is BaseIntegration {
using EnumerableSet for EnumerableSet.UintSet;

MockTokenGatedHook internal mockTokenGatedHook;

MockERC721 internal mockGatedNft;

mapping(uint256 tokenId => address ipAccount) internal ipAcct;

mapping(string name => uint256 licenseId) internal licenseIds;
Expand All @@ -28,6 +34,9 @@ contract BigBang_Integration_SingleNftCollection is BaseIntegration {
function setUp() public override {
super.setUp();

mockTokenGatedHook = new MockTokenGatedHook();
mockGatedNft = new MockERC721("MockGatedNft");

// Add PIL PFM policies

_setPILPolicyFrameworkManager();
Expand All @@ -42,8 +51,8 @@ contract BigBang_Integration_SingleNftCollection is BaseIntegration {
attribution: false,
commercialUse: true,
commercialAttribution: true,
commercializerChecker: address(0),
commercializerCheckerData: "",
commercializerChecker: address(mockTokenGatedHook),
commercializerCheckerData: abi.encode(address(mockGatedNft)),
commercialRevShare: derivCheapFlexibleRevShare,
derivativesAllowed: true,
derivativesAttribution: true,
Expand Down Expand Up @@ -148,6 +157,10 @@ contract BigBang_Integration_SingleNftCollection is BaseIntegration {
vm.startPrank(u.carl);
mockNFT.mintId(u.carl, 6);

// Carl needs to hold an NFT from mockGatedNFT collection to mint license pil_com_deriv_cheap_flexible
// (verified by the mockTokenGatedHook commercializer checker)
mockGatedNft.mint(u.carl);

mockToken.approve(address(royaltyPolicyLAP), 100 ether);

uint256[] memory carl_license_from_root_alice = new uint256[](1);
Expand Down Expand Up @@ -180,7 +193,11 @@ contract BigBang_Integration_SingleNftCollection is BaseIntegration {
// Carl activates one of the two licenses on his NFT 7 IPAccount, linking as child to Bob's NFT 3 IPAccount
{
vm.startPrank(u.carl);
mockNFT.mintId(u.carl, 7);
mockNFT.mintId(u.carl, 7); // NFT for Carl's IPAccount7

// Carl is minting license on non-commercial policy, so no commercializer checker is involved.
// Thus, no need to mint anything (although Carl already has mockGatedNft from above)

uint256[] memory carl_license_from_root_bob = new uint256[](1);
carl_license_from_root_bob[0] = licensingModule.mintLicense(
policyIds["pil_noncom_deriv_reciprocal_derivative"],
Expand All @@ -190,19 +207,36 @@ contract BigBang_Integration_SingleNftCollection is BaseIntegration {
emptyRoyaltyPolicyLAPInitParams
);

IRoyaltyPolicyLAP.InitParams memory params = IRoyaltyPolicyLAP.InitParams({
IRoyaltyPolicyLAP.InitParams memory royaltyContextRegister = IRoyaltyPolicyLAP.InitParams({
targetAncestors: new address[](1),
targetRoyaltyAmount: new uint32[](1),
parentAncestors1: new address[](0),
parentAncestors2: new address[](0),
parentAncestorsRoyalties1: new uint32[](0),
parentAncestorsRoyalties2: new uint32[](0)
});
params.targetAncestors[0] = ipAcct[3];
params.targetRoyaltyAmount[0] = 0;

ipAcct[7] = registerIpAccount(mockNFT, 7, u.carl);
linkIpToParents(carl_license_from_root_bob, ipAcct[7], u.carl, abi.encode(params));
royaltyContextRegister.targetAncestors[0] = ipAcct[3];
royaltyContextRegister.targetRoyaltyAmount[0] = 0;

// TODO: events check
ipAssetRegistry.register(
carl_license_from_root_bob,
abi.encode(royaltyContextRegister),
block.chainid,
address(mockNFT),
7,
address(ipResolver),
true,
abi.encode(
IP.MetadataV1({
name: "IP NAME",
hash: bytes32("hash"),
registrationDate: uint64(block.timestamp),
registrant: u.carl, // caller
uri: "external URL"
})
)
);
}

// Alice mints 2 license for policy "pil_com_deriv_cheap_flexible" on Bob's NFT 3 IPAccount
Expand All @@ -216,6 +250,10 @@ contract BigBang_Integration_SingleNftCollection is BaseIntegration {

mockToken.approve(address(royaltyPolicyLAP), mintAmount * 100 ether);

// Alice needs to hold an NFT from mockGatedNFT collection to mint license on pil_com_deriv_cheap_flexible
// (verified by the mockTokenGatedHook commercializer checker)
mockGatedNft.mint(u.alice);

uint256[] memory alice_license_from_root_bob = new uint256[](1);
alice_license_from_root_bob[0] = licensingModule.mintLicense(
policyIds["pil_com_deriv_cheap_flexible"],
Expand Down Expand Up @@ -285,7 +323,7 @@ contract BigBang_Integration_SingleNftCollection is BaseIntegration {
});

uint256[] memory carl_licenses = new uint256[](2);
// Commercial license
// Commercial license (Carl already has mockGatedNft from above, so he passes commercializer checker check)
carl_licenses[0] = licensingModule.mintLicense(
policyIds["pil_com_deriv_cheap_flexible"], // ipAcct[1] has this policy attached
ipAcct[1],
Expand Down
7 changes: 7 additions & 0 deletions test/foundry/utils/BaseTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ contract BaseTest is Test, DeployHelper, LicensingHelper {
// NOTE: accessController is IAccessController, which doesn't expose `initialize` function.
AccessController(address(accessController)).initialize(address(ipAccountRegistry), getModuleRegistry());

accessController.setGlobalPermission(
address(ipAssetRegistry),
address(licensingModule),
bytes4(licensingModule.linkIpToParents.selector),
AccessPermission.ALLOW
);

// If REAL Registration Module and Licensing Module are deployed, set global permissions
if (deployConditions.module.registrationModule && deployConditions.module.licensingModule) {
accessController.setGlobalPermission(
Expand Down

0 comments on commit ef6f71c

Please sign in to comment.