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

New Integration Test #52

Merged
merged 10 commits into from
Jan 31, 2024
12 changes: 4 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ artifacts/
forge-cache/

# Ignores development broadcast logs
!/broadcast
# ignore 1 for now, it's tenderly fork
/broadcast/*/1/
/broadcast/*/31337/
/broadcast/**/dry-run/
# !/broadcast
deployments
broadcast
!/broadcast/*/1/

# Docs
docs/
Expand All @@ -32,8 +31,5 @@ abi
typechain
!./script/out

# hardhat-tenderly plugin
deployments

# converage
lcov.info
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,14 @@ format:
npx prettier --write contracts/**/**/**/*.sol
npx prettier --write contracts/**/**/**/**/*.sol

# generate forge coverage on pinned mainnet fork
# process lcov file, ignore test, script, and contracts/mocks folders
# generate html report from lcov.info (ignore "line ... has branchcov but no linecov data" error)
coverage:
mkdir -p coverage
forge coverage --report lcov --fork-url https://rpc.ankr.com/eth --fork-block-number 19042069
lcov --remove lcov.info -o lcov.info 'test/*' 'script/*' 'contracts/mocks/*'
genhtml lcov.info --output-dir coverage
lcov --remove lcov.info -o coverage/lcov.info 'test/*' 'script/*' 'contracts/mocks/*' --rc branch_coverage=1
genhtml coverage/lcov.info -o coverage --rc branch_coverage=1 --ignore-errors category

abi:
mkdir -p abi
Expand Down
4 changes: 2 additions & 2 deletions contracts/interfaces/registries/IModuleRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ interface IModuleRegistry {
/// @notice Emitted when a new module is added to the registry.
/// @param name The name of the module.
/// @param module The address of the module.
event ModuleAdded(string indexed name, address indexed module);
event ModuleAdded(string name, address indexed module);

/// @notice Emitted when a module is removed from the registry.
/// @param name The name of the module.
/// @param module The address of the module.
event ModuleRemoved(string indexed name, address indexed module);
event ModuleRemoved(string name, address indexed module);

/// @notice Registers a new module in the registry.
/// @dev This function can only be called by the owner of the registry.
Expand Down
1 change: 1 addition & 0 deletions contracts/lib/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ library Errors {
error LicenseRegistry__UnregisteredFrameworkAddingPolicy();
error LicenseRegistry__UnauthorizedAccess();
error LicenseRegistry__LicensorNotRegistered();
error LicenseRegistry__CallerNotLicensorAndPolicyNotSet();

////////////////////////////////////////////////////////////////////////////
// LicenseRegistryAware //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { IAccessController } from "contracts/interfaces/IAccessController.sol";
/// @notice Manages the approval of derivative IP accounts by the licensor. Used to verify
/// licensing terms like "Derivatives With Approval" in UML.
abstract contract LicensorApprovalManager is LicenseRegistryAware {

/// Emits when a derivative IP account is approved by the licensor.
/// @param licenseId id of the license waiting for approval
/// @param ipId id of the derivative IP to be approved
Expand All @@ -34,7 +33,10 @@ abstract contract LicensorApprovalManager is LicenseRegistryAware {
/// @param approved result of the approval
function setApproval(uint256 licenseId, address childIpId, bool approved) external {
address licensorIpId = LICENSE_REGISTRY.licensorIpId(licenseId);
if (!ACCESS_CONTROLLER.checkPermission(licensorIpId, msg.sender, address(this), msg.sig)) {
if (
msg.sender != licensorIpId &&
!ACCESS_CONTROLLER.checkPermission(licensorIpId, msg.sender, address(this), msg.sig)
) {
revert Errors.LicensorApprovalManager__Unauthorized();
}
// TODO: meta tx version?
Expand All @@ -51,5 +53,4 @@ abstract contract LicensorApprovalManager is LicenseRegistryAware {
address licensorIpId = LICENSE_REGISTRY.licensorIpId(licenseId);
return _approvals[licenseId][licensorIpId][childIpId];
}

}
4 changes: 0 additions & 4 deletions contracts/registries/IPAssetRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,6 @@ contract IPAssetRegistry is IIPAssetRegistry, IPAccountRegistry {
/// @param id The canonical ID of the IP.
/// @param resolverAddr The address of the resolver being set.
function _setResolver(address id, address resolverAddr) internal {
if (resolverAddr == address(0)) {
revert Errors.IPAssetRegistry_ResolverInvalid();
}

ERC165Checker.supportsInterface(resolverAddr, type(IResolver).interfaceId);
_records[id].resolver = resolverAddr;
emit IPResolverSet(id, resolverAddr);
Expand Down
26 changes: 17 additions & 9 deletions contracts/registries/LicenseRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,10 @@ contract LicenseRegistry is ERC1155, ILicenseRegistry {
/// @param polId id of the policy data
/// @return indexOnIpId position of policy within the ipIds policy set
function addPolicyToIp(address ipId, uint256 polId) external returns (uint256 indexOnIpId) {
if (!ACCESS_CONTROLLER.checkPermission(ipId, msg.sender, address(this), this.addPolicyToIp.selector)) {
if (
msg.sender != ipId &&
!ACCESS_CONTROLLER.checkPermission(ipId, msg.sender, address(this), this.addPolicyToIp.selector)
) {
revert Errors.LicenseRegistry__UnauthorizedAccess();
}

Expand Down Expand Up @@ -276,19 +279,21 @@ contract LicenseRegistry is ERC1155, ILicenseRegistry {
uint256 amount, // mint amount
address receiver
) external returns (uint256 licenseId) {
// TODO: check if licensor are valid IP Ids
// TODO: check if licensor has been tagged by disputer
// TODO: check if licensor allowed sender to mint in their behalf
// TODO: licensor == msg.sender, expect if derivatives && withReciprocal
if (licensorIp == address(0)) {
revert Errors.LicenseRegistry__InvalidLicensor();
}
if (!IP_ACCOUNT_REGISTRY.isIpAccount(licensorIp)) {
revert Errors.LicenseRegistry__LicensorNotRegistered();
}
// If the IP ID doesn't have a policy (meaning, no permissionless derivatives)
if (!_policiesPerIpId[licensorIp].contains(policyId)) {
revert Errors.LicenseRegistry__LicensorDoesntHaveThisPolicy();
// We have to check if the caller is licensor or authorized to mint.
if (
msg.sender != licensorIp &&
!ACCESS_CONTROLLER.checkPermission(licensorIp, msg.sender, address(this), this.mintLicense.selector)
) {
revert Errors.LicenseRegistry__CallerNotLicensorAndPolicyNotSet();
}
}
// If a policy is set, then is only up to the policy params.
// Verify minting param
Licensing.Policy memory pol = policy(policyId);
Licensing.PolicyFramework storage fw = _framework(pol.policyFrameworkId);
Expand Down Expand Up @@ -348,7 +353,10 @@ contract LicenseRegistry is ERC1155, ILicenseRegistry {
address holder
) external onlyLicensee(licenseId, holder) {
// check the caller is owner or authorized by the childIp
if (!ACCESS_CONTROLLER.checkPermission(childIpId, msg.sender, address(this), this.linkIpToParent.selector)) {
if (
msg.sender != childIpId &&
!ACCESS_CONTROLLER.checkPermission(childIpId, msg.sender, address(this), this.linkIpToParent.selector)
) {
revert Errors.LicenseRegistry__UnauthorizedAccess();
}
// TODO: check if childIpId exists and is owned by holder
Expand Down
75 changes: 45 additions & 30 deletions script/foundry/deployment/Main.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import { ERC6551Registry } from "lib/reference/src/ERC6551Registry.sol";
import { IERC6551Account } from "lib/reference/src/interfaces/IERC6551Account.sol";
// contracts
import { AccessController } from "contracts/AccessController.sol";
import { Governance } from "contracts/governance/Governance.sol";
import { IPAccountImpl } from "contracts/IPAccountImpl.sol";
import { IIPAccount } from "contracts/interfaces/IIPAccount.sol";
import { Errors } from "contracts/lib/Errors.sol";
import { Licensing } from "contracts/lib/Licensing.sol";
import { IP_RESOLVER_MODULE_KEY, REGISTRATION_MODULE_KEY } from "contracts/lib/modules/Module.sol";
import { IPMetadataProvider } from "contracts/registries/metadata/IPMetadataProvider.sol";
import { IPAccountRegistry } from "contracts/registries/IPAccountRegistry.sol";
import { IPAssetRegistry } from "contracts/registries/IPAssetRegistry.sol";
Expand All @@ -25,19 +27,16 @@ import { RegistrationModule } from "contracts/modules/RegistrationModule.sol";
import { TaggingModule } from "contracts/modules/tagging/TaggingModule.sol";
import { RoyaltyModule } from "contracts/modules/royalty-module/RoyaltyModule.sol";
import { DisputeModule } from "contracts/modules/dispute-module/DisputeModule.sol";
import { IPResolver } from "contracts/resolvers/IPResolver.sol";
import { Governance } from "contracts/governance/Governance.sol";
import { UMLPolicy } from "contracts/interfaces/licensing/IUMLPolicyFrameworkManager.sol";
import { UMLPolicyFrameworkManager } from "contracts/modules/licensing/UMLPolicyFrameworkManager.sol";

// test
import { MockERC721 } from "test/foundry/mocks/MockERC721.sol";
import { UMLPolicyFrameworkManager, UMLPolicy } from "contracts/modules/licensing/UMLPolicyFrameworkManager.sol";

// script
import { StringUtil } from "script/foundry/utils/StringUtil.sol";
import { BroadcastManager } from "script/foundry/utils/BroadcastManager.s.sol";
import { JsonDeploymentHandler } from "script/foundry/utils/JsonDeploymentHandler.s.sol";

// test
import { MockERC721 } from "test/foundry/mocks/MockERC721.sol";

contract Main is Script, BroadcastManager, JsonDeploymentHandler {
using StringUtil for uint256;
using stdJson for string;
Expand Down Expand Up @@ -87,17 +86,18 @@ contract Main is Script, BroadcastManager, JsonDeploymentHandler {
_deployProtocolContracts(deployer);
_configureDeployment();
}
// _configureDeployedProtocolContracts();

_writeDeployment(); // write deployment json to deployments/deployment-{chainId}.json
_endBroadcast(); // BroadcastManager.s.sol
}

function _deployProtocolContracts(address accessControldeployer) private {
function _deployProtocolContracts(address accessControlDeployer) private {
string memory contractKey;

contractKey = "Governance";
_predeploy(contractKey);
governance = new Governance(accessControldeployer);
governance = new Governance(accessControlDeployer);
_postdeploy(contractKey, address(governance));

mockNft = new MockERC721("MockERC721");
Expand Down Expand Up @@ -125,7 +125,12 @@ contract Main is Script, BroadcastManager, JsonDeploymentHandler {
// TODO: deployment sequence
contractKey = "IPAssetRegistry";
_predeploy(contractKey);
ipAssetRegistry = new IPAssetRegistry(address(accessController), ERC6551_REGISTRY, address(implementation), address(metadataProvider));
ipAssetRegistry = new IPAssetRegistry(
address(accessController),
ERC6551_REGISTRY,
address(implementation),
address(metadataProvider)
);
_postdeploy(contractKey, address(ipAssetRegistry));

contractKey = "LicenseRegistry";
Expand All @@ -135,11 +140,7 @@ contract Main is Script, BroadcastManager, JsonDeploymentHandler {

contractKey = "IPResolver";
_predeploy(contractKey);
ipResolver = new IPResolver(
address(accessController),
address(ipAssetRegistry),
address(licenseRegistry)
);
ipResolver = new IPResolver(address(accessController), address(ipAssetRegistry), address(licenseRegistry));
_postdeploy(contractKey, address(ipResolver));

contractKey = "MetadataProvider";
Expand Down Expand Up @@ -184,7 +185,26 @@ contract Main is Script, BroadcastManager, JsonDeploymentHandler {
// mockModule = new MockModule(address(ipAccountRegistry), address(moduleRegistry), "MockModule");
}

function _predeploy(string memory contractKey) private {
function _configureDeployedProtocolContracts() private {
_readDeployment();

accessController = AccessController(_readAddress("main.AccessController"));
ipAccountRegistry = IPAccountRegistry(_readAddress("main.IPAccountRegistry"));
moduleRegistry = ModuleRegistry(_readAddress("main.ModuleRegistry"));
licenseRegistry = LicenseRegistry(_readAddress("main.LicenseRegistry"));
ipAssetRegistry = IPAssetRegistry(_readAddress("main.IPAssetRegistry"));
ipResolver = IPResolver(_readAddress("main.IPResolver"));
metadataProvider = IPMetadataProvider(_readAddress("main.MetadataProvider"));
registrationModule = RegistrationModule(_readAddress("main.RegistrationModule"));
taggingModule = TaggingModule(_readAddress("main.TaggingModule"));
royaltyModule = RoyaltyModule(_readAddress("main.RoyaltyModule"));
disputeModule = DisputeModule(_readAddress("main.DisputeModule"));
renderer = IPAssetRenderer(_readAddress("main.IPAssetRenderer"));

_configureInteractions();
}

function _predeploy(string memory contractKey) private view {
console2.log(string.concat("Deploying ", contractKey, "..."));
}

Expand All @@ -206,8 +226,8 @@ contract Main is Script, BroadcastManager, JsonDeploymentHandler {
}

function _configureModuleRegistry() private {
moduleRegistry.registerModule("REGISTRATION_MODULE", address(registrationModule));
moduleRegistry.registerModule("METADATA_RESOLVER_MODULE", address(ipResolver));
moduleRegistry.registerModule(REGISTRATION_MODULE_KEY, address(registrationModule));
moduleRegistry.registerModule(IP_RESOLVER_MODULE_KEY, address(ipResolver));
}

function _configureInteractions() private {
Expand All @@ -228,14 +248,14 @@ contract Main is Script, BroadcastManager, JsonDeploymentHandler {
);

// wildcard allow
IIPAccount(payable(getIpId(deployer, mockNft, nftIds[1]))).execute(
IIPAccount(payable(getIpId(mockNft, nftIds[1]))).execute(
address(accessController),
0,
abi.encodeWithSignature(
"setPermission(address,address,address,bytes4,uint8)",
getIpId(deployer, mockNft, 1),
getIpId(mockNft, 1),
deployer,
address(0),
address(licenseRegistry),
bytes4(0),
1 // AccessPermission.ALLOW
)
Expand All @@ -259,9 +279,9 @@ contract Main is Script, BroadcastManager, JsonDeploymentHandler {
frameworkIds["all_true"] = umlAllTrue.register();
frameworkIds["mint_payment"] = umlMintPayment.register();

// /*///////////////////////////////////////////////////////////////
// CREATE POLICIES
// ////////////////////////////////////////////////////////////////*/
/*///////////////////////////////////////////////////////////////
CREATE POLICIES
////////////////////////////////////////////////////////////////*/

policyIds["test_true"] = umlAllTrue.addPolicy(
UMLPolicy({
Expand Down Expand Up @@ -337,9 +357,4 @@ contract Main is Script, BroadcastManager, JsonDeploymentHandler {
function getIpId(MockERC721 mnft, uint256 tokenId) public view returns (address ipId) {
return ipAccountRegistry.ipAccount(block.chainid, address(mnft), tokenId);
}

function getIpId(address user, MockERC721 mnft, uint256 tokenId) public view returns (address ipId) {
require(mnft.ownerOf(tokenId) == user, "getIpId: not owner");
return ipAccountRegistry.ipAccount(block.chainid, address(mnft), tokenId);
}
}
}
17 changes: 5 additions & 12 deletions script/foundry/deployment/MockAssets.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ pragma solidity ^0.8.23;
import { console2 } from "forge-std/console2.sol";
import { Script } from "forge-std/Script.sol";
import { stdJson } from "forge-std/StdJson.sol";
// test
import { MockERC20 } from "test/foundry/mocks/MockERC20.sol";
import { MockERC721 } from "test/foundry/mocks/MockERC721.sol";
// script
import { BroadcastManager } from "script/foundry/utils/BroadcastManager.s.sol";
import { JsonDeploymentHandler } from "script/foundry/utils/JsonDeploymentHandler.s.sol";
// test
import { MockERC20 } from "test/foundry/mocks/MockERC20.sol";
import { MockERC721 } from "test/foundry/mocks/MockERC721.sol";

contract MockAssets is Script, BroadcastManager, JsonDeploymentHandler {
using stdJson for string;
Expand All @@ -24,20 +24,13 @@ contract MockAssets is Script, BroadcastManager, JsonDeploymentHandler {
function run() public {
_beginBroadcast(); // BroadcastManager.s.sol

bool configByMultisig = vm.envBool("DEPLOYMENT_CONFIG_BY_MULTISIG");
console2.log("configByMultisig:", configByMultisig);

if (configByMultisig) {
_deployProtocolContracts(multisig);
} else {
_deployProtocolContracts(deployer);
}
_deployProtocolContracts();

_writeDeployment(); // write deployment json to deploy-out/deployment-{chainId}.json
_endBroadcast(); // BroadcastManager.s.sol
}

function _deployProtocolContracts(address accessControlAdmin) private {
function _deployProtocolContracts() private {
_predeploy("MockERC20");
MockERC20 mockERC20 = new MockERC20();
_postdeploy("MockERC20", address(mockERC20));
Expand Down
2 changes: 1 addition & 1 deletion script/foundry/utils/JsonDeploymentHandler.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ contract JsonDeploymentHandler is Script {

function _readDeployment() internal {
string memory root = vm.projectRoot();
string memory filePath = string.concat("./deploy-out/deployment-", (block.chainid).toString(), ".json");
string memory filePath = string.concat("/deploy-out/deployment-", (block.chainid).toString(), ".json");
string memory path = string.concat(root, filePath);
readJson = vm.readFile(path);
}
Expand Down
14 changes: 0 additions & 14 deletions test/foundry/IPAssetRegistry.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -253,20 +253,6 @@ contract IPAssetRegistryTest is BaseTest {
registry.setResolver(block.chainid, tokenAddress, tokenId, resolver);
}

/// @notice Tests IP resolver setting reverts if the resolver is invalid.
function test_IPAssetRegistry_SetResolver_Reverts_ResolverInvalid() public {
registry.register(
block.chainid,
tokenAddress,
tokenId,
resolver,
true
);
vm.startPrank(alice);
vm.expectRevert(Errors.IPAssetRegistry_ResolverInvalid.selector);
registry.setResolver(block.chainid, tokenAddress, tokenId, address(0));
}

/// @notice Helper function for generating an account address.
function _getAccount(
address impl,
Expand Down
Loading
Loading