diff --git a/contracts/IPAssetRegistry.sol b/contracts/IPAssetRegistry.sol index ae1b9562..bd889d8f 100644 --- a/contracts/IPAssetRegistry.sol +++ b/contracts/IPAssetRegistry.sol @@ -31,6 +31,7 @@ contract IPAssetRegistry is IIPAssetRegistry { uint256 numIPAssets = 0; /// @notice Restricts calls to only being from the owner or IPOrg of an IP asset. + /// TODO(leeren): Add more cohesive authorization once the core alpha refactor is completed. modifier onlyAuthorized(uint256 id) { address ipOrg = ipAssets[id].ipOrg; address owner = ipAssets[id].owner; @@ -85,8 +86,9 @@ contract IPAssetRegistry is IIPAssetRegistry { /// @param status_ The new status of the IP asset. /// TODO(ramarti) Finalize authorization logic around the disputer. function setIPAssetStatus(uint256 ipAssetId_, uint8 status_) public onlyDisputer(ipAssetId_) { + uint8 oldStatus = ipAssets[ipAssetId_].status; ipAssets[ipAssetId_].status = status_; - emit IPAssetStatusChanged(ipAssetId_, status_); + emit IPAssetStatusChanged(ipAssetId_, oldStatus, status_); } /// @notice Transfers ownership of an IP asset to a new owner. diff --git a/contracts/interfaces/IIPAssetRegistry.sol b/contracts/interfaces/IIPAssetRegistry.sol index 2373a9d1..e17dc2e1 100644 --- a/contracts/interfaces/IIPAssetRegistry.sol +++ b/contracts/interfaces/IIPAssetRegistry.sol @@ -25,7 +25,8 @@ interface IIPAssetRegistry { /// @notice Emits when an IP asset has its status changed. event IPAssetStatusChanged( uint256 indexed ipAssetId_, - uint8 status_ + uint8 oldStatus_, + uint8 newStatus_ ); } diff --git a/contracts/ip-assets/IPAssetOrg.sol b/contracts/ip-assets/IPAssetOrg.sol index 1c2a04ac..b1b9edac 100644 --- a/contracts/ip-assets/IPAssetOrg.sol +++ b/contracts/ip-assets/IPAssetOrg.sol @@ -2,28 +2,20 @@ pragma solidity ^0.8.13; import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; -import { IIPAssetOrg } from "contracts/interfaces/ip-assets/IIPAssetOrg.sol"; -import { ICollectModule } from "contracts/interfaces/modules/collect/ICollectModule.sol"; import { IPAsset } from "contracts/lib/IPAsset.sol"; import { IPAssetOrgDataManager } from "./storage/IPAssetOrgDataManager.sol"; import { ERC721Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; -import { IERC165Upgradeable } from "@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol"; import { MulticallUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/MulticallUpgradeable.sol"; -import { RightsManager } from "../modules/licensing/RightsManager.sol"; import { IPAssetRegistry } from "contracts/IPAssetRegistry.sol"; -import { ILicensingModule } from "contracts/interfaces/modules/licensing/ILicensingModule.sol"; -import { Collect } from "contracts/lib/modules/Collect.sol"; import { Errors } from "contracts/lib/Errors.sol"; -import { Licensing } from "contracts/lib/modules/Licensing.sol"; /// @notice IP Asset Organization contract IPAssetOrg is + ERC721Upgradeable, IPAssetOrgDataManager, - RightsManager, MulticallUpgradeable, OwnableUpgradeable { - /// @custom:storage-location erc7201:story-protocol.ip-asset-org.storage // TODO: Refactor IP asset types to be specified through the IP Asset Registry or one of its modules. struct IPAssetOrgStorage { @@ -32,11 +24,11 @@ contract IPAssetOrg is } IPAssetRegistry public REGISTRY; - ILicensingModule public LICENSING_MODULE; - ICollectModule public COLLECT_MODULE; // keccak256(bytes.concat(bytes32(uint256(keccak256("story-protocol.ip-assets-registry.storage")) - 1))) - bytes32 private constant _STORAGE_LOCATION = 0x1a0b8fa444ff575656111a4368b8e6a743b70cbf31ffb9ee2c7afe1983f0e378; + bytes32 private constant _STORAGE_LOCATION = + 0x1a0b8fa444ff575656111a4368b8e6a743b70cbf31ffb9ee2c7afe1983f0e378; + string private constant _VERSION = "0.1.0"; // TODO(ramarti): Refactor to configure IP Asset types via registry modules. @@ -47,18 +39,14 @@ contract IPAssetOrg is return _VERSION; } - - function initialize(IPAsset.InitIPAssetOrgParams memory params_) public initializer { - - // TODO(ramarti) Decouple IPAssetOrg from the RightsManager and make sure to move `__ERC721_init` here. - __RightsManager_init(address(this), params_.name, params_.symbol); - + function initialize( + IPAsset.InitIPAssetOrgParams memory params_ + ) public initializer { __Multicall_init(); __Ownable_init(); // TODO: Weird bug does not allow OZ to specify owner in init... _transferOwnership(params_.owner); - if (params_.registry == address(0)) revert Errors.ZeroAddress(); REGISTRY = IPAssetRegistry(params_.registry); } @@ -72,61 +60,35 @@ contract IPAssetOrg is /// @return the created IP Asset id (and IP Asset org id). /// TODO(ramarti): Refactor licensing configuration to use registry asset ids instead of ip asset org ids. /// TODO(leeren): Deprecate returning of internal IP Asset org id once existing dependencies to it are removed. - function createIpAsset(IPAsset.CreateIpAssetParams calldata params_) public returns (uint256, uint256) { - if (params_.ipAssetType == IPAsset.IPAssetType.UNDEFINED) revert Errors.IPAsset_InvalidType(IPAsset.IPAssetType.UNDEFINED); + function createIpAsset( + IPAsset.CreateIpAssetParams calldata params_ + ) public returns (uint256, uint256) { + if (params_.ipAssetType == IPAsset.IPAssetType.UNDEFINED) { + revert Errors.IPAsset_InvalidType(IPAsset.IPAssetType.UNDEFINED); + } - IPAsset.RegisterIpAssetParams memory registrationParams = IPAsset.RegisterIpAssetParams({ - name: params_.name, - ipAssetType: 0, // TODO(ramarti): Replace with valid licensing type. - owner: params_.to, - ipOrg: address(this), - hash: "", - url: "", - data: "" - }); + IPAsset.RegisterIpAssetParams memory registrationParams = IPAsset + .RegisterIpAssetParams({ + name: params_.name, + ipAssetType: 0, // TODO(ramarti): Replace with valid licensing type. + owner: params_.to, + ipOrg: address(this), + hash: "", + url: "", + data: "" + }); // TODO: Add module and other relevant configuration for registration. uint256 ipAssetId = REGISTRY.register(registrationParams); uint256 ipAssetOrgId = _mintBlock(params_.to, params_.ipAssetType); - _writeIPAsset(ipAssetId, ipAssetOrgId, params_.name, params_.description, params_.mediaUrl); - IPAssetOrgStorage storage $ = _getIPAssetOrgStorage(); - - // Non commercial - // TODO(ramarti): Switch to configuration by IP Asset Registry id. - Licensing.IPAssetOrgConfig memory config = LICENSING_MODULE - .getIpAssetOrgConfig(address(this)); - if (config.revoker == address(0)) revert Errors.IPAssetOrg_LicensingNotConfigured(); - _setNonCommercialRights( + _writeIPAsset( + ipAssetId, ipAssetOrgId, - params_.parentIpAssetOrgId, - params_.to, - config.revoker, - config.nonCommercialConfig, - config.nonCommercialTerms + params_.name, + params_.description, + params_.mediaUrl ); - // If non derivative IpAsset, then franchise config may dictate commercial rights - // Derivative works do not have commercial rights unless a deal with the relevant licensor is made - if (config.rootIpAssetHasCommercialRights && params_.parentIpAssetOrgId == 0) { - // Commercial - _setCommercialRights( - ipAssetOrgId, - _ROOT_IP_ASSET, - params_.to, - config.revoker, - config.commercialLicenseUri, - config.commercialConfig, - config.commercialTerms - ); - } - // TODO(@leeren): Add collect NFT impl and other collect data overrides. - COLLECT_MODULE.initCollect( - Collect.InitCollectParams({ - ipAssetId: ipAssetId, - collectNftImpl: address(0), // Default collect module NFT impl - data: params_.collectData - }) - ); return (ipAssetId, ipAssetOrgId); } @@ -139,88 +101,6 @@ contract IPAssetOrg is return readIPAsset(tokenId_).mediaUrl; } - /// @notice Checks if the contract supports interface `interfaceId_`. - /// @param interfaceId_ The id of the interface being checked. - function supportsInterface( - bytes4 interfaceId_ - ) public - view - virtual - override(ERC721Upgradeable, IERC165Upgradeable) - returns (bool) - { - return - interfaceId_ == type(IIPAssetOrg).interfaceId || - super.supportsInterface(interfaceId_); - } - - /// Sets the non commercial rights for an IPAsset, with terms from the IPAssetOrg config in LicensingModule. - /// If no parent asset id is provided, the root IPAsset id is used if it exists in the IPAssetOrg config. - /// @param ipAssetOrgId_ the IPAsset id - /// @param parentIpAssetOrgId_ in case this is a derivative IPAsset, set the parent IPAsset id, 0 otherwise - /// @param holder_ of the IPAsset and licenses - /// @param revoker_ of the license. Can't be zero or changed later - /// @param config_ IPAssetOrg config - /// @param terms_ for the license to be active - /// TODO(ramarti): Refactor to support IP Asset configuration via the registry - deprecate use of ipAssetOrgId. - function _setNonCommercialRights( - uint256 ipAssetOrgId_, - uint256 parentIpAssetOrgId_, - address holder_, - address revoker_, - Licensing.IpAssetConfig memory config_, - Licensing.TermsProcessorConfig memory terms_ - ) internal { - uint256 parentLicenseId = parentIpAssetOrgId_ == 0 - ? config_.ipAssetOrgRootLicenseId - : getLicenseIdByTokenId(parentIpAssetOrgId_, false); - _createLicense( - ipAssetOrgId_, - parentLicenseId, - holder_, - LICENSING_MODULE.getNonCommercialLicenseURI(), - revoker_, - false, - config_.canSublicense, - terms_, - false - ); - } - - /// Sets the commercial rights for an IPAsset, with terms from the IPAssetOrg config in LicensingModule. - /// If no parent asset id is provided, the root IPAsset id is used if it exists in the IPAssetOrg config. - /// @param ipAssetOrgId_ the IP Asset org id - /// @param parentIpAssetOrgId_ in case this is a derivative IPAsset, set the parent IPAsset id, 0 otherwise - /// @param holder_ of the IPAsset and licenses - /// @param revoker_ of the license. Can't be zero or changed later - /// @param config_ IPAssetOrg config - /// @param terms_ for the license to be active - /// TODO(ramarti): Refactor to support ip asset registry ids instead of ip asset org ids. - function _setCommercialRights( - uint256 ipAssetOrgId_, - uint256 parentIpAssetOrgId_, - address holder_, - address revoker_, - string memory licenseUri_, - Licensing.IpAssetConfig memory config_, - Licensing.TermsProcessorConfig memory terms_ - ) internal { - uint256 parentLicenseId = parentIpAssetOrgId_ == _ROOT_IP_ASSET - ? config_.ipAssetOrgRootLicenseId - : getLicenseIdByTokenId(parentIpAssetOrgId_, true); - _createLicense( - ipAssetOrgId_, - parentLicenseId, - holder_, - licenseUri_, - revoker_, - true, - config_.canSublicense, - terms_, - false - ); - } - /// @notice Mints a new IP asset localized for the IP Asset Org. /// @param to_ Address of the owner of the IP Asset. /// @param ipAssetType_ Type of the IP Asset. @@ -230,7 +110,9 @@ contract IPAssetOrg is IPAsset.IPAssetType ipAssetType_ ) private returns (uint256) { uint256 nextId = currentIdFor(ipAssetType_) + 1; - if (nextId > IPAsset._lastId(ipAssetType_)) revert Errors.IPAssetOrg_IdOverBounds(); + if (nextId > IPAsset._lastId(ipAssetType_)) { + revert Errors.IPAssetOrg_IdOverBounds(); + } IPAssetOrgStorage storage $ = _getIPAssetOrgStorage(); $.idsByType[ipAssetType_] = nextId; _safeMint(to_, nextId); @@ -239,7 +121,9 @@ contract IPAssetOrg is /// @notice Gets the next id that a newly minted IP Asset corresponds to. /// @param ipAssetType_ The type of the IP Asset being queried. - function currentIdFor(IPAsset.IPAssetType ipAssetType_) public view returns (uint256) { + function currentIdFor( + IPAsset.IPAssetType ipAssetType_ + ) public view returns (uint256) { IPAssetOrgStorage storage $ = _getIPAssetOrgStorage(); uint256 currentId = $.idsByType[ipAssetType_]; if (currentId == 0) { diff --git a/contracts/lib/IPAsset.sol b/contracts/lib/IPAsset.sol index 14225921..dd8169c0 100644 --- a/contracts/lib/IPAsset.sol +++ b/contracts/lib/IPAsset.sol @@ -7,8 +7,7 @@ import { Errors } from "./Errors.sol"; /// @title IP Asset Library /// @notice Library for constants, structs, and helper functions for IP assets. library IPAsset { - - uint8 constant EXTERNAL_ASSET = type(uint8).max; + uint8 public constant EXTERNAL_ASSET = type(uint8).max; uint256 private constant _ID_RANGE = 10 ** 12; @@ -60,20 +59,28 @@ library IPAsset { } function _zeroId(IPAssetType ipAsset_) internal pure returns (uint256) { - if (ipAsset_ == IPAssetType.UNDEFINED) revert Errors.IPAsset_InvalidType(ipAsset_); + if (ipAsset_ == IPAssetType.UNDEFINED) { + revert Errors.IPAsset_InvalidType(ipAsset_); + } return _ID_RANGE * (uint256(ipAsset_) - 1); } function _lastId(IPAssetType ipAsset_) internal pure returns (uint256) { - if (ipAsset_ == IPAssetType.UNDEFINED) revert Errors.IPAsset_InvalidType(ipAsset_); + if (ipAsset_ == IPAssetType.UNDEFINED) { + revert Errors.IPAsset_InvalidType(ipAsset_); + } return (_ID_RANGE * uint256(ipAsset_)) - 1; } function _ipAssetTypeFor(uint256 id_) internal pure returns (IPAssetType) { // End of _ID_RANGE is zero (undefined) for each IPAsset // Also, we don't support ids higher than the last IPAsset enum item - if (id_ % _ID_RANGE == 0 || id_ > _ID_RANGE * (uint256(IPAssetType.ITEM))) + if ( + id_ % _ID_RANGE == 0 || + id_ > _ID_RANGE * (uint256(IPAssetType.ITEM)) + ) { return IPAssetType.UNDEFINED; + } return IPAsset.IPAssetType((id_ / _ID_RANGE) + 1); } }