From 6aab6ebfc02855438e7762cb62b9b7b951602a8c Mon Sep 17 00:00:00 2001 From: Kingster Date: Wed, 14 Aug 2024 07:48:09 -0700 Subject: [PATCH 1/6] init implementation --- script/foundry/utils/DeployHelper.sol | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/script/foundry/utils/DeployHelper.sol b/script/foundry/utils/DeployHelper.sol index 48222ba1..3af6bf63 100644 --- a/script/foundry/utils/DeployHelper.sol +++ b/script/foundry/utils/DeployHelper.sol @@ -43,6 +43,7 @@ import { CoreMetadataModule } from "contracts/modules/metadata/CoreMetadataModul import { CoreMetadataViewModule } from "contracts/modules/metadata/CoreMetadataViewModule.sol"; import { PILicenseTemplate, PILTerms } from "contracts/modules/licensing/PILicenseTemplate.sol"; import { LicenseToken } from "contracts/LicenseToken.sol"; +import { PILFlavors } from "contracts/lib/PILFlavors.sol"; // script import { StringUtil } from "./StringUtil.sol"; @@ -596,6 +597,10 @@ contract DeployHelper is Script, BroadcastManager, JsonDeploymentHandler, Storag // License Template licenseRegistry.registerLicenseTemplate(address(pilTemplate)); + + // set default license to non-commercial social remixing + uint256 licenseId = pilTemplate.registerLicenseTerms(PILFlavors.nonCommercialSocialRemixing()); + licenseRegistry.setDefaultLicenseTerms(address(pilTemplate), licenseId); } function _configureRoles() private { From 2f0c6303775eb1fbd173a86a52b46bf6d5e79950 Mon Sep 17 00:00:00 2001 From: Kingster Date: Sat, 24 Aug 2024 23:19:04 -0700 Subject: [PATCH 2/6] Add IPGraphACL contract --- contracts/access/IPGraphACL.sol | 49 ++++++++ script/foundry/deployment/ACL.s.sol | 141 ++++++++++++++++++++++++ script/foundry/deployment/TestACL.s.sol | 104 +++++++++++++++++ script/foundry/utils/DeployHelper.sol | 19 ++++ 4 files changed, 313 insertions(+) create mode 100644 contracts/access/IPGraphACL.sol create mode 100644 script/foundry/deployment/ACL.s.sol create mode 100644 script/foundry/deployment/TestACL.s.sol diff --git a/contracts/access/IPGraphACL.sol b/contracts/access/IPGraphACL.sol new file mode 100644 index 00000000..c0574f7f --- /dev/null +++ b/contracts/access/IPGraphACL.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.23; + +contract IPGraphACL { + uint256 public length = 0; + + function addWhitelistAddress(address addr) external { + length++; + uint256 slot = length; + assembly { + sstore(slot, addr) + } + } + + function revokeWhitelistAddress(uint256 index) external { + require(index > 0 && index <= length, "IPGraphACL: index out of bounds"); + uint256 slot = index; + assembly { + sstore(slot, 0) + } + } + + function getWhitelistAddress(uint256 index) external view returns (address) { + require(index <= length, "IPGraphACL: index out of bounds"); + address addr; + uint256 slot = index + 1; + assembly { + addr := sload(slot) + } + return addr; + } + + function getWhitelistLength() external view returns (uint256) { + return length; + } + + function isWhitelisted(address addr) external view returns (bool) { + for (uint256 i = 1; i <= length; i++) { + address whitelistAddr; + assembly { + whitelistAddr := sload(i) + } + if (whitelistAddr == addr) { + return true; + } + } + return false; + } +} diff --git a/script/foundry/deployment/ACL.s.sol b/script/foundry/deployment/ACL.s.sol new file mode 100644 index 00000000..5b6bea1e --- /dev/null +++ b/script/foundry/deployment/ACL.s.sol @@ -0,0 +1,141 @@ +/* solhint-disable no-console */ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { console2 } from "forge-std/console2.sol"; + +import { Script, stdJson } from "forge-std/Script.sol"; +import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; +import { PILFlavors } from "contracts/lib/PILFlavors.sol"; +import { PILicenseTemplate, PILTerms } from "contracts/modules/licensing/PILicenseTemplate.sol"; +import { LicenseRegistry } from "contracts/registries/LicenseRegistry.sol"; +import { ICreate3Deployer } from "@create3-deployer/contracts/ICreate3Deployer.sol"; + +import "test/foundry/mocks/token/MockERC721.sol"; + +contract StoryACL { + uint256 public length; + + function addWhitelistAddress(address addr) external { + uint256 slot = length++; + assembly { + sstore(slot, addr) + } + } + + function getWhitelistAddress(uint256 index) external view returns (address) { + address addr; + uint256 slot = index + 1; + assembly { + addr := sload(slot) + } + return addr; + } + + function getWhitelistLength() external view returns (uint256) { + return length; + } + + function revokeWhitelistAddress(uint256 index) external { + assembly { + sstore(index, 0) + } + } + + // is whitelisted + function isWhitelisted(address addr) external view returns (bool) { + for (uint256 i = 1; i <= length; i++) { + address whitelistAddr; + assembly { + whitelistAddr := sload(i) + } + if (whitelistAddr == addr) { + return true; + } + } + return false; + } +} + +contract DeployStoryACL is Script { + using stdJson for string; + address internal CREATE3_DEPLOYER = 0x384a891dFDE8180b054f04D66379f16B7a678Ad6; + + address public multisig; + address public deployer; + ICreate3Deployer create3Deployer; + address internal protocolAccessManagerAddr; + address internal ipAssetRegistryAddr; + address internal licensingModuleAddr; + address internal licenseRegistryAddr; + address internal royaltyModuleAddr; + address internal coreMetadataModuleAddr; + address internal accessControllerAddr; + address internal pilTemplateAddr; + address internal licenseTokenAddr; + + function run() public { + uint256 deployerPrivateKey; + _readStoryProtocolCoreAddresses(); + console2.log("Deploying StoryACL"); + console2.log("licenseRegistryAddr:", licenseRegistryAddr); + console2.log("royaltyModuleAddr:", royaltyModuleAddr); + console2.log("licensingModuleAddr:", licensingModuleAddr); + + deployerPrivateKey = vm.envUint("STORY_PRIVATEKEY"); + deployer = vm.envAddress("STORY_DEPLOYER_ADDRESS"); + multisig = vm.envAddress("STORY_MULTISIG_ADDRESS"); + + create3Deployer = ICreate3Deployer(CREATE3_DEPLOYER); + address[] memory whitelist = new address[](3); + whitelist[0] = licenseRegistryAddr; + whitelist[1] = royaltyModuleAddr; + whitelist[2] = licensingModuleAddr; + + vm.startBroadcast(deployerPrivateKey); + string memory contractKey = "StoryAcl"; + // uint256 seed = 1000; + _predeploy(contractKey); + StoryACL storyAcl = StoryACL( + create3Deployer.deploy( + keccak256(abi.encode("TheStoryPrecompileACL")), + abi.encodePacked( + type(StoryACL).creationCode, + abi.encode(licenseRegistryAddr), + abi.encode(royaltyModuleAddr), + abi.encode(licensingModuleAddr) + ) + ) + ); + _postdeploy(contractKey, address(storyAcl)); + + vm.stopBroadcast(); + + } + + function _readStoryProtocolCoreAddresses() internal { + string memory root = vm.projectRoot(); + string memory path = string.concat( + root, + string(abi.encodePacked("/deploy-out/deployment-", Strings.toString(block.chainid), ".json")) + ); + string memory json = vm.readFile(path); + protocolAccessManagerAddr = json.readAddress(".main.ProtocolAccessManager"); + ipAssetRegistryAddr = json.readAddress(".main.IPAssetRegistry"); + licensingModuleAddr = json.readAddress(".main.LicensingModule"); + licenseRegistryAddr = json.readAddress(".main.LicenseRegistry"); + royaltyModuleAddr = json.readAddress(".main.RoyaltyModule"); + coreMetadataModuleAddr = json.readAddress(".main.CoreMetadataModule"); + accessControllerAddr = json.readAddress(".main.AccessController"); + pilTemplateAddr = json.readAddress(".main.PILicenseTemplate"); + licenseTokenAddr = json.readAddress(".main.LicenseToken"); + } + + function _predeploy(string memory contractKey) private view { + console2.log(string.concat("Deploying ", contractKey, "...")); + } + + function _postdeploy(string memory contractKey, address newAddress) private { + console2.log(string.concat(contractKey, " deployed to:"), newAddress); + } +} diff --git a/script/foundry/deployment/TestACL.s.sol b/script/foundry/deployment/TestACL.s.sol new file mode 100644 index 00000000..6d819f64 --- /dev/null +++ b/script/foundry/deployment/TestACL.s.sol @@ -0,0 +1,104 @@ +/* solhint-disable no-console */ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { console2 } from "forge-std/console2.sol"; + +import { Script, stdJson } from "forge-std/Script.sol"; +import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; +import { PILFlavors } from "contracts/lib/PILFlavors.sol"; +import { PILicenseTemplate, PILTerms } from "contracts/modules/licensing/PILicenseTemplate.sol"; +import { LicenseRegistry } from "contracts/registries/LicenseRegistry.sol"; +import { ICreate3Deployer } from "@create3-deployer/contracts/ICreate3Deployer.sol"; +import "test/foundry/mocks/token/MockERC721.sol"; +import { IPAssetRegistry } from "contracts/registries/IPAssetRegistry.sol"; +import { LicensingModule } from "contracts/modules/licensing/LicensingModule.sol"; +import "test/foundry/mocks/MockIPGraph.sol"; + +import "test/foundry/mocks/token/MockERC721.sol"; + +contract TestACL is Script { + using stdJson for string; + address internal CREATE3_DEPLOYER = 0x384a891dFDE8180b054f04D66379f16B7a678Ad6; + + address public multisig; + address public deployer; + ICreate3Deployer create3Deployer; + address internal protocolAccessManagerAddr; + address internal ipAssetRegistryAddr; + address internal licensingModuleAddr; + address internal licenseRegistryAddr; + address internal royaltyModuleAddr; + address internal coreMetadataModuleAddr; + address internal accessControllerAddr; + address internal pilTemplateAddr; + address internal licenseTokenAddr; + + function run() public { + vm.etch(address(0x1A), address(new MockIPGraph()).code); + uint256 deployerPrivateKey; + _readStoryProtocolCoreAddresses(); + console2.log("Testing StoryACL"); + console2.log("licenseRegistryAddr:", licenseRegistryAddr); + console2.log("royaltyModuleAddr:", royaltyModuleAddr); + console2.log("licensingModuleAddr:", licensingModuleAddr); + + deployerPrivateKey = vm.envUint("STORY_PRIVATEKEY"); + deployer = vm.envAddress("STORY_DEPLOYER_ADDRESS"); + multisig = vm.envAddress("STORY_MULTISIG_ADDRESS"); + + + vm.startBroadcast(deployerPrivateKey); + MockERC721 mockERC721 = new MockERC721("MockERC721"); + uint256 tokenId1 = mockERC721.mint(deployer); + console2.log("Minted tokenId:", tokenId1); + uint256 tokenId2 = mockERC721.mint(deployer); + console2.log("Minted tokenId:", tokenId2); + uint256 tokenId3 = mockERC721.mint(deployer); + console2.log("Minted tokenId:", tokenId3); + + address ipId1 = IPAssetRegistry(ipAssetRegistryAddr).register(block.chainid, address(mockERC721), tokenId1); + address ipId2 = IPAssetRegistry(ipAssetRegistryAddr).register(block.chainid, address(mockERC721), tokenId2); + address ipId3 = IPAssetRegistry(ipAssetRegistryAddr).register(block.chainid, address(mockERC721), tokenId3); + console2.log("Registered IP:", ipId1); + console2.log("Registered IP:", ipId2); + console2.log("Registered IP:", ipId3); + + + address[] memory parents = new address[](1); + parents[0] = ipId1; + uint256[] memory licenseTermsIds = new uint256[](1); + licenseTermsIds[0] = 1; + LicensingModule(licensingModuleAddr).registerDerivative(ipId2, parents, licenseTermsIds, pilTemplateAddr, ""); + console2.log("Registered Derivative:", ipId2); + + + vm.stopBroadcast(); + } + + function _readStoryProtocolCoreAddresses() internal { + string memory root = vm.projectRoot(); + string memory path = string.concat( + root, + string(abi.encodePacked("/deploy-out/deployment-", Strings.toString(block.chainid), ".json")) + ); + string memory json = vm.readFile(path); + protocolAccessManagerAddr = json.readAddress(".main.ProtocolAccessManager"); + ipAssetRegistryAddr = json.readAddress(".main.IPAssetRegistry"); + licensingModuleAddr = json.readAddress(".main.LicensingModule"); + licenseRegistryAddr = json.readAddress(".main.LicenseRegistry"); + royaltyModuleAddr = json.readAddress(".main.RoyaltyModule"); + coreMetadataModuleAddr = json.readAddress(".main.CoreMetadataModule"); + accessControllerAddr = json.readAddress(".main.AccessController"); + pilTemplateAddr = json.readAddress(".main.PILicenseTemplate"); + licenseTokenAddr = json.readAddress(".main.LicenseToken"); + } + + function _predeploy(string memory contractKey) private view { + console2.log(string.concat("Deploying ", contractKey, "...")); + } + + function _postdeploy(string memory contractKey, address newAddress) private { + console2.log(string.concat(contractKey, " deployed to:"), newAddress); + } +} diff --git a/script/foundry/utils/DeployHelper.sol b/script/foundry/utils/DeployHelper.sol index 3af6bf63..a2261318 100644 --- a/script/foundry/utils/DeployHelper.sol +++ b/script/foundry/utils/DeployHelper.sol @@ -44,6 +44,7 @@ import { CoreMetadataViewModule } from "contracts/modules/metadata/CoreMetadataV import { PILicenseTemplate, PILTerms } from "contracts/modules/licensing/PILicenseTemplate.sol"; import { LicenseToken } from "contracts/LicenseToken.sol"; import { PILFlavors } from "contracts/lib/PILFlavors.sol"; +import { IPGraphACL } from "contracts/access/IPGraphACL.sol"; // script import { StringUtil } from "./StringUtil.sol"; @@ -93,6 +94,7 @@ contract DeployHelper is Script, BroadcastManager, JsonDeploymentHandler, Storag // Access Control AccessManager internal protocolAccessManager; // protocol roles AccessController internal accessController; // per IPA roles + IPGraphACL internal ipGraphACL; // Pause ProtocolPauseAdmin internal protocolPauser; @@ -133,6 +135,8 @@ contract DeployHelper is Script, BroadcastManager, JsonDeploymentHandler, Storag if (block.chainid == 1) erc20 = ERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); else if (block.chainid == 11155111) erc20 = ERC20(0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238); else if (block.chainid == 1513) erc20 = ERC20(0xDE51BB12D5cef80ff2334fe1019089363F80b46e); + else if (block.chainid == 1337) erc20 = ERC20(0xDE51BB12D5cef80ff2334fe1019089363F80b46e); + else revert("Unsupported chain"); } /// @dev To use, run the following command (e.g. for Sepolia): @@ -547,6 +551,17 @@ contract DeployHelper is Script, BroadcastManager, JsonDeploymentHandler, Storag ); _postdeploy("CoreMetadataViewModule", address(coreMetadataViewModule)); + _predeploy("IPGraphACL"); + ipGraphACL = IPGraphACL( + create3Deployer.deploy( + _getSalt(type(IPGraphACL).name), + abi.encodePacked( + type(IPGraphACL).creationCode, + abi.encode(address(protocolAccessManager)) + ) + ) + ); + _postdeploy("IPGraphACL", address(ipGraphACL)); } function _predeploy(string memory contractKey) private view { @@ -601,6 +616,10 @@ contract DeployHelper is Script, BroadcastManager, JsonDeploymentHandler, Storag // set default license to non-commercial social remixing uint256 licenseId = pilTemplate.registerLicenseTerms(PILFlavors.nonCommercialSocialRemixing()); licenseRegistry.setDefaultLicenseTerms(address(pilTemplate), licenseId); + + // IPGraphACL + ipGraphACL.addWhitelistAddress(address(licenseRegistry)); + ipGraphACL.addWhitelistAddress(address(royaltyPolicyLAP)); } function _configureRoles() private { From 4abcb64d5b16fa86613b950f6cd31401a1338ebb Mon Sep 17 00:00:00 2001 From: Kingster Date: Sun, 25 Aug 2024 17:39:24 -0700 Subject: [PATCH 3/6] Implement IPGraphACL to hold a control flag --- contracts/access/IPGraphACL.sol | 85 +++++++++++++------ contracts/lib/Errors.sol | 10 +++ .../royalty/policies/RoyaltyPolicyLAP.sol | 13 ++- contracts/registries/LicenseRegistry.sol | 10 ++- script/foundry/deployment/TestACL.s.sol | 6 +- script/foundry/utils/DeployHelper.sol | 14 +-- test/foundry/access/IPGraphACL.t.sol | 62 ++++++++++++++ .../mocks/module/LicenseRegistryHarness.sol | 2 +- .../modules/royalty/RoyaltyModule.t.sol | 6 +- test/foundry/utils/BaseTest.t.sol | 6 +- 10 files changed, 175 insertions(+), 39 deletions(-) create mode 100644 test/foundry/access/IPGraphACL.t.sol diff --git a/contracts/access/IPGraphACL.sol b/contracts/access/IPGraphACL.sol index c0574f7f..6758e81d 100644 --- a/contracts/access/IPGraphACL.sol +++ b/contracts/access/IPGraphACL.sol @@ -1,49 +1,78 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; -contract IPGraphACL { - uint256 public length = 0; +import { AccessManaged } from "@openzeppelin/contracts/access/manager/AccessManaged.sol"; +import { Errors } from "../lib/Errors.sol"; + +/// @title IPGraphACL +/// @notice This contract is used to manage access to the IPGraph contract. +/// It allows the access manager to whitelist addresses that can allow or disallow access to the IPGraph contract. +/// It allows whitelisted addresses to allow or disallow access to the IPGraph contract. +/// IPGraph precompiled check if the IPGraphACL contract allows access to the IPGraph. +contract IPGraphACL is AccessManaged { + // keccak256(abi.encode(uint256(keccak256("story-protocol.IPGraphACL")) - 1)) & ~bytes32(uint256(0xff)); + bytes32 private constant IP_GRAPH_ACL_SLOT = + 0xaf99b37fdaacca72ee7240cb1435cc9e498aee6ef4edc19c8cc0cd787f4e6800; + + /// @notice Whitelisted addresses that can allow or disallow access to the IPGraph contract. + mapping(address => bool) public whitelist; + + modifier onlyWhitelisted() { + if (!whitelist[msg.sender]) { + revert Errors.IPGraphACL__NotWhitelisted(msg.sender); + } + _; + } + + constructor(address accessManager) AccessManaged(accessManager) {} + + /// @notice Allow access to the IPGraph contract. + function allow() external onlyWhitelisted { + bytes32 slot = IP_GRAPH_ACL_SLOT; + bool value = true; - function addWhitelistAddress(address addr) external { - length++; - uint256 slot = length; assembly { - sstore(slot, addr) + sstore(slot, value) } } - function revokeWhitelistAddress(uint256 index) external { - require(index > 0 && index <= length, "IPGraphACL: index out of bounds"); - uint256 slot = index; + /// @notice Disallow access to the IPGraph contract. + function disallow() external onlyWhitelisted { + bytes32 slot = IP_GRAPH_ACL_SLOT; + bool value = false; + assembly { - sstore(slot, 0) + sstore(slot, value) } } - function getWhitelistAddress(uint256 index) external view returns (address) { - require(index <= length, "IPGraphACL: index out of bounds"); - address addr; - uint256 slot = index + 1; + /// @notice Check if access to the IPGraph contract is allowed. + function isAllowed() external view returns (bool) { + bytes32 slot = IP_GRAPH_ACL_SLOT; + bool value; + assembly { - addr := sload(slot) + value := sload(slot) } - return addr; + + return value; } - function getWhitelistLength() external view returns (uint256) { - return length; + /// @notice Whitelist an address that can allow or disallow access to the IPGraph contract. + /// @param addr The address to whitelist. + function whitelistAddress(address addr) external restricted { + whitelist[addr] = true; } + /// @notice Revoke whitelisted address. + /// @param addr The address to revoke. + function revokeWhitelistedAddress(address addr) external restricted { + whitelist[addr] = false; + } + + /// @notice Check if an address is whitelisted. + /// @param addr The address to check. function isWhitelisted(address addr) external view returns (bool) { - for (uint256 i = 1; i <= length; i++) { - address whitelistAddr; - assembly { - whitelistAddr := sload(i) - } - if (whitelistAddr == addr) { - return true; - } - } - return false; + return whitelist[addr]; } } diff --git a/contracts/lib/Errors.sol b/contracts/lib/Errors.sol index f8cd636b..0c5c6087 100644 --- a/contracts/lib/Errors.sol +++ b/contracts/lib/Errors.sol @@ -416,6 +416,9 @@ library Errors { /// @notice Zero address provided for Licensing Module. error RoyaltyPolicyLAP__ZeroLicensingModule(); + /// @notice Zero address provided for IP Graph ACL. + error RoyaltyPolicyLAP__ZeroIPGraphACL(); + /// @notice Caller is not the Royalty Module. error RoyaltyPolicyLAP__NotRoyaltyModule(); @@ -583,4 +586,11 @@ library Errors { /// @notice Removing a contract that is not in the pausable list. error ProtocolPauseAdmin__PausableNotFound(); + + //////////////////////////////////////////////////////////////////////////// + // IPGraphACL // + //////////////////////////////////////////////////////////////////////////// + + /// @notice The address is not whitelisted. + error IPGraphACL__NotWhitelisted(address addr); } diff --git a/contracts/modules/royalty/policies/RoyaltyPolicyLAP.sol b/contracts/modules/royalty/policies/RoyaltyPolicyLAP.sol index 735ff0a3..04acc67c 100644 --- a/contracts/modules/royalty/policies/RoyaltyPolicyLAP.sol +++ b/contracts/modules/royalty/policies/RoyaltyPolicyLAP.sol @@ -13,6 +13,7 @@ import { IRoyaltyPolicyLAP } from "../../../interfaces/modules/royalty/policies/ import { ArrayUtils } from "../../../lib/ArrayUtils.sol"; import { Errors } from "../../../lib/Errors.sol"; import { ProtocolPausableUpgradeable } from "../../../pause/ProtocolPausableUpgradeable.sol"; +import { IPGraphACL } from "../../../access/IPGraphACL.sol"; /// @title Liquid Absolute Percentage Royalty Policy /// @notice Defines the logic for splitting royalties for a given ipId using a liquid absolute percentage mechanism @@ -60,6 +61,9 @@ contract RoyaltyPolicyLAP is /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address public immutable LICENSING_MODULE; + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + IPGraphACL public immutable IP_GRAPH_ACL; + /// @dev Restricts the calls to the royalty module modifier onlyRoyaltyModule() { if (msg.sender != ROYALTY_MODULE) revert Errors.RoyaltyPolicyLAP__NotRoyaltyModule(); @@ -69,13 +73,17 @@ contract RoyaltyPolicyLAP is /// @notice Constructor /// @param royaltyModule The RoyaltyModule address /// @param licensingModule The LicensingModule address + /// @param ipGraphAcl The IPGraphACL address /// @custom:oz-upgrades-unsafe-allow constructor - constructor(address royaltyModule, address licensingModule) { + constructor(address royaltyModule, address licensingModule, address ipGraphAcl) { if (royaltyModule == address(0)) revert Errors.RoyaltyPolicyLAP__ZeroRoyaltyModule(); if (licensingModule == address(0)) revert Errors.RoyaltyPolicyLAP__ZeroLicensingModule(); + if (ipGraphAcl == address(0)) revert Errors.RoyaltyPolicyLAP__ZeroIPGraphACL(); ROYALTY_MODULE = royaltyModule; LICENSING_MODULE = licensingModule; + IP_GRAPH_ACL = IPGraphACL(ipGraphAcl); + _disableInitializers(); } @@ -220,6 +228,8 @@ contract RoyaltyPolicyLAP is uint32[] memory royaltiesGroupByParent = new uint32[](parentIpIds.length); address[] memory uniqueParents = new address[](parentIpIds.length); uint256 uniqueParentCount; + + IP_GRAPH_ACL.allow(); for (uint256 i = 0; i < parentIpIds.length; i++) { (uint256 index, bool exists) = ArrayUtils.indexOf(uniqueParents, parentIpIds[i]); if (!exists) { @@ -230,6 +240,7 @@ contract RoyaltyPolicyLAP is uniqueParents[index] = parentIpIds[i]; _setRoyalty(ipId, parentIpIds[i], royaltiesGroupByParent[index]); } + IP_GRAPH_ACL.disallow(); // calculate new royalty stack uint32 royaltyStack = _getRoyaltyStack(ipId); diff --git a/contracts/registries/LicenseRegistry.sol b/contracts/registries/LicenseRegistry.sol index bb87c546..5dc71587 100644 --- a/contracts/registries/LicenseRegistry.sol +++ b/contracts/registries/LicenseRegistry.sol @@ -18,6 +18,7 @@ import { ExpiringOps } from "../lib/ExpiringOps.sol"; import { ILicenseTemplate } from "../interfaces/modules/licensing/ILicenseTemplate.sol"; import { IPAccountStorageOps } from "../lib/IPAccountStorageOps.sol"; import { IIPAccount } from "../interfaces/IIPAccount.sol"; +import { IPGraphACL } from "../access/IPGraphACL.sol"; /// @title LicenseRegistry aka LNFT /// @notice Registry of License NFTs, which represent licenses granted by IP ID licensors to create derivative IPs. @@ -33,6 +34,9 @@ contract LicenseRegistry is ILicenseRegistry, AccessManagedUpgradeable, UUPSUpgr ILicensingModule public immutable LICENSING_MODULE; /// @custom:oz-upgrades-unsafe-allow state-variable-immutable IDisputeModule public immutable DISPUTE_MODULE; + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + IPGraphACL public immutable IP_GRAPH_ACL; + /// @dev Storage of the LicenseRegistry /// @param defaultLicenseTemplate The default license template address @@ -76,11 +80,12 @@ contract LicenseRegistry is ILicenseRegistry, AccessManagedUpgradeable, UUPSUpgr } /// @custom:oz-upgrades-unsafe-allow constructor - constructor(address licensingModule, address disputeModule) { + constructor(address licensingModule, address disputeModule, address ipGraphAcl) { if (licensingModule == address(0)) revert Errors.LicenseRegistry__ZeroLicensingModule(); if (disputeModule == address(0)) revert Errors.LicenseRegistry__ZeroDisputeModule(); LICENSING_MODULE = ILicensingModule(licensingModule); DISPUTE_MODULE = IDisputeModule(disputeModule); + IP_GRAPH_ACL = IPGraphACL(ipGraphAcl); _disableInitializers(); } @@ -242,9 +247,12 @@ contract LicenseRegistry is ILicenseRegistry, AccessManagedUpgradeable, UUPSUpgr } } + IP_GRAPH_ACL.allow(); (bool success, ) = IP_GRAPH_CONTRACT.call( abi.encodeWithSignature("addParentIp(address,address[])", childIpId, parentIpIds) ); + IP_GRAPH_ACL.disallow(); + if (!success) { revert Errors.LicenseRegistry__AddParentIpToIPGraphFailed(childIpId, parentIpIds); } diff --git a/script/foundry/deployment/TestACL.s.sol b/script/foundry/deployment/TestACL.s.sol index 6d819f64..6c01a886 100644 --- a/script/foundry/deployment/TestACL.s.sol +++ b/script/foundry/deployment/TestACL.s.sol @@ -14,6 +14,7 @@ import "test/foundry/mocks/token/MockERC721.sol"; import { IPAssetRegistry } from "contracts/registries/IPAssetRegistry.sol"; import { LicensingModule } from "contracts/modules/licensing/LicensingModule.sol"; import "test/foundry/mocks/MockIPGraph.sol"; +import "contracts/access/IPGraphACL.sol"; import "test/foundry/mocks/token/MockERC721.sol"; @@ -33,6 +34,7 @@ contract TestACL is Script { address internal accessControllerAddr; address internal pilTemplateAddr; address internal licenseTokenAddr; + address internal ipGraphAclAddr; function run() public { vm.etch(address(0x1A), address(new MockIPGraph()).code); @@ -64,7 +66,7 @@ contract TestACL is Script { console2.log("Registered IP:", ipId2); console2.log("Registered IP:", ipId3); - + IPGraphACL(ipGraphAclAddr).allow(); address[] memory parents = new address[](1); parents[0] = ipId1; uint256[] memory licenseTermsIds = new uint256[](1); @@ -72,6 +74,7 @@ contract TestACL is Script { LicensingModule(licensingModuleAddr).registerDerivative(ipId2, parents, licenseTermsIds, pilTemplateAddr, ""); console2.log("Registered Derivative:", ipId2); + IPGraphACL(ipGraphAclAddr).disallow(); vm.stopBroadcast(); } @@ -92,6 +95,7 @@ contract TestACL is Script { accessControllerAddr = json.readAddress(".main.AccessController"); pilTemplateAddr = json.readAddress(".main.PILicenseTemplate"); licenseTokenAddr = json.readAddress(".main.LicenseToken"); + ipGraphAclAddr = json.readAddress(".main.IPGraphACL"); } function _predeploy(string memory contractKey) private view { diff --git a/script/foundry/utils/DeployHelper.sol b/script/foundry/utils/DeployHelper.sol index a2261318..55214816 100644 --- a/script/foundry/utils/DeployHelper.sol +++ b/script/foundry/utils/DeployHelper.sol @@ -136,7 +136,6 @@ contract DeployHelper is Script, BroadcastManager, JsonDeploymentHandler, Storag else if (block.chainid == 11155111) erc20 = ERC20(0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238); else if (block.chainid == 1513) erc20 = ERC20(0xDE51BB12D5cef80ff2334fe1019089363F80b46e); else if (block.chainid == 1337) erc20 = ERC20(0xDE51BB12D5cef80ff2334fe1019089363F80b46e); - else revert("Unsupported chain"); } /// @dev To use, run the following command (e.g. for Sepolia): @@ -286,7 +285,8 @@ contract DeployHelper is Script, BroadcastManager, JsonDeploymentHandler, Storag impl = address( new LicenseRegistry( _getDeployedAddress(type(LicensingModule).name), - _getDeployedAddress(type(DisputeModule).name) + _getDeployedAddress(type(DisputeModule).name), + _getDeployedAddress(type(IPGraphACL).name) ) ); licenseRegistry = LicenseRegistry( @@ -451,7 +451,11 @@ contract DeployHelper is Script, BroadcastManager, JsonDeploymentHandler, Storag _postdeploy("ArbitrationPolicySP", address(arbitrationPolicySP)); _predeploy("RoyaltyPolicyLAP"); - impl = address(new RoyaltyPolicyLAP(address(royaltyModule), address(licensingModule))); + impl = address(new RoyaltyPolicyLAP( + address(royaltyModule), + address(licensingModule), + _getDeployedAddress(type(IPGraphACL).name) + )); royaltyPolicyLAP = RoyaltyPolicyLAP( TestProxyHelper.deployUUPSProxy( create3Deployer, @@ -618,8 +622,8 @@ contract DeployHelper is Script, BroadcastManager, JsonDeploymentHandler, Storag licenseRegistry.setDefaultLicenseTerms(address(pilTemplate), licenseId); // IPGraphACL - ipGraphACL.addWhitelistAddress(address(licenseRegistry)); - ipGraphACL.addWhitelistAddress(address(royaltyPolicyLAP)); + ipGraphACL.whitelistAddress(address(licenseRegistry)); + ipGraphACL.whitelistAddress(address(royaltyPolicyLAP)); } function _configureRoles() private { diff --git a/test/foundry/access/IPGraphACL.t.sol b/test/foundry/access/IPGraphACL.t.sol new file mode 100644 index 00000000..1b548742 --- /dev/null +++ b/test/foundry/access/IPGraphACL.t.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.23; + +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"; + +import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; + +contract IPGraphACLTest is BaseTest { + + function setUp() public override { + super.setUp(); + } + + // test allow/disallow + // test add/remove whitelist + // onlyWhitelisted modifier + + + function test_IPGraphACL_initialized_not_allow() public { + assertFalse(ipGraphACL.isAllowed()); + } + + function test_IPGraphACL_allow() public { + vm.prank(address(licenseRegistry)); + ipGraphACL.allow(); + assertTrue(ipGraphACL.isAllowed()); + } + + function test_IPGraphACL_disallow() public { + vm.prank(address(licenseRegistry)); + ipGraphACL.disallow(); + assertFalse(ipGraphACL.isAllowed()); + } + + function test_IPGraphACL_addToWhitelist() public { + vm.prank(admin); + ipGraphACL.whitelistAddress(address(0x123)); + vm.prank(address(0x123)); + ipGraphACL.allow(); + assertTrue(ipGraphACL.isAllowed()); + } + + function test_IPGraphACL_revert_removeFromWhitelist() public { + vm.prank(admin); + ipGraphACL.whitelistAddress(address(0x123)); + vm.prank(address(0x123)); + ipGraphACL.allow(); + assertTrue(ipGraphACL.isAllowed()); + vm.prank(admin); + ipGraphACL.revokeWhitelistedAddress(address(0x123)); + vm.prank(address(0x123)); + vm.expectRevert(abi.encodeWithSelector(Errors.IPGraphACL__NotWhitelisted.selector, address(0x123))); + ipGraphACL.disallow(); + } + +} \ No newline at end of file diff --git a/test/foundry/mocks/module/LicenseRegistryHarness.sol b/test/foundry/mocks/module/LicenseRegistryHarness.sol index 1790e5df..81c47e10 100644 --- a/test/foundry/mocks/module/LicenseRegistryHarness.sol +++ b/test/foundry/mocks/module/LicenseRegistryHarness.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.23; import { LicenseRegistry } from "../../../../contracts/registries/LicenseRegistry.sol"; contract LicenseRegistryHarness is LicenseRegistry { - constructor(address _erc721Registry, address _erc1155Registry) LicenseRegistry(_erc721Registry, _erc1155Registry) {} + constructor(address _erc721Registry, address _erc1155Registry, address _ipGraphAcl) LicenseRegistry(_erc721Registry, _erc1155Registry, _ipGraphAcl) {} function setExpirationTime(address ipId, uint256 expireTime) external { _setExpirationTime(ipId, expireTime); diff --git a/test/foundry/modules/royalty/RoyaltyModule.t.sol b/test/foundry/modules/royalty/RoyaltyModule.t.sol index 0089c691..0b11c30a 100644 --- a/test/foundry/modules/royalty/RoyaltyModule.t.sol +++ b/test/foundry/modules/royalty/RoyaltyModule.t.sol @@ -31,7 +31,11 @@ contract TestRoyaltyModule is BaseTest { USDC.mint(ipAccount2, 1000 * 10 ** 6); // 1000 USDC - address impl = address(new RoyaltyPolicyLAP(address(royaltyModule), address(licensingModule))); + address impl = address(new RoyaltyPolicyLAP( + address(royaltyModule), + address(licensingModule), + address(ipGraphACL) + )); royaltyPolicyLAP2 = RoyaltyPolicyLAP( TestProxyHelper.deployUUPSProxy( impl, diff --git a/test/foundry/utils/BaseTest.t.sol b/test/foundry/utils/BaseTest.t.sol index 8de16003..c4f03e03 100644 --- a/test/foundry/utils/BaseTest.t.sol +++ b/test/foundry/utils/BaseTest.t.sol @@ -96,7 +96,11 @@ contract BaseTest is Test, DeployHelper, LicensingHelper { dealMockAssets(); ipAccountRegistry = IPAccountRegistry(ipAssetRegistry); - lrHarnessImpl = address(new LicenseRegistryHarness(address(licensingModule), address(disputeModule))); + lrHarnessImpl = address(new LicenseRegistryHarness( + address(licensingModule), + address(disputeModule), + address(ipGraphACL) + )); } function dealMockAssets() public { From 5f022c7b78a5da72a314b9a4cf5ee2da331b486a Mon Sep 17 00:00:00 2001 From: Kingster Date: Sun, 25 Aug 2024 17:47:15 -0700 Subject: [PATCH 4/6] Clean code base --- script/foundry/deployment/ACL.s.sol | 141 ------------------------ script/foundry/deployment/TestACL.s.sol | 108 ------------------ script/foundry/utils/DeployHelper.sol | 4 - 3 files changed, 253 deletions(-) delete mode 100644 script/foundry/deployment/ACL.s.sol delete mode 100644 script/foundry/deployment/TestACL.s.sol diff --git a/script/foundry/deployment/ACL.s.sol b/script/foundry/deployment/ACL.s.sol deleted file mode 100644 index 5b6bea1e..00000000 --- a/script/foundry/deployment/ACL.s.sol +++ /dev/null @@ -1,141 +0,0 @@ -/* solhint-disable no-console */ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; - -import { console2 } from "forge-std/console2.sol"; - -import { Script, stdJson } from "forge-std/Script.sol"; -import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; -import { PILFlavors } from "contracts/lib/PILFlavors.sol"; -import { PILicenseTemplate, PILTerms } from "contracts/modules/licensing/PILicenseTemplate.sol"; -import { LicenseRegistry } from "contracts/registries/LicenseRegistry.sol"; -import { ICreate3Deployer } from "@create3-deployer/contracts/ICreate3Deployer.sol"; - -import "test/foundry/mocks/token/MockERC721.sol"; - -contract StoryACL { - uint256 public length; - - function addWhitelistAddress(address addr) external { - uint256 slot = length++; - assembly { - sstore(slot, addr) - } - } - - function getWhitelistAddress(uint256 index) external view returns (address) { - address addr; - uint256 slot = index + 1; - assembly { - addr := sload(slot) - } - return addr; - } - - function getWhitelistLength() external view returns (uint256) { - return length; - } - - function revokeWhitelistAddress(uint256 index) external { - assembly { - sstore(index, 0) - } - } - - // is whitelisted - function isWhitelisted(address addr) external view returns (bool) { - for (uint256 i = 1; i <= length; i++) { - address whitelistAddr; - assembly { - whitelistAddr := sload(i) - } - if (whitelistAddr == addr) { - return true; - } - } - return false; - } -} - -contract DeployStoryACL is Script { - using stdJson for string; - address internal CREATE3_DEPLOYER = 0x384a891dFDE8180b054f04D66379f16B7a678Ad6; - - address public multisig; - address public deployer; - ICreate3Deployer create3Deployer; - address internal protocolAccessManagerAddr; - address internal ipAssetRegistryAddr; - address internal licensingModuleAddr; - address internal licenseRegistryAddr; - address internal royaltyModuleAddr; - address internal coreMetadataModuleAddr; - address internal accessControllerAddr; - address internal pilTemplateAddr; - address internal licenseTokenAddr; - - function run() public { - uint256 deployerPrivateKey; - _readStoryProtocolCoreAddresses(); - console2.log("Deploying StoryACL"); - console2.log("licenseRegistryAddr:", licenseRegistryAddr); - console2.log("royaltyModuleAddr:", royaltyModuleAddr); - console2.log("licensingModuleAddr:", licensingModuleAddr); - - deployerPrivateKey = vm.envUint("STORY_PRIVATEKEY"); - deployer = vm.envAddress("STORY_DEPLOYER_ADDRESS"); - multisig = vm.envAddress("STORY_MULTISIG_ADDRESS"); - - create3Deployer = ICreate3Deployer(CREATE3_DEPLOYER); - address[] memory whitelist = new address[](3); - whitelist[0] = licenseRegistryAddr; - whitelist[1] = royaltyModuleAddr; - whitelist[2] = licensingModuleAddr; - - vm.startBroadcast(deployerPrivateKey); - string memory contractKey = "StoryAcl"; - // uint256 seed = 1000; - _predeploy(contractKey); - StoryACL storyAcl = StoryACL( - create3Deployer.deploy( - keccak256(abi.encode("TheStoryPrecompileACL")), - abi.encodePacked( - type(StoryACL).creationCode, - abi.encode(licenseRegistryAddr), - abi.encode(royaltyModuleAddr), - abi.encode(licensingModuleAddr) - ) - ) - ); - _postdeploy(contractKey, address(storyAcl)); - - vm.stopBroadcast(); - - } - - function _readStoryProtocolCoreAddresses() internal { - string memory root = vm.projectRoot(); - string memory path = string.concat( - root, - string(abi.encodePacked("/deploy-out/deployment-", Strings.toString(block.chainid), ".json")) - ); - string memory json = vm.readFile(path); - protocolAccessManagerAddr = json.readAddress(".main.ProtocolAccessManager"); - ipAssetRegistryAddr = json.readAddress(".main.IPAssetRegistry"); - licensingModuleAddr = json.readAddress(".main.LicensingModule"); - licenseRegistryAddr = json.readAddress(".main.LicenseRegistry"); - royaltyModuleAddr = json.readAddress(".main.RoyaltyModule"); - coreMetadataModuleAddr = json.readAddress(".main.CoreMetadataModule"); - accessControllerAddr = json.readAddress(".main.AccessController"); - pilTemplateAddr = json.readAddress(".main.PILicenseTemplate"); - licenseTokenAddr = json.readAddress(".main.LicenseToken"); - } - - function _predeploy(string memory contractKey) private view { - console2.log(string.concat("Deploying ", contractKey, "...")); - } - - function _postdeploy(string memory contractKey, address newAddress) private { - console2.log(string.concat(contractKey, " deployed to:"), newAddress); - } -} diff --git a/script/foundry/deployment/TestACL.s.sol b/script/foundry/deployment/TestACL.s.sol deleted file mode 100644 index 6c01a886..00000000 --- a/script/foundry/deployment/TestACL.s.sol +++ /dev/null @@ -1,108 +0,0 @@ -/* solhint-disable no-console */ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; - -import { console2 } from "forge-std/console2.sol"; - -import { Script, stdJson } from "forge-std/Script.sol"; -import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; -import { PILFlavors } from "contracts/lib/PILFlavors.sol"; -import { PILicenseTemplate, PILTerms } from "contracts/modules/licensing/PILicenseTemplate.sol"; -import { LicenseRegistry } from "contracts/registries/LicenseRegistry.sol"; -import { ICreate3Deployer } from "@create3-deployer/contracts/ICreate3Deployer.sol"; -import "test/foundry/mocks/token/MockERC721.sol"; -import { IPAssetRegistry } from "contracts/registries/IPAssetRegistry.sol"; -import { LicensingModule } from "contracts/modules/licensing/LicensingModule.sol"; -import "test/foundry/mocks/MockIPGraph.sol"; -import "contracts/access/IPGraphACL.sol"; - -import "test/foundry/mocks/token/MockERC721.sol"; - -contract TestACL is Script { - using stdJson for string; - address internal CREATE3_DEPLOYER = 0x384a891dFDE8180b054f04D66379f16B7a678Ad6; - - address public multisig; - address public deployer; - ICreate3Deployer create3Deployer; - address internal protocolAccessManagerAddr; - address internal ipAssetRegistryAddr; - address internal licensingModuleAddr; - address internal licenseRegistryAddr; - address internal royaltyModuleAddr; - address internal coreMetadataModuleAddr; - address internal accessControllerAddr; - address internal pilTemplateAddr; - address internal licenseTokenAddr; - address internal ipGraphAclAddr; - - function run() public { - vm.etch(address(0x1A), address(new MockIPGraph()).code); - uint256 deployerPrivateKey; - _readStoryProtocolCoreAddresses(); - console2.log("Testing StoryACL"); - console2.log("licenseRegistryAddr:", licenseRegistryAddr); - console2.log("royaltyModuleAddr:", royaltyModuleAddr); - console2.log("licensingModuleAddr:", licensingModuleAddr); - - deployerPrivateKey = vm.envUint("STORY_PRIVATEKEY"); - deployer = vm.envAddress("STORY_DEPLOYER_ADDRESS"); - multisig = vm.envAddress("STORY_MULTISIG_ADDRESS"); - - - vm.startBroadcast(deployerPrivateKey); - MockERC721 mockERC721 = new MockERC721("MockERC721"); - uint256 tokenId1 = mockERC721.mint(deployer); - console2.log("Minted tokenId:", tokenId1); - uint256 tokenId2 = mockERC721.mint(deployer); - console2.log("Minted tokenId:", tokenId2); - uint256 tokenId3 = mockERC721.mint(deployer); - console2.log("Minted tokenId:", tokenId3); - - address ipId1 = IPAssetRegistry(ipAssetRegistryAddr).register(block.chainid, address(mockERC721), tokenId1); - address ipId2 = IPAssetRegistry(ipAssetRegistryAddr).register(block.chainid, address(mockERC721), tokenId2); - address ipId3 = IPAssetRegistry(ipAssetRegistryAddr).register(block.chainid, address(mockERC721), tokenId3); - console2.log("Registered IP:", ipId1); - console2.log("Registered IP:", ipId2); - console2.log("Registered IP:", ipId3); - - IPGraphACL(ipGraphAclAddr).allow(); - address[] memory parents = new address[](1); - parents[0] = ipId1; - uint256[] memory licenseTermsIds = new uint256[](1); - licenseTermsIds[0] = 1; - LicensingModule(licensingModuleAddr).registerDerivative(ipId2, parents, licenseTermsIds, pilTemplateAddr, ""); - console2.log("Registered Derivative:", ipId2); - - IPGraphACL(ipGraphAclAddr).disallow(); - - vm.stopBroadcast(); - } - - function _readStoryProtocolCoreAddresses() internal { - string memory root = vm.projectRoot(); - string memory path = string.concat( - root, - string(abi.encodePacked("/deploy-out/deployment-", Strings.toString(block.chainid), ".json")) - ); - string memory json = vm.readFile(path); - protocolAccessManagerAddr = json.readAddress(".main.ProtocolAccessManager"); - ipAssetRegistryAddr = json.readAddress(".main.IPAssetRegistry"); - licensingModuleAddr = json.readAddress(".main.LicensingModule"); - licenseRegistryAddr = json.readAddress(".main.LicenseRegistry"); - royaltyModuleAddr = json.readAddress(".main.RoyaltyModule"); - coreMetadataModuleAddr = json.readAddress(".main.CoreMetadataModule"); - accessControllerAddr = json.readAddress(".main.AccessController"); - pilTemplateAddr = json.readAddress(".main.PILicenseTemplate"); - licenseTokenAddr = json.readAddress(".main.LicenseToken"); - ipGraphAclAddr = json.readAddress(".main.IPGraphACL"); - } - - function _predeploy(string memory contractKey) private view { - console2.log(string.concat("Deploying ", contractKey, "...")); - } - - function _postdeploy(string memory contractKey, address newAddress) private { - console2.log(string.concat(contractKey, " deployed to:"), newAddress); - } -} diff --git a/script/foundry/utils/DeployHelper.sol b/script/foundry/utils/DeployHelper.sol index 55214816..dcf9380a 100644 --- a/script/foundry/utils/DeployHelper.sol +++ b/script/foundry/utils/DeployHelper.sol @@ -617,10 +617,6 @@ contract DeployHelper is Script, BroadcastManager, JsonDeploymentHandler, Storag // License Template licenseRegistry.registerLicenseTemplate(address(pilTemplate)); - // set default license to non-commercial social remixing - uint256 licenseId = pilTemplate.registerLicenseTerms(PILFlavors.nonCommercialSocialRemixing()); - licenseRegistry.setDefaultLicenseTerms(address(pilTemplate), licenseId); - // IPGraphACL ipGraphACL.whitelistAddress(address(licenseRegistry)); ipGraphACL.whitelistAddress(address(royaltyPolicyLAP)); From ee7c37b3940184db7137e3081e6c5ea5f4dde41f Mon Sep 17 00:00:00 2001 From: Kingster Date: Sun, 25 Aug 2024 17:49:25 -0700 Subject: [PATCH 5/6] fix lint --- contracts/access/IPGraphACL.sol | 3 +-- contracts/registries/LicenseRegistry.sol | 1 - test/foundry/access/IPGraphACL.t.sol | 12 +----------- test/foundry/mocks/module/LicenseRegistryHarness.sol | 6 +++++- test/foundry/modules/royalty/RoyaltyModule.t.sol | 8 +++----- test/foundry/utils/BaseTest.t.sol | 8 +++----- 6 files changed, 13 insertions(+), 25 deletions(-) diff --git a/contracts/access/IPGraphACL.sol b/contracts/access/IPGraphACL.sol index 6758e81d..46c380fe 100644 --- a/contracts/access/IPGraphACL.sol +++ b/contracts/access/IPGraphACL.sol @@ -11,8 +11,7 @@ import { Errors } from "../lib/Errors.sol"; /// IPGraph precompiled check if the IPGraphACL contract allows access to the IPGraph. contract IPGraphACL is AccessManaged { // keccak256(abi.encode(uint256(keccak256("story-protocol.IPGraphACL")) - 1)) & ~bytes32(uint256(0xff)); - bytes32 private constant IP_GRAPH_ACL_SLOT = - 0xaf99b37fdaacca72ee7240cb1435cc9e498aee6ef4edc19c8cc0cd787f4e6800; + bytes32 private constant IP_GRAPH_ACL_SLOT = 0xaf99b37fdaacca72ee7240cb1435cc9e498aee6ef4edc19c8cc0cd787f4e6800; /// @notice Whitelisted addresses that can allow or disallow access to the IPGraph contract. mapping(address => bool) public whitelist; diff --git a/contracts/registries/LicenseRegistry.sol b/contracts/registries/LicenseRegistry.sol index 5dc71587..5158dcf7 100644 --- a/contracts/registries/LicenseRegistry.sol +++ b/contracts/registries/LicenseRegistry.sol @@ -37,7 +37,6 @@ contract LicenseRegistry is ILicenseRegistry, AccessManagedUpgradeable, UUPSUpgr /// @custom:oz-upgrades-unsafe-allow state-variable-immutable IPGraphACL public immutable IP_GRAPH_ACL; - /// @dev Storage of the LicenseRegistry /// @param defaultLicenseTemplate The default license template address /// @param defaultLicenseTermsId The default license terms ID diff --git a/test/foundry/access/IPGraphACL.t.sol b/test/foundry/access/IPGraphACL.t.sol index 1b548742..9fe6e942 100644 --- a/test/foundry/access/IPGraphACL.t.sol +++ b/test/foundry/access/IPGraphACL.t.sol @@ -1,18 +1,10 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; -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"; -import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; - contract IPGraphACLTest is BaseTest { - function setUp() public override { super.setUp(); } @@ -21,7 +13,6 @@ contract IPGraphACLTest is BaseTest { // test add/remove whitelist // onlyWhitelisted modifier - function test_IPGraphACL_initialized_not_allow() public { assertFalse(ipGraphACL.isAllowed()); } @@ -58,5 +49,4 @@ contract IPGraphACLTest is BaseTest { vm.expectRevert(abi.encodeWithSelector(Errors.IPGraphACL__NotWhitelisted.selector, address(0x123))); ipGraphACL.disallow(); } - -} \ No newline at end of file +} diff --git a/test/foundry/mocks/module/LicenseRegistryHarness.sol b/test/foundry/mocks/module/LicenseRegistryHarness.sol index 81c47e10..c67e71ea 100644 --- a/test/foundry/mocks/module/LicenseRegistryHarness.sol +++ b/test/foundry/mocks/module/LicenseRegistryHarness.sol @@ -4,7 +4,11 @@ pragma solidity 0.8.23; import { LicenseRegistry } from "../../../../contracts/registries/LicenseRegistry.sol"; contract LicenseRegistryHarness is LicenseRegistry { - constructor(address _erc721Registry, address _erc1155Registry, address _ipGraphAcl) LicenseRegistry(_erc721Registry, _erc1155Registry, _ipGraphAcl) {} + constructor( + address _erc721Registry, + address _erc1155Registry, + address _ipGraphAcl + ) LicenseRegistry(_erc721Registry, _erc1155Registry, _ipGraphAcl) {} function setExpirationTime(address ipId, uint256 expireTime) external { _setExpirationTime(ipId, expireTime); diff --git a/test/foundry/modules/royalty/RoyaltyModule.t.sol b/test/foundry/modules/royalty/RoyaltyModule.t.sol index 0b11c30a..1306750e 100644 --- a/test/foundry/modules/royalty/RoyaltyModule.t.sol +++ b/test/foundry/modules/royalty/RoyaltyModule.t.sol @@ -31,11 +31,9 @@ contract TestRoyaltyModule is BaseTest { USDC.mint(ipAccount2, 1000 * 10 ** 6); // 1000 USDC - address impl = address(new RoyaltyPolicyLAP( - address(royaltyModule), - address(licensingModule), - address(ipGraphACL) - )); + address impl = address( + new RoyaltyPolicyLAP(address(royaltyModule), address(licensingModule), address(ipGraphACL)) + ); royaltyPolicyLAP2 = RoyaltyPolicyLAP( TestProxyHelper.deployUUPSProxy( impl, diff --git a/test/foundry/utils/BaseTest.t.sol b/test/foundry/utils/BaseTest.t.sol index c4f03e03..54ba59cf 100644 --- a/test/foundry/utils/BaseTest.t.sol +++ b/test/foundry/utils/BaseTest.t.sol @@ -96,11 +96,9 @@ contract BaseTest is Test, DeployHelper, LicensingHelper { dealMockAssets(); ipAccountRegistry = IPAccountRegistry(ipAssetRegistry); - lrHarnessImpl = address(new LicenseRegistryHarness( - address(licensingModule), - address(disputeModule), - address(ipGraphACL) - )); + lrHarnessImpl = address( + new LicenseRegistryHarness(address(licensingModule), address(disputeModule), address(ipGraphACL)) + ); } function dealMockAssets() public { From 3659d866b2b0449e59b9aab2cadc273f0b9a4e54 Mon Sep 17 00:00:00 2001 From: Kingster Date: Sun, 25 Aug 2024 18:46:02 -0700 Subject: [PATCH 6/6] handle zero address --- contracts/lib/Errors.sol | 3 +++ contracts/registries/LicenseRegistry.sol | 1 + 2 files changed, 4 insertions(+) diff --git a/contracts/lib/Errors.sol b/contracts/lib/Errors.sol index 0c5c6087..eceb452c 100644 --- a/contracts/lib/Errors.sol +++ b/contracts/lib/Errors.sol @@ -173,6 +173,9 @@ library Errors { /// @notice Failed to add parent IPs to IP graph. error LicenseRegistry__AddParentIpToIPGraphFailed(address childIpId, address[] parentIpIds); + /// @notice Zero address provided for IP Graph ACL. + error LicenseRegistry__ZeroIPGraphACL(); + //////////////////////////////////////////////////////////////////////////// // License Token // //////////////////////////////////////////////////////////////////////////// diff --git a/contracts/registries/LicenseRegistry.sol b/contracts/registries/LicenseRegistry.sol index 5158dcf7..56c053e9 100644 --- a/contracts/registries/LicenseRegistry.sol +++ b/contracts/registries/LicenseRegistry.sol @@ -82,6 +82,7 @@ contract LicenseRegistry is ILicenseRegistry, AccessManagedUpgradeable, UUPSUpgr constructor(address licensingModule, address disputeModule, address ipGraphAcl) { if (licensingModule == address(0)) revert Errors.LicenseRegistry__ZeroLicensingModule(); if (disputeModule == address(0)) revert Errors.LicenseRegistry__ZeroDisputeModule(); + if (ipGraphAcl == address(0)) revert Errors.LicenseRegistry__ZeroIPGraphACL(); LICENSING_MODULE = ILicensingModule(licensingModule); DISPUTE_MODULE = IDisputeModule(disputeModule); IP_GRAPH_ACL = IPGraphACL(ipGraphAcl);