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

Adds IP registry and metadata resolver #7

Merged
merged 5 commits into from
Jan 20, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
34 changes: 34 additions & 0 deletions contracts/interfaces/erc6551/IERC6551Registry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IERC6551Registry {
leeren marked this conversation as resolved.
Show resolved Hide resolved

/// @notice Emits when a new ERC6551 account is created.
event AccountCreated(
address account,
address indexed implementation,
uint256 chainId,
address indexed tokenContract,
uint256 indexed tokenId,
uint256 salt
);

/// @notice Creates a new token-bound account for an NFT.
function createAccount(
address implementation,
uint256 chainId,
address tokenContract,
uint256 tokenId,
uint256 seed,
bytes calldata initData
) external returns (address);

/// @notice Retrieves the token-bound account address for an NFT.
function account(
address implementation,
uint256 chainId,
address tokenContract,
uint256 tokenId,
uint256 salt
) external view returns (address);
}
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 the token URI associated with the IP.
/// @param ipId The canonical ID of the specified IP.
function tokenURI(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 a token URI to associated with the IP.
/// @param ipId The canonical ID of the specified IP.
function setTokenURI(address ipId, string calldata tokenURI) external;
LeoHChen marked this conversation as resolved.
Show resolved Hide resolved

}
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 @@ -42,5 +70,4 @@ library Errors {
error AccessController__SignerIsZeroAddress();
error AccessController__CallerIsNotIPAccount();
error AccessController__PermissionIsNotValid();

}
}
43 changes: 43 additions & 0 deletions contracts/lib/IP.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// 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.
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 Resolved attributes not referenced here are processed through
/// their corresponding data modules (e.g. licensing for license data).
struct MetadataRecord {
leeren marked this conversation as resolved.
Show resolved Hide resolved
// 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