Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IPOrg refactor for creation & registration #168

Merged
merged 9 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 84 additions & 67 deletions contracts/IPAssetRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,121 +2,138 @@
pragma solidity ^0.8.19;

import { IIPAssetRegistry } from "contracts/interfaces/IIPAssetRegistry.sol";
import { IRegistrationModule } from "contracts/interfaces/modules/registration/IRegistrationModule.sol";
import { IModuleRegistry } from "contracts/interfaces/modules/IModuleRegistry.sol";
import { IIPOrg } from "contracts/interfaces/ip-org/IIPOrg.sol";
import { ModuleRegistryKeys } from "contracts/lib/modules/ModuleRegistryKeys.sol";
import { Errors } from "contracts/lib/Errors.sol";
import { IPAsset } from "contracts/lib/IPAsset.sol";

/// @title Global IP Asset Registry
/// @notice The source of truth for IP on Story Protocol.
// TO-DO(@leeren): Migrate from consecutive ids to a global namehashing scheme.
contract IPAssetRegistry is IIPAssetRegistry {

/// @notice Core attributes that make up an IP Asset.
struct IPA {
string name; // Human-readable identifier for the IP asset.
uint64 ipAssetType; // Numerical code corresponding to IP type (e.g. patent, copyright, etc.)
address registrant; // Address of the initial registrant of the IP asset.
uint8 status; // Current status of the IP asset (e.g. active, expired, etc.)
address owner; // Address of the current owner of the IP asset.
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.
}

/// @notice Used for fetching modules associated with an IP asset.
IModuleRegistry public immutable MODULE_REGISTRY;

/// @notice Mapping from IP asset ids to registry records.
mapping(uint256 => IPA) public ipAssets;
mapping(uint256 => IPA) internal _ipAssets;

/// @notice Tracks the total number of IP Assets in existence.
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;
if (msg.sender != owner || msg.sender != ipOrg) {
/// TODO(leeren) Switch from numerical ids to a universal namehash.
uint256 totalSupply = 0;

/// @notice Restricts calls to the registration module of the IP Asset.
/// TODO(ramarti): Enable IPOrg-specific registration modules to be authorized.
modifier onlyRegistrationModule() {
if (MODULE_REGISTRY.protocolModule(ModuleRegistryKeys.REGISTRATION_MODULE) != msg.sender) {
revert Errors.Unauthorized();
}
_;
}

/// @notice Restricts calls to only being from the disputer of an IP asset.
/// @notice Restricts calls to only being from the disputer for an IP asset.
/// TODO(ramarti): Add authorization for calls that manage dispute lifecycle changes.
modifier onlyDisputer(uint256 id) {
_;
}

/// @notice Registers a new IP Asset.
/// @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) {
uint256 ipAssetId = numIPAssets++;
uint64 registrationDate = uint64(block.timestamp);
/// @notice Initializes the Global IP Asset Registry.
/// @param moduleRegistry_ Address of the module registry.
constructor(address moduleRegistry_) {
MODULE_REGISTRY = IModuleRegistry(moduleRegistry_);
}

/// @notice Registers a new IP asset.
/// @param registrant_ The initial registrant for the IP asset.
/// @param name_ A name given to describe the IP asset.
/// @param ipAssetType_ A numerical code corresponding to IP asset type.
/// @param hash_ A content hash used for verifyign provenance of the asset.
function register(
address registrant_,
string memory name_,
uint64 ipAssetType_,
bytes32 hash_
Ramarti marked this conversation as resolved.
Show resolved Hide resolved
) public onlyRegistrationModule returns (uint256 ipAssetId) {

if (MODULE_REGISTRY.protocolModule(ModuleRegistryKeys.REGISTRATION_MODULE) != msg.sender) {
revert Errors.Unauthorized();
}

ipAssets[ipAssetId] = IPA({
name: params_.name,
ipAssetType: params_.ipAssetType,
// Crate a new IP asset with the provided IP attributes.
ipAssetId = totalSupply++;
uint64 registrationDate = uint64(block.timestamp);
_ipAssets[ipAssetId] = IPA({
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,
registrationDate: registrationDate,
data: params_.data
registrant: registrant_,
ipOrg: msg.sender,
hash: hash_,
registrationDate: registrationDate
});

emit IPAssetRegistered(
emit Registered(
ipAssetId,
params_.ipAssetType,
params_.owner,
params_.ipOrg,
params_.hash
name_,
ipAssetType_,
msg.sender,
registrant_,
hash_
);

emit IPAssetTransferred(ipAssetId, address(0), params_.owner);

return ipAssetId;
}

/// @notice Changes the status of an IP asset..
/// @notice Changes the IP Org of an IP asset.
/// @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_) {
uint8 oldStatus = ipAssets[ipAssetId_].status;
ipAssets[ipAssetId_].status = status_;
emit IPAssetStatusChanged(ipAssetId_, oldStatus, status_);
/// @param ipOrg_ The new IP Org to govern the IP asset.
function transferIPOrg(uint256 ipAssetId_, address ipOrg_) public onlyRegistrationModule {
address oldIPOrg = _ipAssets[ipAssetId_].ipOrg;
_ipAssets[ipAssetId_].ipOrg = ipOrg_;
emit IPOrgTransferred(ipAssetId_, oldIPOrg, ipOrg_);
}

/// @notice Transfers ownership of an IP asset to a new owner.
/// @notice Changes the status of an IP asset.
/// @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_) {
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) {
return ipAssets[ipAssetId_].owner;
/// @param status_ The new status of the IP asset.
/// TODO(ramarti) Finalize authorization logic around status changes.
function setStatus(uint256 ipAssetId_, uint8 status_) public onlyDisputer(ipAssetId_) {
uint8 oldStatus = _ipAssets[ipAssetId_].status;
_ipAssets[ipAssetId_].status = status_;
emit StatusChanged(ipAssetId_, oldStatus, status_);
}

/// @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) {
return ipAssets[ipAssetId_].status;
function status(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.
/// @param ipAssetId_ The id of the IP asset being queried.
function ipAssetOrg(uint256 ipAssetId_) public view returns (address) {
return ipAssets[ipAssetId_].ipOrg;
return _ipAssets[ipAssetId_].ipOrg;
}

/// @notice Returns the current owner of an IP asset.
/// @param ipAssetId_ The id of the IP asset being queried.
function ipAssetOwner(uint256 ipAssetId_) public view returns (address) {
address registrationModule = MODULE_REGISTRY.protocolModule(ModuleRegistryKeys.REGISTRATION_MODULE);
return IRegistrationModule(registrationModule).ownerOf(ipAssetId_);
}

/// @notice Returns all attributes related to an IP asset.
/// @param ipAssetId_ The id of the IP asset being queried for.
function ipAsset(uint256 ipAssetId_) public view returns (IPA memory) {
return _ipAssets[ipAssetId_];
}

}
110 changes: 101 additions & 9 deletions contracts/StoryProtocol.sol
Original file line number Diff line number Diff line change
@@ -1,35 +1,127 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.19;

import { IIPOrgFactory } from "contracts/interfaces/ip-org/IIPOrgFactory.sol";
import { IIPOrgController } from "contracts/interfaces/ip-org/IIPOrgController.sol";
import { IIPOrg } from "contracts/interfaces/ip-org/IIPOrg.sol";
import { IPOrgParams } from "contracts/lib/IPOrgParams.sol";
import { Errors } from "contracts/lib/Errors.sol";
import { IPOrgParams } from "contracts/lib/IPOrgParams.sol";
import { ModuleRegistry } from "contracts/modules/ModuleRegistry.sol";
import { LibRelationship } from "contracts/lib/modules/LibRelationship.sol";
import { Registration } from "contracts/lib/modules/Registration.sol";
import { ModuleRegistryKeys } from "contracts/lib/modules/ModuleRegistryKeys.sol";

contract StoryProtocol {
// TODO: should this be immutable, or should the protocol be able to change factory
IIPOrgFactory public immutable FACTORY;

IIPOrgController public immutable IP_ORG_CONTROLLER;
ModuleRegistry public immutable MODULE_REGISTRY;

constructor(IIPOrgFactory ipOrgFactory_, ModuleRegistry moduleRegistry_) {
constructor(IIPOrgController ipOrgController_, ModuleRegistry moduleRegistry_) {
if (
address(ipOrgFactory_) == address(0) ||
address(ipOrgController_) == address(0) ||
address(moduleRegistry_) == address(0)
) {
revert Errors.ZeroAddress();
}
FACTORY = ipOrgFactory_;
IP_ORG_CONTROLLER = ipOrgController_;
MODULE_REGISTRY = moduleRegistry_;
}

////////////////////////////////////////////////////////////////////////////
// IPOrg //
////////////////////////////////////////////////////////////////////////////

/// @notice Sets the metadata for an IP Org.
/// @param ipOrg_ The address of the IP Org being configured.
/// @param baseURI_ The base token metadata URI for the IP Org.
/// @param contractURI_ The contract URI associated with the IP Org.
function setMetadata(
address ipOrg_,
string calldata baseURI_,
string calldata contractURI_
) public {
bytes memory encodedParams = abi.encode(
Registration.SET_IP_ORG_METADATA,
abi.encode(baseURI_, contractURI_)
);
MODULE_REGISTRY.configure(
IIPOrg(ipOrg_),
msg.sender,
ModuleRegistryKeys.REGISTRATION_MODULE,
encodedParams
);
}

/// @notice Registers a new IP Org
/// @param owner_ The address of the IP Org to be registered.
/// @param name_ A name to associate with the IP Org.
/// @param symbol_ A symbol to associate with the IP Org.
/// TODO: Add module configurations to the IP Org registration process.
/// TODO: Add permissions for IP Org registration.
function registerIpOrg(
IPOrgParams.RegisterIPOrgParams calldata params_
) external returns (address) {
return FACTORY.registerIpOrg(params_);
address owner_,
string calldata name_,
string calldata symbol_
) external returns (address ipOrg_) {
return IP_ORG_CONTROLLER.registerIpOrg(
owner_,
name_,
symbol_
);
}

/// @notice Transfers an IP asset to another owner.
/// @param ipOrg_ The governing IP Org under which the IP asset is registered.
/// @param params_ The registration params, including owner, name, hash.
/// @param preHooksData_ Hooks to embed with the registration pre-call.
/// @param postHooksData_ Hooks to embed with the registration post-call.
/// @return The global IP asset and local IP Org asset id.
function registerIPAsset(
address ipOrg_,
Registration.RegisterIPAssetParams calldata params_,
bytes[] calldata preHooksData_,
bytes[] calldata postHooksData_
) public returns (uint256, uint256) {
bytes memory encodedParams = abi.encode(
Registration.REGISTER_IP_ASSET,
abi.encode(params_)
);
bytes memory result = MODULE_REGISTRY.execute(
IIPOrg(ipOrg_),
msg.sender,
ModuleRegistryKeys.REGISTRATION_MODULE,
abi.encode(params_),
preHooksData_,
postHooksData_
);
return abi.decode(result, (uint256, uint256));
}

/// @notice Transfers an IP asset to another owner.
/// @param ipOrg_ The IP Org which the IP asset is associated with.
/// @param from_ The address of the current owner of the IP asset.
/// @param to_ The address of the new owner of the IP asset.
/// @param ipAssetId_ The global id of the IP asset being transferred.
function transferIPAsset(
address ipOrg_,
address from_,
address to_,
uint256 ipAssetId_,
bytes[] calldata preHooksData_,
bytes[] calldata postHooksData_
) public {
bytes memory encodedParams = abi.encode(
Registration.TRANSFER_IP_ASSET,
abi.encode(from_, to_, ipAssetId_)
);
bytes memory result = MODULE_REGISTRY.execute(
IIPOrg(ipOrg_),
msg.sender,
ModuleRegistryKeys.REGISTRATION_MODULE,
encodedParams,
preHooksData_,
postHooksData_
);
}

////////////////////////////////////////////////////////////////////////////
Expand Down
31 changes: 22 additions & 9 deletions contracts/interfaces/IIPAssetRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,40 @@ import { IPAsset } from "contracts/lib/IPAsset.sol";
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.19;

/// @title Global IP Asset Registry Contract Interface
/// @title Global IP Asset Registry Interface
interface IIPAssetRegistry {

/// @notice Emits when a new IP asset is registered.
event IPAssetRegistered(
/// @param ipAssetId_ The global IP asset identifier.
/// @param name_ The assigned name for the IP asset.
/// @param ipAssetType_ The status indicator for the IP asset.
/// @param ipOrg_ The registering governing body for the IP asset.
/// @param registrant_ The initial individual registrant of the IP asset.
/// @param hash_ The content hash associated with the IP asset.
event Registered(
uint256 ipAssetId_,
string name_,
uint64 indexed ipAssetType_,
address indexed owner_,
address indexed ipAssetOrg_,
address indexed ipOrg_,
address indexed registrant_,
bytes32 hash_
);

/// @notice Emits when an IP asset is transferred to a new owner.
event IPAssetTransferred(
/// @notice Emits when an IP asset is transferred to a new IP Org.
/// @param ipAssetId_ The identifier of the IP asset being transferred.
/// @param oldIPOrg_ The original administering IP Org of the IP asset.
/// @param newIPOrg_ The new administering IP Org of the IP asset.
event IPOrgTransferred(
uint256 indexed ipAssetId_,
address indexed from_,
address indexed to_
address indexed oldIPOrg_,
address indexed newIPOrg_
);

/// @notice Emits when an IP asset has its status changed.
event IPAssetStatusChanged(
/// @param ipAssetId_ The identifier of the IP asset whose status changed.
/// @param oldStatus_ The original status associated with the IP asset.
/// @param newStatus_ The new status associated with the IP asset.
event StatusChanged(
uint256 indexed ipAssetId_,
uint8 oldStatus_,
uint8 newStatus_
Expand Down
Loading