Skip to content

Commit

Permalink
Adds scaffolding for metadata rendering and ip asset creation
Browse files Browse the repository at this point in the history
  • Loading branch information
leeren committed Nov 10, 2023
1 parent f40f880 commit 67349e1
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 77 deletions.
33 changes: 17 additions & 16 deletions contracts/IPAssetRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ contract IPAssetRegistry is IIPAssetRegistry {
address initialRegistrant; // Address of the initial registrant of the IP asset.
address ipOrg; // Address of the governing entity of the IP asset.
bytes32 hash; // A unique content hash of the IP asset for preserving integrity.
string url; // URL linked to additional metadata for the IP asset.
uint64 registrationDate; // Timestamp for which the IP asset was first registered.
bytes data; // Any additional data to be tied to the IP asset.
}

uint256 public immutable IP_ORG_CONTROLLER;
Expand Down Expand Up @@ -63,21 +61,24 @@ contract IPAssetRegistry is IIPAssetRegistry {
/// @param params_ The IP asset registration parameters.
// TODO(ramarti): Add registration authorization via registration module.
// TODO(ramarti): Include module parameters and interfacing to registration.
function register(IPAsset.RegisterIpAssetParams calldata params_) public returns (uint256) {
function register(
address owner_,
string name_,
uint64 ipAssetType_,
bytes32 hash_
) public returns (uint256) {
uint256 ipAssetId = numIPAssets++;
uint64 registrationDate = uint64(block.timestamp);

ipAssets[ipAssetId] = IPA({
name: params_.name,
ipAssetType: params_.ipAssetType,
name: name_,
ipAssetType: ipAssetType_,
status: 0, // TODO(ramarti): Define status types.
owner: params_.owner,
initialRegistrant: params_.owner,
ipOrg: params_.ipOrg,
hash: params_.hash,
url: params_.url,
owner: owner_,
initialRegistrant: owner_,
ipOrg: msg.sender,
hash: hash_,
registrationDate: registrationDate,
data: params_.data
});

emit IPAssetRegistered(
Expand All @@ -97,7 +98,7 @@ contract IPAssetRegistry is IIPAssetRegistry {
/// @param ipAssetId_ The identifier of the IP asset being transferred.
/// @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_) {
function setStatus(uint256 ipAssetId_, uint8 status_) public onlyDisputer(ipAssetId_) {
uint8 oldStatus = ipAssets[ipAssetId_].status;
ipAssets[ipAssetId_].status = status_;
emit IPAssetStatusChanged(ipAssetId_, oldStatus, status_);
Expand All @@ -107,27 +108,27 @@ contract IPAssetRegistry is IIPAssetRegistry {
/// @param ipAssetId_ The identifier of the IP asset being transferred.
/// @param owner_ The new owner of the IP asset.
/// TODO(leeren) Add authorization around IPOrg transferring rights.
function setIPAssetOwner(uint256 ipAssetId_, address owner_) public onlyAuthorized(ipAssetId_) {
function setOwner(uint256 ipAssetId_, address owner_) public onlyAuthorized(ipAssetId_) {
address prevOwner = ipAssets[ipAssetId_].owner;
ipAssets[ipAssetId_].owner = owner_;
emit IPAssetTransferred(ipAssetId_, prevOwner, owner_);
}

/// @notice Gets the owner of a specific IP Asset.
/// @param ipAssetId_ The id of the IP Asset being queried.
function ipAssetOwner(uint256 ipAssetId_) public view returns (address) {
function getOwner(uint256 ipAssetId_) public view returns (address) {
return ipAssets[ipAssetId_].owner;
}

/// @notice Gets the status for a specific IP Asset.
/// @param ipAssetId_ The id of the IP Asset being queried.
function ipAssetStatus(uint256 ipAssetId_) public view returns (uint8) {
function getStatus(uint256 ipAssetId_) public view returns (uint8) {
return ipAssets[ipAssetId_].status;
}

/// @notice Gets the IP Asset Org that administers a specific IP Asset.
/// @param ipAssetId_ The id of the IP Asset being queried.
function ipAssetOrg(uint256 ipAssetId_) public view returns (address) {
function getIPOrg(uint256 ipAssetId_) public view returns (address) {
return ipAssets[ipAssetId_].ipOrg;
}

Expand Down
113 changes: 63 additions & 50 deletions contracts/ip-org/IPOrg.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,36 @@ import { IIPOrg } from "contracts/interfaces/ip-org/IIPOrg.sol";
import { IPOrgParams } from "contracts/lib/IPOrgParams.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 { IPAssetRegistry } from "contracts/IPAssetRegistry.sol";
import { ModuleRegistryKeys } from "contracts/lib/modules/ModuleRegistryKeys.sol";
import { Errors } from "contracts/lib/Errors.sol";

/// @notice IP Asset Organization
/// TODO(leeren): Deprecate upgradeability once the IPOrg contracts is finalized.
contract IPOrg is
IIPOrg,
ERC721Upgradeable,
MulticallUpgradeable
ERC721Upgradeable
{

struct IPOrgAsset {
uint256 ipAssetId;
string name;
string description;
}

/// @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 IPOrgStorage {
}
/// @notice Tracks the total number of IP Assets owned by the org.
uint256 numIPAssets = 0;

// Address of the module regisry.
address private immutable _moduleRegistry;

// Address of the IP Org Controller.
address private immutable controller;
// Address of the Global IP Asset Registry
address private immutable registry;
address private immutable _controller;

// keccak256(bytes.concat(bytes32(uint256(keccak256("story-protocol.ip-org-registry.storage")) - 1)))
bytes32 private constant _STORAGE_LOCATION = bytes32(uint256(keccak256("story-protocol.ip-org.storage")) - 1);
// Address of the Global IP Asset Registry (GIPR).
address private immutable _registry;

/// @notice Restricts calls to being through the registration module.
modifier onlyRegistrationModule() {
if (IModuleRegistry(_moduleRegistry).protocolModules(ModuleRegistryKeys.REGISTRATION_MODULE) != msg.sender) {
revert Errors.Unauthorized();
}
_;
}

/// @notice Creates the IP Org implementation contract.
/// @param ipAssetRegistry_ Address of the Global IP Asset Registry.
Expand All @@ -46,6 +46,20 @@ contract IPOrg is
registry = ipAssetRegistry;
}

/// @notice Retrieves the current owner of the IP Org.
function owner() external {
return IP_ASSET_CONTROLLER.ownerOf(msg.sender);
}

/// @notice Retrieves the token URI for an IP Asset within the IP Asset Org.
/// @param tokenId_ The id of the IP Asset within the IP Asset Org.
function tokenURI(
uint256 tokenId_
) public view override returns (string memory) {
address registrationModule = IModuleRegistry(_moduleRegistry).protocolModules(ModuleRegistryKeys.REGISTRATION_MODULE);
return IRegistrationModule(registrationModule).renderMetadata(msg.sender, tokenId_);
}

/// @notice Initializes an IP Org.
/// @param name_ Name to assign to the IP Org.
/// @param symbol_ Symbol to assign to the IP Org.
Expand All @@ -64,43 +78,42 @@ contract IPOrg is

__ERC721_init(params_.name, params_.symbol);

__Multicall_init();
__Ownable_init();
}

function createIpAsset(IPAsset.CreateIpAssetParams calldata params_) public returns (uint256, uint256) {
if (params_.ipAssetType == IPAsset.IPAssetType.UNDEFINED) revert Errors.IPAsset_InvalidType(IPAsset.IPAssetType.UNDEFINED);
// TODO: Add module and other relevant configuration for registration.
uint256 ipAssetId = REGISTRY.register(msg.sender, address(this));
uint256 ipAssetOrgId = _mintBlock(params_.to, params_.ipAssetType);
_writeIPAsset(ipAssetId, ipAssetOrgId, params_.name, params_.description, params_.mediaUrl);
IPAssetOrgStorage storage $ = _getIPAssetOrgStorage();

return (ipAssetId, ipAssetOrgId);
}

/// @notice Retrieves the token URI for an IP Asset within the IP Asset Org.
/// @param tokenId_ The id of the IP Asset within the IP Asset Org.
function tokenURI(
uint256 tokenId_
) public view override returns (string memory) {
// TODO: should this reference the license too?
return "TODO";
}

/// @notice Retrieves the current owner of the IP Org.
function owner() external {
return IP_ASSET_CONTROLLER.ownerOf(msg.sender);
/// @notice Registers a new IP Asset for the IP Org.
/// TODO(leeren) Change ownership attribution to track the GIPR directly.
/// This will be changed once ownership attribution of GIPR and IPOrg Assets are better defined.
function register(
address owner_,
string name_,
uint64 ipAssetType_,
bytes32 hash_
) onlyRegistrationModule returns (uint256 registryId, uint256 id) {
registryId = IPAssetRegistry(_registry).register(
owner_,
name_,
ipAssetType_,
hash_,
);
id = numIPAssets++;
_mint(owner, id);
registryIds[id] = registryId;
}

/// @dev Gets the storage associated with the IPOrg contract.
function _getIPOrgStorage()
private
pure
returns (IPOrgStorage storage $)
{
assembly {
$.slot := _STORAGE_LOCATION
/// @notice Transfers ownership of an IP Asset to the new owner.
function transferFrom(
address from,
address to,
uint256 id
) public override onlyRegistrationModule {
if (to == address(0)) {
revert Errors.ZeroAddress();
}
address prevOwner = _update(to, id, address(0));
if (prevOwner != from) {
revert Errors.Unauthorized();
}
}

}
3 changes: 0 additions & 3 deletions contracts/lib/IPAsset.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,7 @@ library IPAsset {
string name;
uint64 ipAssetType;
address owner;
address ipOrg;
bytes32 hash;
string url;
bytes data;
}

struct CreateIpAssetParams {
Expand Down
1 change: 1 addition & 0 deletions contracts/lib/modules/ModuleRegistryKeys.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ pragma solidity ^0.8.19;
library ModuleRegistryKeys {
string public constant RELATIONSHIP_MODULE = "RELATIONSHIP_MODULE";
string public constant LICENSING_MODULE = "LICENSING_MODULE";
string public constant REGISTRATION_MODULE = "REGISTRATION_MODULE";
}
16 changes: 16 additions & 0 deletions contracts/lib/modules/Registration.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.19;

/// @title Relationship Module Library
library Registration {

struct RegisterIPAParams {
address owner;
string name;
uint64 ipAssetType;
bytes32 hash;
}

bytes32 public constant ADD_METADATA_RENDERER_TYPE_CONFIG = keccak256("ADD_REL_TYPE");
bytes32 public constant REMOVE_REL_TYPE_CONFIG = keccak256("REMOVE_REL_TYPE");
}
16 changes: 8 additions & 8 deletions contracts/modules/ModuleRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ contract ModuleRegistry is AccessControlled, Multicall {
bytes params
);

mapping(string => BaseModule) private _protocolModules;
mapping(string => BaseModule) public protocolModules;

address public constant PROTOCOL_LEVEL = address(0);

Expand All @@ -49,7 +49,7 @@ contract ModuleRegistry is AccessControlled, Multicall {
if (address(moduleAddress) == address(0)) {
revert Errors.ZeroAddress();
}
_protocolModules[moduleKey] = moduleAddress;
protocolModules[moduleKey] = moduleAddress;
emit ModuleAdded(PROTOCOL_LEVEL, moduleKey, moduleAddress);
}

Expand All @@ -59,17 +59,17 @@ contract ModuleRegistry is AccessControlled, Multicall {
function removeProtocolModule(
string calldata moduleKey
) external onlyRole(AccessControl.MODULE_REGISTRAR_ROLE) {
if (address(_protocolModules[moduleKey]) == address(0)) {
if (address(protocolModules[moduleKey]) == address(0)) {
revert Errors.ModuleRegistry_ModuleNotRegistered(moduleKey);
}
BaseModule moduleAddress = _protocolModules[moduleKey];
delete _protocolModules[moduleKey];
BaseModule moduleAddress = protocolModules[moduleKey];
delete protocolModules[moduleKey];
emit ModuleRemoved(PROTOCOL_LEVEL, moduleKey, moduleAddress);
}

/// Get a module from the protocol, by its key.
function moduleForKey(string calldata moduleKey) external view returns (BaseModule) {
return _protocolModules[moduleKey];
return protocolModules[moduleKey];
}

/// Execution entrypoint, callable by any address on its own behalf.
Expand Down Expand Up @@ -142,7 +142,7 @@ contract ModuleRegistry is AccessControlled, Multicall {
bytes[] calldata preHookParams_,
bytes[] calldata postHookParams_
) private returns (bytes memory result) {
BaseModule module = _protocolModules[moduleKey_];
BaseModule module = protocolModules[moduleKey_];
if (address(module) == address(0)) {
revert Errors.ModuleRegistry_ModuleNotRegistered(moduleKey_);
}
Expand All @@ -160,7 +160,7 @@ contract ModuleRegistry is AccessControlled, Multicall {
// if (IIPOrg(ipOrg_).owner() != msg.sender) {
// revert Errors.ModuleRegistry_CallerNotOrgOwner();
//}
BaseModule module = _protocolModules[moduleKey_];
BaseModule module = protocolModules[moduleKey_];
if (address(module) == address(0)) {
revert Errors.ModuleRegistry_ModuleNotRegistered(moduleKey_);
}
Expand Down
1 change: 1 addition & 0 deletions contracts/modules/base/BaseModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { IPAssetRegistry } from "contracts/IPAssetRegistry.sol";
/// @dev This contract should NOT have state in storage, in order to have upgradeable or non-upgradeable
/// modules.
abstract contract BaseModule is IModule, HookRegistry {

struct ModuleConstruction {
IPAssetRegistry ipaRegistry;
ModuleRegistry moduleRegistry;
Expand Down
1 change: 1 addition & 0 deletions contracts/modules/base/HookRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity ^0.8.13;
import { Errors } from "contracts/lib/Errors.sol";

abstract contract HookRegistry {

enum HookType {
PreAction,
PostAction
Expand Down
Loading

0 comments on commit 67349e1

Please sign in to comment.