Skip to content

Commit

Permalink
Merge branch 'dev' into refactor_licensing
Browse files Browse the repository at this point in the history
  • Loading branch information
Raul committed Nov 15, 2023
2 parents 703494e + c1dee85 commit dba7cd0
Show file tree
Hide file tree
Showing 41 changed files with 1,643 additions and 716 deletions.
147 changes: 82 additions & 65 deletions contracts/IPAssetRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,111 +2,128 @@
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 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 => IPAsset.IPA) public ipAssets;
mapping(uint256 => IPAsset.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_
) public onlyRegistrationModule returns (uint256 ipAssetId) {

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

ipAssets[ipAssetId] = IPAsset.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] = IPAsset.IPA({
name: name_,
ipAssetType: ipAssetType_,
status: 1, // 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_);
}

function getIpAsset(uint256 ipAssetId_) external view returns (IPAsset.IPA memory) {
return ipAssets[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 (IPAsset.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,36 +1,128 @@
// 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";
import { Licensing } from "contracts/lib/modules/Licensing.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

0 comments on commit dba7cd0

Please sign in to comment.