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

Commit

Permalink
Merge pull request #7 from leeren/feat/ip-registry-and-resolver
Browse files Browse the repository at this point in the history
Adds IP registry and metadata resolver
  • Loading branch information
leeren authored Jan 20, 2024
2 parents 1001bb7 + 0b3cc8a commit 5c716ae
Show file tree
Hide file tree
Showing 19 changed files with 1,364 additions and 147 deletions.
131 changes: 131 additions & 0 deletions contracts/interfaces/registries/IIPRecordRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.21;

/// @title IP Record Registry Interface
interface IIPRecordRegistry {

/// @notice Emits when an IP is officially registered into the protocol.
/// @param ipId The canonical identifier for the IP.
/// @param chainId The chain identifier of where the IP resides.
/// @param tokenContract The address of the IP.
/// @param tokenId The token identifier of the IP.
/// @param resolver The address of the resolver linked to the IP.
event IPRegistered(
address ipId,
uint256 indexed chainId,
address indexed tokenContract,
uint256 indexed tokenId,
address resolver
);

/// @notice Emits when an IP account is created for an IP.
/// @param ipId The canonical identifier for the IP.
/// @param chainId The chain identifier of where the IP resides.
/// @param tokenContract The address of the IP.
/// @param tokenId The token identifier of the IP.
event IPAccountSet(
address ipId,
uint256 indexed chainId,
address indexed tokenContract,
uint256 indexed tokenId
);

/// @notice Emits when an IP resolver is bound to an IP.
/// @param ipId The canonical identifier of the specified IP.
/// @param resolver The address of the new resolver bound to the IP.
event IPResolverSet(
address ipId,
address resolver
);

/// @notice Gets the canonical IP identifier associated with an IP (NFT).
/// @dev This is the same as the address of the IP account bound to the IP.
/// @param chainId The chain identifier of where the IP resides.
/// @param tokenContract The address of the IP.
/// @param tokenId The token identifier of the IP.
/// @return The address of the associated IP account.
function ipId(
uint256 chainId,
address tokenContract,
uint256 tokenId
) external view returns (address);

/// @notice Checks whether an IP was registered based on its ID.
/// @param id The canonical identifier for the IP.
/// @return Whether the IP was registered into the protocol.
function isRegistered(
address id
) external view returns (bool);

/// @notice Retrieves whether or not an IP was registered.
/// @param chainId The chain identifier of where the IP resides.
/// @param tokenContract The address of the IP.
/// @param tokenId The token identifier of the IP.
/// @return Whether the IP was registered into the protocol.
function isRegistered(
uint256 chainId,
address tokenContract,
uint256 tokenId
) external view returns (bool);

/// @notice Gets the resolver bound to an IP based on its ID.
/// @param id The canonical identifier for the IP.
/// @return The IP resolver address if registered, else the zero address.
function resolver(
address id
) external view returns (address);

/// @notice Gets the resolver bound to an IP based on its NFT attributes.
/// @param chainId The chain identifier of where the IP resides.
/// @param tokenContract The address of the IP.
/// @param tokenId The token identifier of the IP.
/// @return The IP resolver address if registered, else the zero address.
function resolver(
uint256 chainId,
address tokenContract,
uint256 tokenId
) external view returns (address);

/// @notice Registers an NFT as IP, creating a corresponding IP record.
/// @dev This is only callable by an authorized registration module.
/// @param chainId The chain identifier of where the IP resides.
/// @param tokenContract The address of the IP.
/// @param tokenId The token identifier of the IP.
/// @param createAccount Whether to create an IP account in the process.
function register(
uint256 chainId,
address tokenContract,
uint256 tokenId,
address resolverAddr,
bool createAccount
) external;

/// @notice Creates the IP account for the specified IP.
/// @param chainId The chain identifier of where the IP resides.
/// @param tokenContract The address of the IP.
/// @param tokenId The token identifier of the IP.
function createIPAccount(
uint256 chainId,
address tokenContract,
uint256 tokenId
) external returns (address);

/// @notice Sets the resolver for an IP based on its canonical ID.
/// @param id The canonical ID of the IP.
/// @param resolverAddr The address of the resolver being set.
function setResolver(address id, address resolverAddr) external;

/// @notice Sets the resolver for an IP based on its NFT attributes.
/// @dev This is only callable by an authorized registration module.
/// @param chainId The chain identifier of where the IP resides.
/// @param tokenContract The address of the IP.
/// @param tokenId The token identifier of the IP.
function setResolver(
uint256 chainId,
address tokenContract,
uint256 tokenId,
address resolver
) external;

}
68 changes: 68 additions & 0 deletions contracts/interfaces/resolvers/IIPMetadataResolver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.21;

import { IResolver } from "contracts/interfaces/resolvers/IResolver.sol";
import { IP } from "contracts/lib/IP.sol";

/// @notice Resolver Interface
interface IIPMetadataResolver is IResolver {

/// @notice Fetches core metadata attributed to a specific IP.
function metadata(address ipId) external view returns (IP.Metadata memory);

/// @notice Fetches the canonical name associated with the specified IP.
/// @param ipId The canonical ID of the specified IP.
function name(address ipId) external view returns (string memory);

/// @notice Fetches the description associated with the specified IP.
/// @param ipId The canonical ID of the specified IP.
/// @return The string descriptor of the IP.
function description(address ipId) external view returns (string memory);

/// @notice Fetches the keccak-256 hash associated with the specified IP.
/// @param ipId The canonical ID of the specified IP.
/// @return The bytes32 content hash of the IP.
function hash(address ipId) external view returns (bytes32);

/// @notice Fetches the date of registration of the IP.
/// @param ipId The canonical ID of the specified IP.
function registrationDate(address ipId) external view returns (uint64);

/// @notice Fetches the initial registrant of the IP.
/// @param ipId The canonical ID of the specified IP.
function registrant(address ipId) external view returns (address);

/// @notice Fetches the current owner of the IP.
/// @param ipId The canonical ID of the specified IP.
function owner(address ipId) external view returns (address);

/// @notice Fetches an IP owner defined URI associated with the IP.
/// @param ipId The canonical ID of the specified IP.
function uri(address ipId) external view returns (string memory);

/// @notice Sets the core metadata associated with an IP.
/// @param ipId The canonical ID of the specified IP.
/// @param data Metadata to be stored for the IP in the metadata resolver.
function setMetadata(address ipId, IP.MetadataRecord calldata data) external;

/// @notice Sets the name associated with an IP.
/// @param ipId The canonical ID of the specified IP.
/// @param name The string name to associate with the IP.
function setName(address ipId, string calldata name) external;

/// @notice Sets the description associated with an IP.
/// @param ipId The canonical ID of the specified IP.
/// @param description The string description to associate with the IP.
function setDescription(address ipId, string calldata description) external;

/// @notice Sets the keccak-256 hash associated with an IP.
/// @param ipId The canonical ID of the specified IP.
/// @param hash The keccak-256 hash to associate with the IP.
function setHash(address ipId, bytes32 hash) external;

/// @notice Sets an IP owner defined URI to associate with the IP.
/// @param ipId The canonical ID of the specified IP.
function setURI(address ipId, string calldata uri) external;

}
14 changes: 14 additions & 0 deletions contracts/interfaces/resolvers/IResolver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.21;

/// @notice Resolver Interface
interface IResolver {

/// @notice Gets the address of the access controller for the resolver.
function accessController() view external returns (address);

/// @notice Checks whether the resolver IP interface is supported.
function supportsInterface(bytes4 id) view external returns (bool);

}
41 changes: 34 additions & 7 deletions contracts/lib/Errors.sol
Original file line number Diff line number Diff line change
@@ -1,15 +1,43 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;
// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.19;

/// @title Errors Library
/// @notice Library for all Story Protocol contract errors.
library Errors {

////////////////////////////////////////////////////////////////////////////
// IPRecordRegistry //
////////////////////////////////////////////////////////////////////////////

/// @notice The IP record has already been registered.
error IPRecordRegistry_AlreadyRegistered();

/// @notice The IP account has already been created.
error IPRecordRegistry_IPAccountAlreadyCreated();

/// @notice The IP record has not yet been registered.
error IPRecordRegistry_NotYetRegistered();

/// @notice The specified IP resolver is not valid.
error IPRecordRegistry_ResolverInvalid();

/// @notice Caller not authorized to perform the IP registry function call.
error IPRecordRegistry_Unauthorized();

////////////////////////////////////////////////////////////////////////////
// IPResolver ///
////////////////////////////////////////////////////////////////////////////

/// @notice The targeted IP does not yet have an IP account.
error IPResolver_InvalidIP();

/// @notice Caller not authorized to perform the IP resolver function call.
error IPResolver_Unauthorized();

////////////////////////////////////////////////////////////////////////////
// LicenseRegistry //
////////////////////////////////////////////////////////////////////////////

/// @notice Error thrown when a policy is already set for an IP ID.
error LicenseRegistry__PolicyAlreadySetForIpId();
error LicenseRegistry__FrameworkNotFound();
Expand Down Expand Up @@ -44,5 +72,4 @@ library Errors {
error AccessController__SignerIsZeroAddress();
error AccessController__CallerIsNotIPAccount();
error AccessController__PermissionIsNotValid();

}
}
47 changes: 47 additions & 0 deletions contracts/lib/IP.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.21;

/// @title IP Library
/// @notice Library for constants, structs, and helper functions used for IP.
library IP {
/// @notice Core metadata associated with an IP.
/// @dev This is what is fetched when `metadata()` is called from an IP
/// resolver, and includes aggregated attributes fetched from various
/// modules in addition to that which is stored on the resolver itself.
struct Metadata {
// The current owner of the IP.
address owner;
// The name associated with the IP.
string name;
// A description associated with the IP.
string description;
// A keccak-256 hash of the IP content.
bytes32 hash;
// The date which the IP was registered.
uint64 registrationDate;
// The address of the initial IP registrant.
address registrant;
// The token URI associated with the IP.
string uri;
}

/// @notice Core metadata exclusively saved by the IP resolver.
/// @dev This only encompasses metadata which is stored on the IP metadata
/// resolver itself, and does not include those attributes which may
/// be fetched from different modules (e.g. the licensing modules).
struct MetadataRecord {
// The name associated with the IP.
string name;
// A description associated with the IP.
string description;
// A keccak-256 hash of the IP content.
bytes32 hash;
// The date which the IP was registered.
uint64 registrationDate;
// The address of the initial IP registrant.
address registrant;
// The token URI associated with the IP.
string uri;
}
}
6 changes: 6 additions & 0 deletions contracts/lib/modules/Module.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.21;

// String values for core protocol modules.
string constant REGISTRATION_MODULE_KEY = "REGISTRATION_MODULE";
8 changes: 4 additions & 4 deletions contracts/registries/IPAccountRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import { IERC6551Registry } from "lib/reference/src/interfaces/IERC6551Registry.
/// @notice This contract is responsible for managing the registration and tracking of IP Accounts.
/// It leverages a public ERC6551 registry to deploy IPAccount contracts.
contract IPAccountRegistry is IIPAccountRegistry {
address internal immutable IP_ACCOUNT_IMPL;
bytes32 internal immutable IP_ACCOUNT_SALT;
address internal immutable ERC6551_PUBLIC_REGISTRY;
address internal immutable ACCESS_CONTROLLER;
address public immutable IP_ACCOUNT_IMPL;
bytes32 public immutable IP_ACCOUNT_SALT;
address public immutable ERC6551_PUBLIC_REGISTRY;
address public immutable ACCESS_CONTROLLER;

error NonExistIpAccountImpl();

Expand Down
Loading

0 comments on commit 5c716ae

Please sign in to comment.