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

test: More licensing and UML PFM tests #114

Merged
merged 11 commits into from
Feb 17, 2024
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ abi:
@$(call generate_abi,"DisputeModule","./modules/dispute-module")
@$(call generate_abi,"ArbitrationPolicySP","./modules/dispute-module/policies")
@$(call generate_abi,"LicensingModule","./modules/licensing")
@$(call generate_abi,"UMLPolicyFrameworkManager","./modules/licensing")
@$(call generate_abi,"PILPolicyFrameworkManager","./modules/licensing")
@$(call generate_abi,"RoyaltyModule","./modules/royalty-module")
@$(call generate_abi,"LSClaimer","./modules/royalty-module/policies")
@$(call generate_abi,"RoyaltyPolicyLS","./modules/royalty-module/policies")
Expand Down
10 changes: 5 additions & 5 deletions contracts/lib/PILFrameworkErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ library PILFrameworkErrors {
// PILPolicyFrameworkManager //
////////////////////////////////////////////////////////////////////////////

error PILPolicyFrameworkManager__CommecialDisabled_CantAddAttribution();
error PILPolicyFrameworkManager__CommercialDisabled_CantAddAttribution();
error PILPolicyFrameworkManager__CommercialDisabled_CantAddCommercializers();
error PILPolicyFrameworkManager__CommecialDisabled_CantAddRevShare();
error PILPolicyFrameworkManager__CommercialDisabled_CantAddRevShare();
error PILPolicyFrameworkManager__DerivativesDisabled_CantAddAttribution();
error PILPolicyFrameworkManager__DerivativesDisabled_CantAddApproval();
error PILPolicyFrameworkManager__DerivativesDisabled_CantAddReciprocal();
error PILPolicyFrameworkManager__RightsNotFound();
error PILPolicyFrameworkManager__CommercialDisabled_CantAddRoyaltyPolicy();
error PILPolicyFrameworkManager__CommecialEnabled_RoyaltyPolicyRequired();
error PILPolicyFrameworkManager__CommercialEnabled_RoyaltyPolicyRequired();
error PILPolicyFrameworkManager__ReciprocalButDifferentPolicyIds();
error PILPolicyFrameworkManager__ReciprocalValueMismatch();
error PILPolicyFrameworkManager__CommercialValueMismatch();
error PILPolicyFrameworkManager__StringArrayMismatch();
error PILPolicyFrameworkManager__CommecialDisabled_CantAddMintingFee();
error PILPolicyFrameworkManager__CommecialDisabled_CantAddMintingFeeToken();
error PILPolicyFrameworkManager__CommercialDisabled_CantAddMintingFee();
error PILPolicyFrameworkManager__CommercialDisabled_CantAddMintingFeeToken();
}
17 changes: 15 additions & 2 deletions contracts/modules/licensing/LicensingModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,25 @@ contract LicensingModule is AccessControlled, ILicensingModule, BaseModule, Reen
revert Errors.LicensingModule__CallerNotLicensorAndPolicyNotSet();
}
}
// If the policy has a royalty policy, we need to call the royalty module to process the minting

// If the policy has a royalty policy, we need to call the royalty module to process the minting.
// Otherwise, it's non commercial and we can skip the call.
// NOTE: We must call `payLicenseMintingFee` after calling `onLicenseMinting` because minting licenses on
// root IPs (licensors) might mean the licensors don't have royalty policy initialized, so we initialize it
// (deploy the split clone contract) via `onLicenseMinting`. Then, pay the minting fee to the licensor's split
// clone contract address.
if (pol.royaltyPolicy != address(0)) {
ROYALTY_MODULE.onLicenseMinting(licensorIpId, pol.royaltyPolicy, pol.royaltyData, royaltyContext);
LeoHChen marked this conversation as resolved.
Show resolved Hide resolved

// If there's a minting fee, sender must pay it
if (pol.mintingFee > 0) {
ROYALTY_MODULE.payLicenseMintingFee(licensorIpId, msg.sender, pol.royaltyPolicy, pol.mintingFeeToken, pol.mintingFee);
ROYALTY_MODULE.payLicenseMintingFee(
jdubpark marked this conversation as resolved.
Show resolved Hide resolved
licensorIpId,
msg.sender,
pol.royaltyPolicy,
pol.mintingFeeToken,
pol.mintingFee
);
}
}

Expand Down
18 changes: 11 additions & 7 deletions contracts/modules/licensing/PILPolicyFrameworkManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.s
// contracts
import { IHookModule } from "../../interfaces/modules/base/IHookModule.sol";
import { ILicensingModule } from "../../interfaces/modules/licensing/ILicensingModule.sol";
import { IRoyaltyModule } from "../../interfaces/modules/royalty/IRoyaltyModule.sol";
import { Licensing } from "../../lib/Licensing.sol";
import { Errors } from "../../lib/Errors.sol";
import { PILFrameworkErrors } from "../../lib/PILFrameworkErrors.sol";
Expand Down Expand Up @@ -354,29 +353,34 @@ contract PILPolicyFrameworkManager is
/// @param policy The policy to verify
/// @param royaltyPolicy The address of the royalty policy
// solhint-disable-next-line code-complexity
function _verifyComercialUse(PILPolicy calldata policy, address royaltyPolicy, uint256 mintingFee, address mintingFeeToken) internal view {
function _verifyComercialUse(
PILPolicy calldata policy,
address royaltyPolicy,
uint256 mintingFee,
address mintingFeeToken
) internal view {
if (!policy.commercialUse) {
if (policy.commercialAttribution) {
revert PILFrameworkErrors.PILPolicyFrameworkManager__CommecialDisabled_CantAddAttribution();
revert PILFrameworkErrors.PILPolicyFrameworkManager__CommercialDisabled_CantAddAttribution();
}
if (policy.commercializerChecker != address(0)) {
revert PILFrameworkErrors.PILPolicyFrameworkManager__CommercialDisabled_CantAddCommercializers();
}
if (policy.commercialRevShare > 0) {
revert PILFrameworkErrors.PILPolicyFrameworkManager__CommecialDisabled_CantAddRevShare();
revert PILFrameworkErrors.PILPolicyFrameworkManager__CommercialDisabled_CantAddRevShare();
}
if (royaltyPolicy != address(0)) {
revert PILFrameworkErrors.PILPolicyFrameworkManager__CommercialDisabled_CantAddRoyaltyPolicy();
}
if (mintingFee > 0) {
revert PILFrameworkErrors.PILPolicyFrameworkManager__CommecialDisabled_CantAddMintingFee();
revert PILFrameworkErrors.PILPolicyFrameworkManager__CommercialDisabled_CantAddMintingFee();
}
if (mintingFeeToken != address(0)) {
revert PILFrameworkErrors.PILPolicyFrameworkManager__CommecialDisabled_CantAddMintingFeeToken();
revert PILFrameworkErrors.PILPolicyFrameworkManager__CommercialDisabled_CantAddMintingFeeToken();
}
} else {
if (royaltyPolicy == address(0)) {
revert PILFrameworkErrors.PILPolicyFrameworkManager__CommecialEnabled_RoyaltyPolicyRequired();
revert PILFrameworkErrors.PILPolicyFrameworkManager__CommercialEnabled_RoyaltyPolicyRequired();
}
if (policy.commercializerChecker != address(0)) {
if (!policy.commercializerChecker.supportsInterface(type(IHookModule).interfaceId)) {
Expand Down
1 change: 0 additions & 1 deletion contracts/modules/royalty-module/RoyaltyModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -183,5 +183,4 @@ contract RoyaltyModule is IRoyaltyModule, Governable, ReentrancyGuard, BaseModul
function supportsInterface(bytes4 interfaceId) public view virtual override(BaseModule, IERC165) returns (bool) {
return interfaceId == type(IRoyaltyModule).interfaceId || super.supportsInterface(interfaceId);
}

}
71 changes: 29 additions & 42 deletions test/foundry/AccessController.t.sol
Original file line number Diff line number Diff line change
@@ -1,48 +1,31 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import { Test } from "forge-std/Test.sol";

import { ERC6551Registry } from "erc6551/ERC6551Registry.sol";

import { AccessController } from "contracts/AccessController.sol";
import { IIPAccount } from "contracts/interfaces/IIPAccount.sol";
import { IModuleRegistry } from "contracts/interfaces/registries/IModuleRegistry.sol";
import { IPAccountImpl } from "contracts/IPAccountImpl.sol";
import { AccessPermission } from "contracts/lib/AccessPermission.sol";
import { Errors } from "contracts/lib/Errors.sol";
import { IPAccountRegistry } from "contracts/registries/IPAccountRegistry.sol";
import { ModuleRegistry } from "contracts/registries/ModuleRegistry.sol";
import { MockERC721 } from "test/foundry/mocks/token/MockERC721.sol";
import { MockModule } from "test/foundry/mocks/module/MockModule.sol";
import { MockOrchestratorModule } from "test/foundry/mocks/module/MockOrchestratorModule.sol";
import { Governance } from "contracts/governance/Governance.sol";

contract AccessControllerTest is Test {
AccessController public accessController;
IPAccountRegistry public ipAccountRegistry;
IModuleRegistry public moduleRegistry;
IPAccountImpl public implementation;
MockERC721 public nft = new MockERC721("MockERC721");
import { IIPAccount } from "../../contracts/interfaces/IIPAccount.sol";
import { AccessPermission } from "../../contracts/lib/AccessPermission.sol";
import { Errors } from "../../contracts/lib/Errors.sol";

import { MockModule } from "./mocks/module/MockModule.sol";
import { MockOrchestratorModule } from "./mocks/module/MockOrchestratorModule.sol";
import { BaseTest } from "./utils/BaseTest.t.sol";

contract AccessControllerTest is BaseTest {
MockModule public mockModule;
MockModule public moduleWithoutPermission;
IIPAccount public ipAccount;
ERC6551Registry public erc6551Registry = new ERC6551Registry();
address public owner = vm.addr(1);
uint256 public tokenId = 100;
Governance public governance;

error ERC721NonexistentToken(uint256 tokenId);

function setUp() public {
governance = new Governance(address(this));
accessController = new AccessController(address(governance));
implementation = new IPAccountImpl(address(accessController));
ipAccountRegistry = new IPAccountRegistry(address(erc6551Registry), address(implementation));
moduleRegistry = new ModuleRegistry(address(governance));
accessController.initialize(address(ipAccountRegistry), address(moduleRegistry));
nft.mintId(owner, tokenId);
address deployedAccount = ipAccountRegistry.registerIpAccount(block.chainid, address(nft), tokenId);
function setUp() public override {
super.setUp();
buildDeployAccessCondition(DeployAccessCondition({ accessController: true, governance: true }));
deployConditionally();
postDeploymentSetup();

mockNFT.mintId(owner, tokenId);
address deployedAccount = ipAccountRegistry.registerIpAccount(block.chainid, address(mockNFT), tokenId);
ipAccount = IIPAccount(payable(deployedAccount));

mockModule = new MockModule(address(ipAccountRegistry), address(moduleRegistry), "MockModule");
Expand Down Expand Up @@ -908,13 +891,15 @@ contract AccessControllerTest is Test {
);
moduleRegistry.registerModule("Module2WithPermission", address(module2WithPermission));

vm.prank(u.admin);
accessController.setGlobalPermission(
address(mockOrchestratorModule),
address(module1WithPermission),
mockModule.executeSuccessfully.selector,
AccessPermission.ALLOW
);

vm.prank(u.admin);
accessController.setGlobalPermission(
address(mockOrchestratorModule),
address(module2WithPermission),
Expand All @@ -927,6 +912,7 @@ contract AccessControllerTest is Test {
}

function test_AccessController_revert_setGlobalPermissionWithInvalidPermission() public {
vm.prank(u.admin);
vm.expectRevert(Errors.AccessController__PermissionIsNotValid.selector);
accessController.setGlobalPermission(
address(mockModule),
Expand All @@ -937,6 +923,7 @@ contract AccessControllerTest is Test {
}

function test_AccessController_revert_setGlobalPermissionWithZeroSignerAddress() public {
vm.prank(u.admin);
vm.expectRevert(abi.encodeWithSelector(Errors.AccessController__SignerIsZeroAddress.selector));
accessController.setGlobalPermission(
address(0),
Expand Down Expand Up @@ -1292,7 +1279,7 @@ contract AccessControllerTest is Test {
AccessPermission.ALLOW
);
vm.prank(owner);
nft.transferFrom(owner, address(0xbeefbeef), tokenId);
mockNFT.transferFrom(owner, address(0xbeefbeef), tokenId);
assertEq(
accessController.getPermission(
address(ipAccount),
Expand Down Expand Up @@ -1328,7 +1315,7 @@ contract AccessControllerTest is Test {
mockModule.executeSuccessfully.selector
);
vm.prank(owner);
nft.transferFrom(owner, address(0xbeefbeef), tokenId);
mockNFT.transferFrom(owner, address(0xbeefbeef), tokenId);

vm.expectRevert(
abi.encodeWithSelector(
Expand Down Expand Up @@ -1374,7 +1361,7 @@ contract AccessControllerTest is Test {
AccessPermission.ALLOW
);
vm.prank(owner);
nft.transferFrom(owner, address(0xbeefbeef), tokenId);
mockNFT.transferFrom(owner, address(0xbeefbeef), tokenId);

assertEq(
accessController.getPermission(
Expand All @@ -1387,7 +1374,7 @@ contract AccessControllerTest is Test {
);

vm.prank(address(0xbeefbeef));
nft.transferFrom(address(0xbeefbeef), owner, tokenId);
mockNFT.transferFrom(address(0xbeefbeef), owner, tokenId);

assertEq(
accessController.getPermission(
Expand Down Expand Up @@ -1424,7 +1411,7 @@ contract AccessControllerTest is Test {
mockModule.executeSuccessfully.selector
);
vm.prank(owner);
nft.transferFrom(owner, address(0xbeefbeef), tokenId);
mockNFT.transferFrom(owner, address(0xbeefbeef), tokenId);

vm.expectRevert(
abi.encodeWithSelector(
Expand All @@ -1443,7 +1430,7 @@ contract AccessControllerTest is Test {
);

vm.prank(address(0xbeefbeef));
nft.transferFrom(address(0xbeefbeef), owner, tokenId);
mockNFT.transferFrom(address(0xbeefbeef), owner, tokenId);

accessController.checkPermission(
address(ipAccount),
Expand Down Expand Up @@ -1480,7 +1467,7 @@ contract AccessControllerTest is Test {
AccessPermission.ALLOW
);
vm.prank(owner);
nft.burn(tokenId);
mockNFT.burn(tokenId);
vm.expectRevert(abi.encodeWithSelector(ERC721NonexistentToken.selector, tokenId));
accessController.getPermission(
address(ipAccount),
Expand Down Expand Up @@ -1514,7 +1501,7 @@ contract AccessControllerTest is Test {
mockModule.executeSuccessfully.selector
);
vm.prank(owner);
nft.burn(tokenId);
mockNFT.burn(tokenId);

vm.expectRevert(abi.encodeWithSelector(ERC721NonexistentToken.selector, tokenId));
accessController.checkPermission(
Expand Down
Loading
Loading