Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 35,458 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
Amount
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Register Root Ip | 8495047 | 227 days ago | IN | 0 ETH | 0.00067494 | ||||
| Register Root Ip | 6923282 | 454 days ago | IN | 0 ETH | 0.00122044 | ||||
| Register Root Ip | 6594696 | 508 days ago | IN | 0 ETH | 0.03913505 | ||||
| Register Root Ip | 6594311 | 508 days ago | IN | 0 ETH | 0.02098479 | ||||
| Register Root Ip | 6565923 | 513 days ago | IN | 0 ETH | 0.00211199 | ||||
| Register Root Ip | 6565923 | 513 days ago | IN | 0 ETH | 0.00211258 | ||||
| Register Root Ip | 6565923 | 513 days ago | IN | 0 ETH | 0.00211239 | ||||
| Register Root Ip | 6565923 | 513 days ago | IN | 0 ETH | 0.00211226 | ||||
| Register Root Ip | 6565923 | 513 days ago | IN | 0 ETH | 0.00211232 | ||||
| Register Root Ip | 6565923 | 513 days ago | IN | 0 ETH | 0.00211213 | ||||
| Register Root Ip | 6565923 | 513 days ago | IN | 0 ETH | 0.00211219 | ||||
| Register Root Ip | 6565923 | 513 days ago | IN | 0 ETH | 0.00211213 | ||||
| Register Root Ip | 6565923 | 513 days ago | IN | 0 ETH | 0.00211213 | ||||
| Register Root Ip | 6565923 | 513 days ago | IN | 0 ETH | 0.00211199 | ||||
| Register Root Ip | 6565923 | 513 days ago | IN | 0 ETH | 0.00211245 | ||||
| Register Root Ip | 6565923 | 513 days ago | IN | 0 ETH | 0.00211213 | ||||
| Register Root Ip | 6565922 | 513 days ago | IN | 0 ETH | 0.00220205 | ||||
| Register Root Ip | 6565922 | 513 days ago | IN | 0 ETH | 0.00220246 | ||||
| Register Root Ip | 6565922 | 513 days ago | IN | 0 ETH | 0.00220205 | ||||
| Register Root Ip | 6565922 | 513 days ago | IN | 0 ETH | 0.00220225 | ||||
| Register Root Ip | 6565921 | 513 days ago | IN | 0 ETH | 0.00221744 | ||||
| Register Root Ip | 6565921 | 513 days ago | IN | 0 ETH | 0.00221785 | ||||
| Register Root Ip | 6565921 | 513 days ago | IN | 0 ETH | 0.00221764 | ||||
| Register Root Ip | 6565921 | 513 days ago | IN | 0 ETH | 0.00221737 | ||||
| Register Root Ip | 6565921 | 513 days ago | IN | 0 ETH | 0.00015564 |
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers.
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
To
|
Amount
|
|||
|---|---|---|---|---|---|---|---|---|
| Transfer* | 8495047 | 227 days ago | 0 ETH | |||||
| Transfer* | 8495047 | 227 days ago | 0 ETH | |||||
| Transfer* | 6923282 | 454 days ago | 0 ETH | |||||
| Transfer* | 6923282 | 454 days ago | 0 ETH | |||||
| Transfer* | 6594696 | 508 days ago | 0 ETH | |||||
| Transfer* | 6594696 | 508 days ago | 0 ETH | |||||
| Transfer* | 6594311 | 508 days ago | 0 ETH | |||||
| Transfer* | 6594311 | 508 days ago | 0 ETH | |||||
| Transfer* | 6565923 | 513 days ago | 0 ETH | |||||
| Transfer* | 6565923 | 513 days ago | 0 ETH | |||||
| Transfer* | 6565923 | 513 days ago | 0 ETH | |||||
| Transfer* | 6565923 | 513 days ago | 0 ETH | |||||
| Transfer* | 6565923 | 513 days ago | 0 ETH | |||||
| Transfer* | 6565923 | 513 days ago | 0 ETH | |||||
| Transfer* | 6565923 | 513 days ago | 0 ETH | |||||
| Transfer* | 6565923 | 513 days ago | 0 ETH | |||||
| Transfer* | 6565923 | 513 days ago | 0 ETH | |||||
| Transfer* | 6565923 | 513 days ago | 0 ETH | |||||
| Transfer* | 6565923 | 513 days ago | 0 ETH | |||||
| Transfer* | 6565923 | 513 days ago | 0 ETH | |||||
| Transfer* | 6565923 | 513 days ago | 0 ETH | |||||
| Transfer* | 6565923 | 513 days ago | 0 ETH | |||||
| Transfer* | 6565923 | 513 days ago | 0 ETH | |||||
| Transfer* | 6565923 | 513 days ago | 0 ETH | |||||
| Transfer* | 6565923 | 513 days ago | 0 ETH |
Loading...
Loading
Loading...
Loading
Contract Name:
RegistrationModule
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 20000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import { IPResolver } from "../resolvers/IPResolver.sol";
import { IRegistrationModule } from "../interfaces/modules/IRegistrationModule.sol";
import { REGISTRATION_MODULE_KEY } from "../lib/modules/Module.sol";
import { Errors } from "../lib/Errors.sol";
import { IP } from "../lib/IP.sol";
import { BaseModule } from "../modules/BaseModule.sol";
import { ILicensingModule } from "../interfaces/modules/licensing/ILicensingModule.sol";
import { IIPAssetRegistry } from "../interfaces/registries/IIPAssetRegistry.sol";
/// @title Registration Module
/// @notice The registration module is responsible for registration of IP into
/// the protocol. During registration, this module will register an IP
/// into the protocol, create a resolver, and bind to it any licenses
/// and terms specified by the IP registrant (IP account owner).
contract RegistrationModule is BaseModule, IRegistrationModule {
string public constant override name = REGISTRATION_MODULE_KEY;
/// @notice Returns the metadata resolver used by the registration module.
IPResolver public ipResolver;
/// @dev The canonical protocol-wide IP Asset Registry
IIPAssetRegistry private _IP_ASSET_REGISTRY;
/// @dev The canonical protocol-wide Licensing Module
ILicensingModule private _LICENSING_MODULE;
constructor(address assetRegistry, address licensingModule, address resolverAddr) {
ipResolver = IPResolver(resolverAddr);
_LICENSING_MODULE = ILicensingModule(licensingModule);
_IP_ASSET_REGISTRY = IIPAssetRegistry(assetRegistry);
}
// TODO: Rethink the semantics behind "root-level IPs" vs. "normal IPs".
// TODO: Update function parameters to utilize a struct instead.
// TODO: Revisit requiring binding an existing NFT to a "root-level IP".
// If root-level IPs are an organizational primitive, why require NFTs?
// TODO: Change to a different resolver optimized for root IP metadata.
/// @notice Registers a root-level IP into the protocol. Root-level IPs can be thought of as organizational hubs
/// for encapsulating policies that actual IPs can use to register through. As such, a root-level IP is not an
/// actual IP, but a container for IP policy management for their child IP assets.
/// @param policyId The policy that identifies the licensing terms of the IP.
/// @param tokenContract The address of the NFT bound to the root-level IP.
/// @param tokenId The token id of the NFT bound to the root-level IP.
/// @param ipName The name assigned to the new IP.
/// @param contentHash The content hash of the IP being registered.
/// @param externalURL An external URI to link to the IP.
function registerRootIp(
uint256 policyId,
address tokenContract,
uint256 tokenId,
string memory ipName,
bytes32 contentHash,
string calldata externalURL
) external returns (address) {
// Perform registrant authorization.
// Check that the caller is authorized to perform the registration.
// TODO: Perform additional registration authorization logic, allowing
// registrants or root-IP creators to specify their own auth logic.
address owner = IERC721(tokenContract).ownerOf(tokenId);
if (msg.sender != owner && !IERC721(tokenContract).isApprovedForAll(owner, msg.sender)) {
revert Errors.RegistrationModule__InvalidOwner();
}
bytes memory metadata = abi.encode(
IP.MetadataV1({
name: ipName,
hash: contentHash,
registrationDate: uint64(block.timestamp),
registrant: msg.sender,
uri: externalURL
})
);
// Perform core IP registration and IP account creation.
address ipId = _IP_ASSET_REGISTRY.register(
block.chainid,
tokenContract,
tokenId,
address(ipResolver),
true,
metadata
);
// Perform core IP policy creation.
if (policyId != 0) {
// If we know the policy ID, we can register it directly on creation.
// TODO: return policy index
_LICENSING_MODULE.addPolicyToIp(ipId, policyId);
}
emit RootIPRegistered(msg.sender, ipId, policyId);
return ipId;
}
// TODO: Replace all metadata with a generic bytes parameter type, and do encoding on the periphery contract
// level instead.
/// @notice Registers derivative IPs into the protocol. Derivative IPs are IP assets that inherit policies from
/// parent IPs by burning acquired license NFTs.
/// @param licenseIds The licenses to incorporate for the new IP.
/// @param tokenContract The address of the NFT bound to the derivative IP.
/// @param tokenId The token id of the NFT bound to the derivative IP.
/// @param ipName The name assigned to the new IP.
/// @param contentHash The content hash of the IP being registered.
/// @param externalURL An external URI to link to the IP.
/// @param royaltyContext The royalty context for the derivative IP.
/// TODO: Replace all metadata with a generic bytes parameter type, and do
/// encoding on the periphery contract level instead.
function registerDerivativeIp(
uint256[] calldata licenseIds,
address tokenContract,
uint256 tokenId,
string memory ipName,
bytes32 contentHash,
string calldata externalURL,
bytes calldata royaltyContext
) external {
// Check that the caller is authorized to perform the registration.
// TODO: Perform additional registration authorization logic, allowing
// registrants or IP creators to specify their own auth logic.
address owner = IERC721(tokenContract).ownerOf(tokenId);
if (msg.sender != owner && !IERC721(tokenContract).isApprovedForAll(owner, msg.sender)) {
revert Errors.RegistrationModule__InvalidOwner();
}
bytes memory metadata = abi.encode(
IP.MetadataV1({
name: ipName,
hash: contentHash,
registrationDate: uint64(block.timestamp),
registrant: msg.sender,
uri: externalURL
})
);
address ipId = _IP_ASSET_REGISTRY.register(
block.chainid,
tokenContract,
tokenId,
address(ipResolver),
true,
metadata
);
// Perform core IP derivative licensing - the license must be owned by the caller.
_LICENSING_MODULE.linkIpToParents(licenseIds, ipId, royaltyContext);
emit DerivativeIPRegistered(msg.sender, ipId, licenseIds);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
* {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { ResolverBase } from "./ResolverBase.sol";
import { KeyValueResolver } from "../resolvers/KeyValueResolver.sol";
import { IP_RESOLVER_MODULE_KEY } from "../lib/modules/Module.sol";
/// @title IP Resolver
/// @notice Canonical IP resolver contract used for Story Protocol.
/// TODO: Add support for interface resolvers, where one can add a contract
/// and supported interface (address, interfaceId) to tie to an IP asset.
/// TODO: Add support for multicall, so multiple records may be set at once.
contract IPResolver is KeyValueResolver {
string public constant override name = IP_RESOLVER_MODULE_KEY;
constructor(address accessController, address ipAssetRegistry) ResolverBase(accessController, ipAssetRegistry) {}
/// @notice IERC165 interface support.
function supportsInterface(bytes4 id) public view virtual override returns (bool) {
return super.supportsInterface(id);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { IPResolver } from "../../resolvers/IPResolver.sol";
interface IRegistrationModule {
/// @notice Emitted when a root-level IP is registered.
/// @param caller The address of the caller.
/// @param ipId The address of the IP that was registered.
/// @param policyId The policy that identifies the licensing terms of the IP.
event RootIPRegistered(address indexed caller, address indexed ipId, uint256 indexed policyId);
/// @notice Emitted when a derivative IP is registered.
/// @param caller The address of the caller.
/// @param ipId The address of the IP that was registered.
/// @param licenseIds The licenses that were used to register the derivative IP.
event DerivativeIPRegistered(address indexed caller, address indexed ipId, uint256[] licenseIds);
/// @notice Returns the metadata resolver used by the registration module.
function ipResolver() external view returns (IPResolver);
/// @notice Registers a root-level IP into the protocol. Root-level IPs can be thought of as organizational hubs
/// for encapsulating policies that actual IPs can use to register through. As such, a root-level IP is not an
/// actual IP, but a container for IP policy management for their child IP assets.
/// @param policyId The policy that identifies the licensing terms of the IP.
/// @param tokenContract The address of the NFT bound to the root-level IP.
/// @param tokenId The token id of the NFT bound to the root-level IP.
/// @param ipName The name assigned to the new IP.
/// @param contentHash The content hash of the IP being registered.
/// @param externalURL An external URI to link to the IP.
function registerRootIp(
uint256 policyId,
address tokenContract,
uint256 tokenId,
string memory ipName,
bytes32 contentHash,
string calldata externalURL
) external returns (address);
/// @notice Registers derivative IPs into the protocol. Derivative IPs are IP assets that inherit policies from
/// parent IPs by burning acquired license NFTs.
/// @param licenseIds The licenses to incorporate for the new IP.
/// @param tokenContract The address of the NFT bound to the derivative IP.
/// @param tokenId The token id of the NFT bound to the derivative IP.
/// @param ipName The name assigned to the new IP.
/// @param contentHash The content hash of the IP being registered.
/// @param externalURL An external URI to link to the IP.
/// @param royaltyContext The royalty context for the derivative IP.
function registerDerivativeIp(
uint256[] calldata licenseIds,
address tokenContract,
uint256 tokenId,
string memory ipName,
bytes32 contentHash,
string calldata externalURL,
bytes calldata royaltyContext
) external;
}// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; // Default Module Type, all modules in this type by default string constant MODULE_TYPE_DEFAULT = "MODULE"; string constant MODULE_TYPE_HOOK = "HOOK_MODULE"; // String values for core protocol modules. string constant IP_RESOLVER_MODULE_KEY = "IP_RESOLVER_MODULE"; // String values for core protocol modules. string constant REGISTRATION_MODULE_KEY = "REGISTRATION_MODULE"; // String values for core protocol modules. string constant LICENSING_MODULE_KEY = "LICENSING_MODULE"; // String values for core protocol modules. string constant DISPUTE_MODULE_KEY = "DISPUTE_MODULE"; string constant ROYALTY_MODULE_KEY = "ROYALTY_MODULE"; string constant TOKEN_WITHDRAWAL_MODULE_KEY = "TOKEN_MANAGEMENT_MODULE";
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @title Errors Library
/// @notice Library for all Story Protocol contract errors.
library Errors {
////////////////////////////////////////////////////////////////////////////
// Governance //
////////////////////////////////////////////////////////////////////////////
error Governance__OnlyProtocolAdmin();
error Governance__ZeroAddress();
error Governance__ProtocolPaused();
error Governance__InconsistentState();
error Governance__NewStateIsTheSameWithOldState();
error Governance__UnsupportedInterface(string interfaceName);
////////////////////////////////////////////////////////////////////////////
// IPAccount //
////////////////////////////////////////////////////////////////////////////
error IPAccount__InvalidSigner();
error IPAccount__InvalidSignature();
error IPAccount__ExpiredSignature();
error IPAccount__InvalidCalldata();
error IPAccount__InvalidAccessController();
////////////////////////////////////////////////////////////////////////////
// Module //
////////////////////////////////////////////////////////////////////////////
/// @notice The caller is not allowed to call the provided module.
error Module_Unauthorized();
////////////////////////////////////////////////////////////////////////////
// IPAccountRegistry //
////////////////////////////////////////////////////////////////////////////
error IPAccountRegistry_InvalidIpAccountImpl();
////////////////////////////////////////////////////////////////////////////
// IPAssetRegistry //
////////////////////////////////////////////////////////////////////////////
/// @notice The IP asset has already been registered.
error IPAssetRegistry__AlreadyRegistered();
/// @notice The IP account has already been created.
error IPAssetRegistry__IPAccountAlreadyCreated();
/// @notice The IP asset has not yet been registered.
error IPAssetRegistry__NotYetRegistered();
/// @notice The IP asset registrant is not authorized.
error IPAssetRegistry__RegistrantUnauthorized();
/// @notice The specified IP resolver is not valid.
error IPAssetRegistry__ResolverInvalid();
/// @notice Caller not authorized to perform the IP registry function call.
error IPAssetRegistry__Unauthorized();
/// @notice The deployed address of account doesn't match with IP ID.
error IPAssetRegistry__InvalidAccount();
/// @notice The metadata provider is not valid.
error IPAssetRegistry__InvalidMetadataProvider();
////////////////////////////////////////////////////////////////////////////
// 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();
////////////////////////////////////////////////////////////////////////////
// Metadata Provider ///
////////////////////////////////////////////////////////////////////////////
/// @notice Provided hash metadata is not valid.
error MetadataProvider__HashInvalid();
/// @notice The caller is not the authorized IP asset owner.
error MetadataProvider__IPAssetOwnerInvalid();
/// @notice Provided hash metadata is not valid.
error MetadataProvider__NameInvalid();
/// @notice The new metadata provider is not compatible with the old provider.
error MetadataProvider__MetadataNotCompatible();
/// @notice Provided registrant metadata is not valid.
error MetadataProvider__RegistrantInvalid();
/// @notice Provided registration date is not valid.
error MetadataProvider__RegistrationDateInvalid();
/// @notice Caller does not access to set metadata storage for the provider.
error MetadataProvider__Unauthorized();
/// @notice A metadata provider upgrade is not currently available.
error MetadataProvider__UpgradeUnavailable();
/// @notice The upgrade provider is not valid.
error MetadataProvider__UpgradeProviderInvalid();
/// @notice Provided metadata URI is not valid.
error MetadataProvider__URIInvalid();
////////////////////////////////////////////////////////////////////////////
// LicenseRegistry //
////////////////////////////////////////////////////////////////////////////
error LicenseRegistry__CallerNotLicensingModule();
error LicenseRegistry__ZeroLicensingModule();
error LicensingModule__CallerNotLicenseRegistry();
error LicenseRegistry__RevokedLicense();
/// @notice emitted when trying to transfer a license that is not transferable (by policy)
error LicenseRegistry__NotTransferable();
/// @notice emitted on constructor if dispute module is not set
error LicenseRegistry__ZeroDisputeModule();
////////////////////////////////////////////////////////////////////////////
// LicensingModule //
////////////////////////////////////////////////////////////////////////////
error LicensingModule__PolicyAlreadySetForIpId();
error LicensingModule__FrameworkNotFound();
error LicensingModule__EmptyLicenseUrl();
error LicensingModule__InvalidPolicyFramework();
error LicensingModule__ParamVerifierLengthMismatch();
error LicensingModule__PolicyNotFound();
error LicensingModule__NotLicensee();
error LicensingModule__ParentIdEqualThanChild();
error LicensingModule__LicensorDoesntHaveThisPolicy();
error LicensingModule__MintLicenseParamFailed();
error LicensingModule__LinkParentParamFailed();
error LicensingModule__TransferParamFailed();
error LicensingModule__InvalidLicensor();
error LicensingModule__ParamVerifierAlreadySet();
error LicensingModule__CommercialTermInNonCommercialPolicy();
error LicensingModule__EmptyParamName();
error LicensingModule__UnregisteredFrameworkAddingPolicy();
error LicensingModule__UnauthorizedAccess();
error LicensingModule__LicensorNotRegistered();
error LicensingModule__CallerNotLicensorAndPolicyNotSet();
error LicensingModule__DerivativesCannotAddPolicy();
error LicensingModule__IncompatibleRoyaltyPolicyAddress();
error LicensingModule__IncompatibleRoyaltyPolicyDerivativeRevShare();
error LicensingModule__IncompatibleLicensorCommercialPolicy();
error LicensingModule__IncompatibleLicensorRoyaltyDerivativeRevShare();
error LicensingModule__DerivativeRevShareSumExceedsMaxRNFTSupply();
error LicensingModule__MismatchBetweenRoyaltyPolicy();
error LicensingModule__RegisterPolicyFrameworkMismatch();
error LicensingModule__RoyaltyPolicyNotWhitelisted();
error LicensingModule__MintingFeeTokenNotWhitelisted();
error LicensingModule__ReceiverZeroAddress();
error LicensingModule__MintAmountZero();
/// @notice emitted when trying to interact with an IP that has been disputed in the DisputeModule
error LicensingModule__DisputedIpId();
/// @notice emitted when linking a license from a licensor that has been disputed in the DisputeModule
error LicensingModule__LinkingRevokedLicense();
////////////////////////////////////////////////////////////////////////////
// LicensingModuleAware //
////////////////////////////////////////////////////////////////////////////
error LicensingModuleAware__CallerNotLicensingModule();
////////////////////////////////////////////////////////////////////////////
// PolicyFrameworkManager //
////////////////////////////////////////////////////////////////////////////
error PolicyFrameworkManager__GettingPolicyWrongFramework();
error PolicyFrameworkManager__CommercializerCheckerDoesNotSupportHook(address commercializer);
////////////////////////////////////////////////////////////////////////////
// LicensorApprovalChecker //
////////////////////////////////////////////////////////////////////////////
error LicensorApprovalChecker__Unauthorized();
////////////////////////////////////////////////////////////////////////////
// Dispute Module //
////////////////////////////////////////////////////////////////////////////
error DisputeModule__ZeroArbitrationPolicy();
error DisputeModule__ZeroArbitrationRelayer();
error DisputeModule__ZeroDisputeTag();
error DisputeModule__ZeroLinkToDisputeEvidence();
error DisputeModule__NotWhitelistedArbitrationPolicy();
error DisputeModule__NotWhitelistedDisputeTag();
error DisputeModule__NotWhitelistedArbitrationRelayer();
error DisputeModule__NotDisputeInitiator();
error DisputeModule__NotInDisputeState();
error DisputeModule__NotAbleToResolve();
error DisputeModule__NotRegisteredIpId();
error DisputeModule__UnauthorizedAccess();
error ArbitrationPolicySP__ZeroDisputeModule();
error ArbitrationPolicySP__ZeroPaymentToken();
error ArbitrationPolicySP__NotDisputeModule();
////////////////////////////////////////////////////////////////////////////
// Royalty Module //
////////////////////////////////////////////////////////////////////////////
error RoyaltyModule__ZeroRoyaltyPolicy();
error RoyaltyModule__NotWhitelistedRoyaltyPolicy();
error RoyaltyModule__ZeroRoyaltyToken();
error RoyaltyModule__NotWhitelistedRoyaltyToken();
error RoyaltyModule__NoRoyaltyPolicySet();
error RoyaltyModule__IncompatibleRoyaltyPolicy();
error RoyaltyModule__NotAllowedCaller();
error RoyaltyModule__ZeroLicensingModule();
error RoyaltyModule__CanOnlyMintSelectedPolicy();
error RoyaltyModule__NoParentsOnLinking();
error RoyaltyModule__NotRegisteredIpId();
error RoyaltyPolicyLAP__ZeroRoyaltyModule();
error RoyaltyPolicyLAP__ZeroLiquidSplitFactory();
error RoyaltyPolicyLAP__ZeroLiquidSplitMain();
error RoyaltyPolicyLAP__NotRoyaltyModule();
error RoyaltyPolicyLAP__ZeroLicensingModule();
error RoyaltyPolicyLAP__AboveParentLimit();
error RoyaltyPolicyLAP__AboveAncestorsLimit();
error RoyaltyPolicyLAP__AboveRoyaltyStackLimit();
error RoyaltyPolicyLAP__InvalidAncestorsLength();
error RoyaltyPolicyLAP__InvalidAncestors();
error RoyaltyPolicyLAP__InvalidRoyaltyAmountLength();
error RoyaltyPolicyLAP__InvalidAncestorsHash();
error RoyaltyPolicyLAP__InvalidParentRoyaltiesLength();
error RoyaltyPolicyLAP__InvalidAncestorsRoyalty();
error RoyaltyPolicyLAP__ImplementationAlreadySet();
error RoyaltyPolicyLAP__ZeroAncestorsVaultImpl();
error RoyaltyPolicyLAP__NotFullOwnership();
error RoyaltyPolicyLAP__UnlinkableToParents();
error RoyaltyPolicyLAP__TransferFailed();
error RoyaltyPolicyLAP__LastPositionNotAbleToMintLicense();
error AncestorsVaultLAP__ZeroRoyaltyPolicyLAP();
error AncestorsVaultLAP__AlreadyClaimed();
error AncestorsVaultLAP__InvalidAncestorsHash();
error AncestorsVaultLAP__InvalidClaimer();
error AncestorsVaultLAP__ClaimerNotAnAncestor();
error AncestorsVaultLAP__ETHBalanceNotZero();
error AncestorsVaultLAP__ERC20BalanceNotZero();
error AncestorsVaultLAP__TransferFailed();
////////////////////////////////////////////////////////////////////////////
// ModuleRegistry //
////////////////////////////////////////////////////////////////////////////
error ModuleRegistry__ModuleAddressZeroAddress();
error ModuleRegistry__ModuleAddressNotContract();
error ModuleRegistry__ModuleAlreadyRegistered();
error ModuleRegistry__NameEmptyString();
error ModuleRegistry__NameAlreadyRegistered();
error ModuleRegistry__NameDoesNotMatch();
error ModuleRegistry__ModuleNotRegistered();
error ModuleRegistry__InterfaceIdZero();
error ModuleRegistry__ModuleTypeAlreadyRegistered();
error ModuleRegistry__ModuleTypeNotRegistered();
error ModuleRegistry__ModuleNotSupportExpectedModuleTypeInterfaceId();
error ModuleRegistry__ModuleTypeEmptyString();
////////////////////////////////////////////////////////////////////////////
// RegistrationModule //
////////////////////////////////////////////////////////////////////////////
/// @notice The caller is not the owner of the root IP NFT.
error RegistrationModule__InvalidOwner();
////////////////////////////////////////////////////////////////////////////
// AccessController //
////////////////////////////////////////////////////////////////////////////
error AccessController__IPAccountIsZeroAddress();
error AccessController__IPAccountIsNotValid(address ipAccount);
error AccessController__SignerIsZeroAddress();
error AccessController__CallerIsNotIPAccount();
error AccessController__PermissionIsNotValid();
error AccessController__BothCallerAndRecipientAreNotRegisteredModule(address signer, address to);
error AccessController__PermissionDenied(address ipAccount, address signer, address to, bytes4 func);
////////////////////////////////////////////////////////////////////////////
// AccessControlled //
////////////////////////////////////////////////////////////////////////////
error AccessControlled__ZeroAddress();
error AccessControlled__NotIpAccount(address ipAccount);
error AccessControlled__CallerIsNotIpAccount(address caller);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @title IP Library
/// @notice Library for constants, structs, and helper functions used for IP.
library IP {
/// @notice Core metadata to associate with each IP.
struct MetadataV1 {
// The name associated with the IP.
string name;
// 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;
// An external URI associated with the IP.
string uri;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { IERC165, ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import { IModule } from "../interfaces/modules/base/IModule.sol";
/// @title BaseModule
/// @notice Base implementation for all modules in Story Protocol.
abstract contract BaseModule is ERC165, IModule {
/// @notice IERC165 interface support.
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IModule).interfaceId || super.supportsInterface(interfaceId);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { Licensing } from "../../../lib/Licensing.sol";
import { IModule } from "../base/IModule.sol";
import { RoyaltyModule } from "../../../modules/royalty/RoyaltyModule.sol";
import { ILicenseRegistry } from "../../registries/ILicenseRegistry.sol";
import { IDisputeModule } from "../dispute/IDisputeModule.sol";
/// @title ILicensingModule
interface ILicensingModule is IModule {
/// @notice Status of a policy on IP asset
/// @param index The local index of the policy in the IP asset
/// @param isSet True if the policy is set in the IP asset
/// @param active True if the policy is active
/// @param isInherited True if the policy is inherited from a parent IP asset
struct PolicySetup {
uint256 index;
bool isSet;
bool active;
bool isInherited;
}
/// @notice Emitted when a policy framework is created by registering a policy framework manager
/// @param framework The address of the IPolicyFrameworkManager
/// @param framework The policy framework data
event PolicyFrameworkRegistered(address indexed framework, string name, string licenseTextUrl);
/// @notice Emitted when a policy is added to the contract
/// @param policyId The id of the policy
/// @param policyFrameworkManager The address of the policy framework manager
/// @param frameworkData The policy framework specific encoded data
/// @param royaltyPolicy The address of the royalty policy
/// @param royaltyData The royalty policy specific encoded data
/// @param mintingFee The fee to be paid when minting a license
/// @param mintingFeeToken The token to be used to pay the minting fee
event PolicyRegistered(
uint256 indexed policyId,
address indexed policyFrameworkManager,
bytes frameworkData,
address royaltyPolicy,
bytes royaltyData,
uint256 mintingFee,
address mintingFeeToken
);
/// @notice Emitted when a policy is added to an IP
/// @param caller The address that called the function
/// @param ipId The id of the IP
/// @param policyId The id of the policy
/// @param index The index of the policy in the IP's policy set
/// @param isInherited Whether the policy was inherited from a parent IP (linking) or set by IP owner
event PolicyAddedToIpId(
address indexed caller,
address indexed ipId,
uint256 indexed policyId,
uint256 index,
bool isInherited
);
/// @notice Emitted when an IP is linked to its parent by burning a license
/// @param caller The address that called the function
/// @param ipId The id of the IP
/// @param parentIpIds The ids of the parent IPs
event IpIdLinkedToParents(address indexed caller, address indexed ipId, address[] parentIpIds);
/// @notice Returns the canonical protocol-wide RoyaltyModule
function ROYALTY_MODULE() external view returns (RoyaltyModule);
/// @notice Returns the canonical protocol-wide LicenseRegistry
function LICENSE_REGISTRY() external view returns (ILicenseRegistry);
/// @notice Returns the canonical protocol-wide DisputeModule
function DISPUTE_MODULE() external view returns (IDisputeModule);
/// @notice Registers a policy framework manager into the contract, so it can add policy data for licenses.
/// @param manager the address of the manager. Will be ERC165 checked for IPolicyFrameworkManager
function registerPolicyFrameworkManager(address manager) external;
/// @notice Registers a policy into the contract. MUST be called by a registered
/// framework or it will revert. The policy data and its integrity must be
/// verified by the policy framework manager.
/// @param pol The Licensing policy data. MUST have same policy framework as the caller address
/// @return policyId The id of the newly registered policy
function registerPolicy(Licensing.Policy memory pol) external returns (uint256 policyId);
/// @notice Adds a policy to the set of policies of an IP
/// @param ipId The id of the IP
/// @param polId The id of the policy
/// @return indexOnIpId The index of the policy in the IP's policy set
function addPolicyToIp(address ipId, uint256 polId) external returns (uint256 indexOnIpId);
/// @notice Mints a license to create derivative IP. License NFTs represent a policy granted by IPs (licensors).
/// Reverts if caller is not authorized by any of the licensors.
/// @dev This NFT needs to be burned in order to link a derivative IP with its parents. If this is the first
/// combination of policy and licensors, a new licenseId will be created (by incrementing prev totalLicenses).
/// If not, the license is fungible and an id will be reused. The licensing terms that regulate creating new
/// licenses will be verified to allow minting.
/// @param policyId The id of the policy with the licensing parameters
/// @param licensorIpId The id of the licensor IP
/// @param amount The amount of licenses to mint
/// @param receiver The address that will receive the license
/// @param royaltyContext The context for the royalty module to process
/// @return licenseId The ID of the license NFT(s)
function mintLicense(
uint256 policyId,
address licensorIpId,
uint256 amount,
address receiver,
bytes calldata royaltyContext
) external returns (uint256 licenseId);
/// @notice Links an IP to the licensors listed in the license NFTs, if their policies allow it. Burns the license
/// NFTs in the proccess. The caller must be the owner of the IP asset and license NFTs.
/// @param licenseIds The id of the licenses to burn
/// @param childIpId The id of the child IP to be linked
/// @param royaltyContext The context for the royalty module to process
function linkIpToParents(uint256[] calldata licenseIds, address childIpId, bytes calldata royaltyContext) external;
///
/// Getters
///
/// @notice Returns if the framework address is registered in the LicensingModule.
/// @param policyFramework The address of the policy framework manager
/// @return isRegistered True if the framework is registered
function isFrameworkRegistered(address policyFramework) external view returns (bool);
/// @notice Returns amount of distinct licensing policies in the LicensingModule.
/// @return totalPolicies The amount of policies
function totalPolicies() external view returns (uint256);
/// @notice Returns the policy data for policyId, reverts if not found.
/// @param policyId The id of the policy
/// @return pol The policy data
function policy(uint256 policyId) external view returns (Licensing.Policy memory pol);
/// @notice Returns the policy id for the given policy data, or 0 if not found.
/// @param pol The policy data in Policy struct
/// @return policyId The id of the policy
function getPolicyId(Licensing.Policy calldata pol) external view returns (uint256 policyId);
/// @notice Returns the policy aggregator data for the given IP ID in the framework.
/// @param framework The address of the policy framework manager
/// @param ipId The id of the IP asset
/// @return data The encoded policy aggregator data to be decoded by the framework manager
function policyAggregatorData(address framework, address ipId) external view returns (bytes memory);
/// @notice Returns if policyId exists in the LicensingModule
/// @param policyId The id of the policy
/// @return isDefined True if the policy is defined
function isPolicyDefined(uint256 policyId) external view returns (bool);
/// @notice Returns the policy ids attached to an IP
/// @dev Potentially gas-intensive operation, use with care.
/// @param isInherited True if the policy is inherited from a parent IP
/// @param ipId The id of the IP asset
/// @return policyIds The ids of policy ids for the IP
function policyIdsForIp(bool isInherited, address ipId) external view returns (uint256[] memory policyIds);
/// @notice Returns the total number of policies attached to an IP
/// @param isInherited True if the policy is inherited from a parent IP
/// @param ipId The id of the IP asset
/// @return totalPolicies The total number of policies for the IP
function totalPoliciesForIp(bool isInherited, address ipId) external view returns (uint256);
/// @notice Returns if a given policyId is attached to an IP
/// @param isInherited True if the policy is inherited from a parent IP
/// @param ipId The id of the IP asset
/// @param policyId The id of the policy
/// @return isSet True if the policy is set in the IP asset
function isPolicyIdSetForIp(bool isInherited, address ipId, uint256 policyId) external view returns (bool);
/// @notice Returns the policy ID for an IP by local index on the IP's policy set
/// @param isInherited True if the policy is inherited from a parent IP
/// @param ipId The id of the IP asset to check
/// @param index The local index of a policy in the IP's policy set
/// @return policyId The id of the policy
function policyIdForIpAtIndex(
bool isInherited,
address ipId,
uint256 index
) external view returns (uint256 policyId);
/// @notice Returns the policy data for an IP by the policy's local index on the IP's policy set
/// @param isInherited True if the policy is inherited from a parent IP
/// @param ipId The id of the IP asset to check
/// @param index The local index of a policy in the IP's policy set
/// @return policy The policy data
function policyForIpAtIndex(
bool isInherited,
address ipId,
uint256 index
) external view returns (Licensing.Policy memory);
/// @notice Returns the status of a policy in an IP's policy set
/// @param ipId The id of the IP asset to check
/// @param policyId The id of the policy
/// @return index The local index of the policy in the IP's policy set
/// @return isInherited True if the policy is inherited from a parent IP
/// @return active True if the policy is active
function policyStatus(
address ipId,
uint256 policyId
) external view returns (uint256 index, bool isInherited, bool active);
/// @notice Returns if the given policy attached to the given IP is inherited from a parent IP.
/// @param ipId The id of the IP asset that has the policy attached
/// @param policyId The id of the policy to check if inherited
/// @return isInherited True if the policy is inherited from a parent IP
function isPolicyInherited(address ipId, uint256 policyId) external view returns (bool);
/// @notice Returns if an IP is a derivative of another IP
/// @param parentIpId The id of the parent IP asset to check
/// @param childIpId The id of the child IP asset to check
/// @return isParent True if the child IP is a derivative of the parent IP
function isParent(address parentIpId, address childIpId) external view returns (bool);
/// @notice Returns the list of parent IP assets for a given child IP asset
/// @param ipId The id of the child IP asset to check
/// @return parentIpIds The ids of the parent IP assets
function parentIpIds(address ipId) external view returns (address[] memory);
/// @notice Returns the total number of parents for an IP asset
/// @param ipId The id of the IP asset to check
/// @return totalParents The total number of parent IP assets
function totalParentsForIpId(address ipId) external view returns (uint256);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { IIPAccountRegistry } from "./IIPAccountRegistry.sol";
import { IModuleRegistry } from "./IModuleRegistry.sol";
import { IMetadataProviderMigratable } from "./metadata/IMetadataProviderMigratable.sol";
import { IRegistrationModule } from "../modules/IRegistrationModule.sol";
/// @title Interface for IP Account Registry
/// @notice This interface manages the registration and tracking of IP Accounts
interface IIPAssetRegistry is IIPAccountRegistry {
// TODO: Deprecate `resolver` in favor of consolidation through the provider.
/// @notice Attributes for the IP asset type.
/// @param metadataProvider Metadata provider for Story Protocol canonicalized metadata.
/// @param resolver Metadata resolver for custom metadata added by the IP owner.
struct Record {
IMetadataProviderMigratable metadataProvider;
address resolver;
}
// TODO: Add support for optional licenseIds.
/// @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.
/// @param provider The address of the metadata provider linked to the IP.
/// @param metadata Canonical metadata that was linked to the IP.
event IPRegistered(
address ipId,
uint256 indexed chainId,
address indexed tokenContract,
uint256 indexed tokenId,
address resolver,
address provider,
bytes metadata
);
/// @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 Emits when an operator is approved for IP registration for an NFT owner.
/// @param owner The address of the IP owner.
/// @param operator The address of the operator the owneris authorizing.
/// @param approved Whether or not to approve that operator for registration.
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/// @notice Emits when metadata is set for an IP asset.
/// @param ipId The canonical identifier of the specified IP.
/// @param metadataProvider Address of the metadata provider associated with the IP.
/// @param metadata The canonical metadata in bytes associated with the IP.
event MetadataSet(address indexed ipId, address indexed metadataProvider, bytes metadata);
/// @notice The canonical module registry used by the protocol.
function MODULE_REGISTRY() external view returns (IModuleRegistry);
/// @notice The registration module that interacts with IPAssetRegistry.
function REGISTRATION_MODULE() external view returns (IRegistrationModule);
/// @notice Tracks the total number of IP assets in existence.
function totalSupply() external view returns (uint256);
/// @notice Checks whether an operator is approved to register on behalf of an IP owner.
/// @param owner The address of the IP owner whose approval is being checked for.
/// @param operator The address of the operator the owner has approved for registration delgation.
/// @return Whether the operator is approved on behalf of the owner for registering.
function isApprovedForAll(address owner, address operator) external view returns (bool);
/// @notice Enables third party operators to register on behalf of an NFT owner.
/// @param operator The address of the operator the sender authorizes.
/// @param approved Whether or not to approve that operator for registration.
function setApprovalForAll(address operator, bool approved) external;
/// @notice Registers an NFT as IP, creating a corresponding IP record.
/// @param chainId The chain identifier of where the NFT resides.
/// @param tokenContract The address of the NFT.
/// @param tokenId The token identifier of the NFT.
/// @param resolverAddr The address of the resolver to associate with the IP.
/// @param createAccount Whether to create an IP account when registering.
/// @param metadata_ Metadata in bytes to associate with the IP.
/// @return ipId_ The address of the newly registered IP.
function register(
uint256 chainId,
address tokenContract,
uint256 tokenId,
address resolverAddr,
bool createAccount,
bytes calldata metadata_
) external returns (address);
/// @notice Registers an NFT as an IP using licenses derived from parent IP asset(s).
/// @param licenseIds The parent IP asset licenses used to derive the new IP asset.
/// @param royaltyContext The context for the royalty module to process.
/// @param chainId The chain identifier of where the NFT resides.
/// @param tokenContract The address of the NFT.
/// @param tokenId The token identifier of the NFT.
/// @param resolverAddr The address of the resolver to associate with the IP.
/// @param createAccount Whether to create an IP account when registering.
/// @param metadata_ Metadata in bytes to associate with the IP.
/// @return ipId_ The address of the newly registered IP.
function register(
uint256[] calldata licenseIds,
bytes calldata royaltyContext,
uint256 chainId,
address tokenContract,
uint256 tokenId,
address resolverAddr,
bool createAccount,
bytes calldata metadata_
) external returns (address);
/// @notice Gets the canonical IP identifier associated with an IP NFT.
/// @dev This is equivalent to the address of its bound IP account.
/// @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 ipId The IP's canonical address identifier.
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 isRegistered Whether the IP was registered into the protocol.
function isRegistered(address id) 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 resolver The IP resolver address if registered, else the zero address.
function resolver(address id) external view returns (address);
/// @notice Gets the metadata provider used for new metadata registrations.
/// @return metadataProvider The address of the metadata provider used for new IP registrations.
function metadataProvider() external view returns (address);
/// @notice Gets the metadata provider linked to an IP based on its ID.
/// @param id The canonical identifier for the IP.
/// @return metadataProvider The metadata provider that was bound to this IP at creation time.
function metadataProvider(address id) external view returns (address);
/// @notice Gets the underlying canonical metadata linked to an IP asset.
/// @param id The canonical ID of the IP asset.
/// @return metadata The metadata that was bound to this IP at creation time.
function metadata(address id) external view returns (bytes memory);
/// @notice Sets the underlying metadata for an IP asset.
/// @dev As metadata is immutable but additive, this will only be used when an IP migrates from a new provider that
/// introduces new attributes.
/// @param id The canonical ID of the IP.
/// @param data Canonical metadata to associate with the IP.
function setMetadata(address id, address metadataProvider, bytes calldata data) external;
/// @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;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { BaseModule } from "../modules/BaseModule.sol";
import { IResolver } from "../interfaces/resolvers/IResolver.sol";
import { AccessControlled } from "../access/AccessControlled.sol";
/// @notice IP Resolver Base Contract
abstract contract ResolverBase is IResolver, BaseModule, AccessControlled {
constructor(address accessController, address assetRegistry) AccessControlled(accessController, assetRegistry) {}
/// @notice IERC165 interface support.
function supportsInterface(bytes4 id) public view virtual override(BaseModule, IResolver) returns (bool) {
return id == type(IResolver).interfaceId || super.supportsInterface(id);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { IKeyValueResolver } from "../interfaces/resolvers/IKeyValueResolver.sol";
import { ResolverBase } from "../resolvers/ResolverBase.sol";
/// @title Key Value Resolver
/// @notice Resolver used for returning values associated with keys. This is the
/// preferred approach for adding additional attribution to IP that the
/// IP originator thinks is beneficial to have on chain.
abstract contract KeyValueResolver is IKeyValueResolver, ResolverBase {
/// @dev Stores key-value pairs associated with each IP.
mapping(address => mapping(string => string)) internal _values;
/// @notice Sets the string value for a specified key of an IP ID.
/// @dev Enforced to be only callable by users with valid permission to call on behalf of the ipId.
/// @param ipId The canonical identifier of the IP asset.
/// @param key The string parameter key to update.
/// @param val The value to set for the specified key.
function setValue(address ipId, string calldata key, string calldata val) external virtual verifyPermission(ipId) {
_values[ipId][key] = val;
emit KeyValueSet(ipId, key, val);
}
/// @notice Retrieves the string value associated with a key for an IP asset.
/// @param key The string parameter key to query.
/// @return value The value associated with the specified key.
function value(address ipId, string calldata key) external view virtual returns (string memory) {
return _values[ipId][key];
}
/// @notice IERC165 interface support.
function supportsInterface(bytes4 id) public view virtual override returns (bool) {
return id == type(IKeyValueResolver).interfaceId || super.supportsInterface(id);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/// @notice Module Interface
interface IModule is IERC165 {
/// @notice Returns the string identifier associated with the module.
function name() external returns (string memory);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @title Licensing
/// @notice Types and constants used by the licensing related contracts
library Licensing {
/// @notice A particular configuration (flavor) of a Policy Framework, setting values for the licensing
/// terms (parameters) of the framework.
/// @param isLicenseTransferable Whether or not the license is transferable
/// @param policyFramework address of the IPolicyFrameworkManager this policy is based on
/// @param frameworkData Data to be used by the policy framework to verify minting and linking
/// @param royaltyPolicy address of the royalty policy to be used by the policy framework, if any
/// @param royaltyData Data to be used by the royalty policy (for example, encoding of the royalty percentage)
/// @param mintingFee Fee to be paid when minting a license
/// @param mintingFeeToken Token to be used to pay the minting fee
struct Policy {
bool isLicenseTransferable;
address policyFramework;
bytes frameworkData;
address royaltyPolicy;
bytes royaltyData;
uint256 mintingFee;
address mintingFeeToken;
}
/// @notice Data that define a License Agreement NFT
/// @param policyId Id of the policy this license is based on, which will be set in the derivative IP when the
/// license is burnt for linking
/// @param licensorIpId Id of the IP this license is for
/// @param transferable Whether or not the license is transferable
struct License {
uint256 policyId;
address licensorIpId;
bool transferable;
// TODO: support for transfer hooks
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import { BaseModule } from "../BaseModule.sol";
import { Governable } from "../../governance/Governable.sol";
import { IRoyaltyModule } from "../../interfaces/modules/royalty/IRoyaltyModule.sol";
import { IRoyaltyPolicy } from "../../interfaces/modules/royalty/policies/IRoyaltyPolicy.sol";
import { Errors } from "../../lib/Errors.sol";
import { ROYALTY_MODULE_KEY } from "../../lib/modules/Module.sol";
import { BaseModule } from "../BaseModule.sol";
/// @title Story Protocol Royalty Module
/// @notice The Story Protocol royalty module allows to set royalty policies an IP asset and pay royalties as a
/// derivative IP.
contract RoyaltyModule is IRoyaltyModule, Governable, ReentrancyGuard, BaseModule {
using ERC165Checker for address;
string public constant override name = ROYALTY_MODULE_KEY;
/// @notice Returns the licensing module address
address public LICENSING_MODULE;
/// @notice Indicates if a royalty policy is whitelisted
mapping(address royaltyPolicy => bool isWhitelisted) public isWhitelistedRoyaltyPolicy;
/// @notice Indicates if a royalty token is whitelisted
mapping(address token => bool) public isWhitelistedRoyaltyToken;
/// @notice Indicates the royalty policy for a given IP asset
mapping(address ipId => address royaltyPolicy) public royaltyPolicies;
constructor(address governance) Governable(governance) {}
/// @notice Modifier to enforce that the caller is the licensing module
modifier onlyLicensingModule() {
if (msg.sender != LICENSING_MODULE) revert Errors.RoyaltyModule__NotAllowedCaller();
_;
}
/// @notice Sets the license registry
/// @dev Enforced to be only callable by the protocol admin
/// @param licensingModule The address of the license registry
function setLicensingModule(address licensingModule) external onlyProtocolAdmin {
if (licensingModule == address(0)) revert Errors.RoyaltyModule__ZeroLicensingModule();
LICENSING_MODULE = licensingModule;
}
/// @notice Whitelist a royalty policy
/// @dev Enforced to be only callable by the protocol admin
/// @param royaltyPolicy The address of the royalty policy
/// @param allowed Indicates if the royalty policy is whitelisted or not
function whitelistRoyaltyPolicy(address royaltyPolicy, bool allowed) external onlyProtocolAdmin {
if (royaltyPolicy == address(0)) revert Errors.RoyaltyModule__ZeroRoyaltyPolicy();
isWhitelistedRoyaltyPolicy[royaltyPolicy] = allowed;
emit RoyaltyPolicyWhitelistUpdated(royaltyPolicy, allowed);
}
/// @notice Whitelist a royalty token
/// @dev Enforced to be only callable by the protocol admin
/// @param token The token address
/// @param allowed Indicates if the token is whitelisted or not
function whitelistRoyaltyToken(address token, bool allowed) external onlyProtocolAdmin {
if (token == address(0)) revert Errors.RoyaltyModule__ZeroRoyaltyToken();
isWhitelistedRoyaltyToken[token] = allowed;
emit RoyaltyTokenWhitelistUpdated(token, allowed);
}
/// @notice Executes royalty related logic on license minting
/// @dev Enforced to be only callable by LicensingModule
/// @param ipId The ipId whose license is being minted (licensor)
/// @param royaltyPolicy The royalty policy address of the license being minted
/// @param licenseData The license data custom to each the royalty policy
/// @param externalData The external data custom to each the royalty policy
function onLicenseMinting(
address ipId,
address royaltyPolicy,
bytes calldata licenseData,
bytes calldata externalData
) external nonReentrant onlyLicensingModule {
if (!isWhitelistedRoyaltyPolicy[royaltyPolicy]) revert Errors.RoyaltyModule__NotWhitelistedRoyaltyPolicy();
address royaltyPolicyIpId = royaltyPolicies[ipId];
// if the node is a root node, then royaltyPolicyIpId will be address(0) and any type of royalty type can be
// selected to mint a license if the node is a derivative node, then the any minted licenses by the derivative
// node should have the same royalty policy as the parent node a derivative node set its royalty policy
// immutably in onLinkToParents() function below
if (royaltyPolicyIpId != royaltyPolicy && royaltyPolicyIpId != address(0))
revert Errors.RoyaltyModule__CanOnlyMintSelectedPolicy();
IRoyaltyPolicy(royaltyPolicy).onLicenseMinting(ipId, licenseData, externalData);
}
/// @notice Executes royalty related logic on linking to parents
/// @dev Enforced to be only callable by LicensingModule
/// @param ipId The children ipId that is being linked to parents
/// @param royaltyPolicy The common royalty policy address of all the licenses being burned
/// @param parentIpIds The parent ipIds that the children ipId is being linked to
/// @param licenseData The license data custom to each the royalty policy
/// @param externalData The external data custom to each the royalty policy
function onLinkToParents(
address ipId,
address royaltyPolicy,
address[] calldata parentIpIds,
bytes[] memory licenseData,
bytes calldata externalData
) external nonReentrant onlyLicensingModule {
if (!isWhitelistedRoyaltyPolicy[royaltyPolicy]) revert Errors.RoyaltyModule__NotWhitelistedRoyaltyPolicy();
if (parentIpIds.length == 0) revert Errors.RoyaltyModule__NoParentsOnLinking();
for (uint32 i = 0; i < parentIpIds.length; i++) {
address parentRoyaltyPolicy = royaltyPolicies[parentIpIds[i]];
// if the parent node has a royalty policy set, then the derivative node should have the same royalty
// policy if the parent node does not have a royalty policy set, then the derivative node can set any type
// of royalty policy as long as the children ip obtained and is burning all licenses with that royalty type
// from each parent (was checked in licensing module before calling this function)
if (parentRoyaltyPolicy != royaltyPolicy && parentRoyaltyPolicy != address(0))
revert Errors.RoyaltyModule__IncompatibleRoyaltyPolicy();
}
royaltyPolicies[ipId] = royaltyPolicy;
IRoyaltyPolicy(royaltyPolicy).onLinkToParents(ipId, parentIpIds, licenseData, externalData);
}
/// @notice Allows the function caller to pay royalties to the receiver IP asset on behalf of the payer IP asset.
/// @param receiverIpId The ipId that receives the royalties
/// @param payerIpId The ipId that pays the royalties
/// @param token The token to use to pay the royalties
/// @param amount The amount to pay
function payRoyaltyOnBehalf(
address receiverIpId,
address payerIpId,
address token,
uint256 amount
) external nonReentrant {
if (!isWhitelistedRoyaltyToken[token]) revert Errors.RoyaltyModule__NotWhitelistedRoyaltyToken();
address payerRoyaltyPolicy = royaltyPolicies[payerIpId];
// if the payer does not have a royalty policy set, then the payer is not a derivative ip and does not pay
// royalties the receiver ip can have a zero royalty policy since that could mean it is an ip a root
if (payerRoyaltyPolicy == address(0)) revert Errors.RoyaltyModule__NoRoyaltyPolicySet();
if (!isWhitelistedRoyaltyPolicy[payerRoyaltyPolicy]) revert Errors.RoyaltyModule__NotWhitelistedRoyaltyPolicy();
IRoyaltyPolicy(payerRoyaltyPolicy).onRoyaltyPayment(msg.sender, receiverIpId, token, amount);
emit RoyaltyPaid(receiverIpId, payerIpId, msg.sender, token, amount);
}
/// @notice Allows to pay the minting fee for a license
/// @param receiverIpId The ipId that receives the royalties
/// @param payerAddress The address that pays the royalties
/// @param licenseRoyaltyPolicy The royalty policy of the license being minted
/// @param token The token to use to pay the royalties
/// @param amount The amount to pay
function payLicenseMintingFee(
address receiverIpId,
address payerAddress,
address licenseRoyaltyPolicy,
address token,
uint256 amount
) external onlyLicensingModule {
if (!isWhitelistedRoyaltyToken[token]) revert Errors.RoyaltyModule__NotWhitelistedRoyaltyToken();
if (licenseRoyaltyPolicy == address(0)) revert Errors.RoyaltyModule__NoRoyaltyPolicySet();
if (!isWhitelistedRoyaltyPolicy[licenseRoyaltyPolicy])
revert Errors.RoyaltyModule__NotWhitelistedRoyaltyPolicy();
IRoyaltyPolicy(licenseRoyaltyPolicy).onRoyaltyPayment(payerAddress, receiverIpId, token, amount);
emit LicenseMintingFeePaid(receiverIpId, payerAddress, token, amount);
}
/// @notice IERC165 interface support.
function supportsInterface(bytes4 interfaceId) public view virtual override(BaseModule, IERC165) returns (bool) {
return interfaceId == type(IRoyaltyModule).interfaceId || super.supportsInterface(interfaceId);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { IERC1155 } from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import { Licensing } from "../../lib/Licensing.sol";
import { IDisputeModule } from "../modules/dispute/IDisputeModule.sol";
import { ILicensingModule } from "../modules/licensing/ILicensingModule.sol";
/// @title ILicenseRegistry
interface ILicenseRegistry is IERC1155 {
/// @notice Emitted when a license is minted
/// @param creator The address that created the license
/// @param receiver The address that received the license
/// @param licenseId The ID of the license
/// @param amount The amount of licenses minted
/// @param licenseData The license data
event LicenseMinted(
address indexed creator,
address indexed receiver,
uint256 indexed licenseId,
uint256 amount,
Licensing.License licenseData
);
/// @notice Returns the canonical protocol-wide LicensingModule
function LICENSING_MODULE() external view returns (ILicensingModule);
/// @notice Returns the canonical protocol-wide DisputeModule
function DISPUTE_MODULE() external view returns (IDisputeModule);
/// @notice Mints license NFTs representing a policy granted by a set of ipIds (licensors). This NFT needs to be
/// burned in order to link a derivative IP with its parents. If this is the first combination of policy and
/// licensors, a new licenseId will be created. If not, the license is fungible and an id will be reused.
/// @dev Only callable by the licensing module.
/// @param policyId The ID of the policy to be minted
/// @param licensorIpId_ The ID of the IP granting the license (ie. licensor)
/// @param transferable True if the license is transferable
/// @param amount Number of licenses to mint. License NFT is fungible for same policy and same licensors
/// @param receiver Receiver address of the minted license NFT(s).
/// @return licenseId The ID of the minted license NFT(s).
function mintLicense(
uint256 policyId,
address licensorIpId_,
bool transferable,
uint256 amount,
address receiver
) external returns (uint256 licenseId);
/// @notice Burns licenses
/// @param holder The address that holds the licenses
/// @param licenseIds The ids of the licenses to burn
function burnLicenses(address holder, uint256[] calldata licenseIds) external;
///
/// Getters
///
/// @notice Returns the number of licenses registered in the protocol.
/// @dev Token ID counter total count.
/// @return mintedLicenses The number of minted licenses
function mintedLicenses() external view returns (uint256);
/// @notice Returns true if holder has positive balance for the given license ID.
/// @return isLicensee True if holder is the licensee for the license (owner of the license NFT), or derivative IP
/// owner if the license was added to the IP by linking (burning a license).
function isLicensee(uint256 licenseId, address holder) external view returns (bool);
/// @notice Returns the license data for the given license ID
/// @param licenseId The ID of the license
/// @return licenseData The license data
function license(uint256 licenseId) external view returns (Licensing.License memory);
/// @notice Returns the ID of the IP asset that is the licensor of the given license ID
/// @param licenseId The ID of the license
/// @return licensorIpId The ID of the licensor
function licensorIpId(uint256 licenseId) external view returns (address);
/// @notice Returns the policy ID for the given license ID
/// @param licenseId The ID of the license
/// @return policyId The ID of the policy
function policyIdForLicense(uint256 licenseId) external view returns (uint256);
/// @notice Returns true if the license has been revoked (licensor tagged after a dispute in
/// the dispute module). If the tag is removed, the license is not revoked anymore.
/// @param licenseId The id of the license to check
/// @return isRevoked True if the license is revoked
function isLicenseRevoked(uint256 licenseId) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @title Dispute Module Interface
interface IDisputeModule {
/// @notice Dispute struct
/// @param targetIpId The ipId that is the target of the dispute
/// @param disputeInitiator The address of the dispute initiator
/// @param arbitrationPolicy The address of the arbitration policy
/// @param linkToDisputeEvidence The link of the dispute evidence
/// @param targetTag The target tag of the dispute
/// @param currentTag The current tag of the dispute
struct Dispute {
address targetIpId;
address disputeInitiator;
address arbitrationPolicy;
bytes32 linkToDisputeEvidence;
bytes32 targetTag;
bytes32 currentTag;
}
/// @notice Event emitted when a dispute tag whitelist status is updated
/// @param tag The dispute tag
/// @param allowed Indicates if the dispute tag is whitelisted
event TagWhitelistUpdated(bytes32 tag, bool allowed);
/// @notice Event emitted when an arbitration policy whitelist status is updated
/// @param arbitrationPolicy The address of the arbitration policy
/// @param allowed Indicates if the arbitration policy is whitelisted
event ArbitrationPolicyWhitelistUpdated(address arbitrationPolicy, bool allowed);
/// @notice Event emitted when an arbitration relayer whitelist status is updated
/// @param arbitrationPolicy The address of the arbitration policy
/// @param arbitrationRelayer The address of the arbitration relayer
/// @param allowed Indicates if the arbitration relayer is whitelisted
event ArbitrationRelayerWhitelistUpdated(address arbitrationPolicy, address arbitrationRelayer, bool allowed);
/// @notice Event emitted when the base arbitration policy is set
/// @param arbitrationPolicy The address of the arbitration policy
event DefaultArbitrationPolicyUpdated(address arbitrationPolicy);
/// @notice Event emitted when an arbitration policy is set for an ipId
/// @param ipId The ipId address
/// @param arbitrationPolicy The address of the arbitration policy
event ArbitrationPolicySet(address ipId, address arbitrationPolicy);
/// @notice Event emitted when a dispute is raised
/// @param disputeId The dispute id
/// @param targetIpId The ipId that is the target of the dispute
/// @param disputeInitiator The address of the dispute initiator
/// @param arbitrationPolicy The address of the arbitration policy
/// @param linkToDisputeEvidence The link of the dispute evidence
/// @param targetTag The target tag of the dispute
/// @param data Custom data adjusted to each policy
event DisputeRaised(
uint256 disputeId,
address targetIpId,
address disputeInitiator,
address arbitrationPolicy,
bytes32 linkToDisputeEvidence,
bytes32 targetTag,
bytes data
);
/// @notice Event emitted when a dispute judgement is set
/// @param disputeId The dispute id
/// @param decision The decision of the dispute
/// @param data Custom data adjusted to each policy
event DisputeJudgementSet(uint256 disputeId, bool decision, bytes data);
/// @notice Event emitted when a dispute is cancelled
/// @param disputeId The dispute id
/// @param data Custom data adjusted to each policy
event DisputeCancelled(uint256 disputeId, bytes data);
/// @notice Event emitted when a dispute is resolved
/// @param disputeId The dispute id
event DisputeResolved(uint256 disputeId);
/// @notice Tag to represent the dispute is in dispute state waiting for judgement
function IN_DISPUTE() external view returns (bytes32);
/// @notice Dispute ID counter
function disputeCounter() external view returns (uint256);
/// @notice The address of the base arbitration policy
function baseArbitrationPolicy() external view returns (address);
/// @notice Returns the dispute information for a given dispute id
/// @param disputeId The dispute id
/// @return targetIpId The ipId that is the target of the dispute
/// @return disputeInitiator The address of the dispute initiator
/// @return arbitrationPolicy The address of the arbitration policy
/// @return linkToDisputeEvidence The link of the dispute summary
/// @return targetTag The target tag of the dispute
/// @return currentTag The current tag of the dispute
function disputes(
uint256 disputeId
)
external
view
returns (
address targetIpId,
address disputeInitiator,
address arbitrationPolicy,
bytes32 linkToDisputeEvidence,
bytes32 targetTag,
bytes32 currentTag
);
/// @notice Indicates if a dispute tag is whitelisted
/// @param tag The dispute tag
/// @return allowed Indicates if the dispute tag is whitelisted
function isWhitelistedDisputeTag(bytes32 tag) external view returns (bool allowed);
/// @notice Indicates if an arbitration policy is whitelisted
/// @param arbitrationPolicy The address of the arbitration policy
/// @return allowed Indicates if the arbitration policy is whitelisted
function isWhitelistedArbitrationPolicy(address arbitrationPolicy) external view returns (bool allowed);
/// @notice Indicates if an arbitration relayer is whitelisted for a given arbitration policy
/// @param arbitrationPolicy The address of the arbitration policy
/// @param arbitrationRelayer The address of the arbitration relayer
/// @return allowed Indicates if the arbitration relayer is whitelisted
function isWhitelistedArbitrationRelayer(
address arbitrationPolicy,
address arbitrationRelayer
) external view returns (bool allowed);
/// @notice Arbitration policy for a given ipId
/// @param ipId The ipId
/// @return policy The address of the arbitration policy
function arbitrationPolicies(address ipId) external view returns (address policy);
/// @notice Whitelists a dispute tag
/// @param tag The dispute tag
/// @param allowed Indicates if the dispute tag is whitelisted or not
function whitelistDisputeTag(bytes32 tag, bool allowed) external;
/// @notice Whitelists an arbitration policy
/// @param arbitrationPolicy The address of the arbitration policy
/// @param allowed Indicates if the arbitration policy is whitelisted or not
function whitelistArbitrationPolicy(address arbitrationPolicy, bool allowed) external;
/// @notice Whitelists an arbitration relayer for a given arbitration policy
/// @param arbitrationPolicy The address of the arbitration policy
/// @param arbPolicyRelayer The address of the arbitration relayer
/// @param allowed Indicates if the arbitration relayer is whitelisted or not
function whitelistArbitrationRelayer(address arbitrationPolicy, address arbPolicyRelayer, bool allowed) external;
/// @notice Sets the base arbitration policy
/// @param arbitrationPolicy The address of the arbitration policy
function setBaseArbitrationPolicy(address arbitrationPolicy) external;
/// @notice Sets the arbitration policy for an ipId
/// @param ipId The ipId
/// @param arbitrationPolicy The address of the arbitration policy
function setArbitrationPolicy(address ipId, address arbitrationPolicy) external;
/// @notice Raises a dispute on a given ipId
/// @param targetIpId The ipId that is the target of the dispute
/// @param linkToDisputeEvidence The link of the dispute evidence
/// @param targetTag The target tag of the dispute
/// @param data The data to initialize the policy
/// @return disputeId The id of the newly raised dispute
function raiseDispute(
address targetIpId,
string memory linkToDisputeEvidence,
bytes32 targetTag,
bytes calldata data
) external returns (uint256 disputeId);
/// @notice Sets the dispute judgement on a given dispute. Only whitelisted arbitration relayers can call to judge.
/// @param disputeId The dispute id
/// @param decision The decision of the dispute
/// @param data The data to set the dispute judgement
function setDisputeJudgement(uint256 disputeId, bool decision, bytes calldata data) external;
/// @notice Cancels an ongoing dispute
/// @param disputeId The dispute id
/// @param data The data to cancel the dispute
function cancelDispute(uint256 disputeId, bytes calldata data) external;
/// @notice Resolves a dispute after it has been judged
/// @param disputeId The dispute id
function resolveDispute(uint256 disputeId) external;
/// @notice Returns true if the ipId is tagged with any tag (meaning at least one dispute went through)
/// @param ipId The ipId
/// @return isTagged True if the ipId is tagged
function isIpTagged(address ipId) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @title Interface for IP Account Registry
/// @notice This interface manages the registration and tracking of IP Accounts
interface IIPAccountRegistry {
/// @notice Event emitted when a new IP Account is created
/// @param account The address of the new IP Account
/// @param implementation The address of the IP Account implementation
/// @param chainId The chain ID where the token contract was deployed
/// @param tokenContract The address of the token contract associated with the IP Account
/// @param tokenId The ID of the token associated with the IP Account
event IPAccountRegistered(
address indexed account,
address indexed implementation,
uint256 indexed chainId,
address tokenContract,
uint256 tokenId
);
/// @notice Returns the IPAccount implementation address
function IP_ACCOUNT_IMPL() external view returns (address);
/// @notice Returns the IPAccount salt
function IP_ACCOUNT_SALT() external view returns (bytes32);
/// @notice Returns the public ERC6551 registry address
function ERC6551_PUBLIC_REGISTRY() external view returns (address);
/// @notice Deploys an IPAccount contract with the IPAccount implementation and returns the address of the new IP
/// @dev The IPAccount deployment deltegates to public ERC6551 Registry
/// @param chainId The chain ID where the IP Account will be created
/// @param tokenContract The address of the token contract to be associated with the IP Account
/// @param tokenId The ID of the token to be associated with the IP Account
/// @return ipAccountAddress The address of the newly created IP Account
function registerIpAccount(uint256 chainId, address tokenContract, uint256 tokenId) external returns (address);
/// @notice Returns the IPAccount address for the given NFT token.
/// @param chainId The chain ID where the IP Account is located
/// @param tokenContract The address of the token contract associated with the IP Account
/// @param tokenId The ID of the token associated with the IP Account
/// @return ipAccountAddress The address of the IP Account associated with the given NFT token
function ipAccount(uint256 chainId, address tokenContract, uint256 tokenId) external view returns (address);
/// @notice Returns the IPAccount implementation address.
/// @return The address of the IPAccount implementation
function getIPAccountImpl() external view returns (address);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @title IModuleRegistry
/// @dev This interface defines the methods for a module registry in the Story Protocol.
interface IModuleRegistry {
/// @notice Emitted when a new module is added to the registry.
/// @param name The name of the module.
/// @param module The address of the module.
event ModuleAdded(string name, address indexed module, bytes4 indexed moduleTypeInterfaceId, string moduleType);
/// @notice Emitted when a module is removed from the registry.
/// @param name The name of the module.
/// @param module The address of the module.
event ModuleRemoved(string name, address indexed module);
/// @notice Returns the address of a registered module by its name.
/// @param name The name of the module.
/// @return moduleAddress The address of the module.
function getModule(string memory name) external view returns (address);
/// @notice Returns the module type of a registered module by its address.
/// @param moduleAddress The address of the module.
/// @return moduleType The type of the module as a string.
function getModuleType(address moduleAddress) external view returns (string memory);
/// @notice Returns the interface ID of a registered module type.
/// @param moduleType The name of the module type.
/// @return moduleTypeInterfaceId The interface ID of the module type as bytes4.
function getModuleTypeInterfaceId(string memory moduleType) external view returns (bytes4);
/// @notice Registers a new module type in the registry associate with an interface.
/// @dev Enforced to be only callable by the protocol admin in governance.
/// @param name The name of the module type to be registered.
/// @param interfaceId The interface ID associated with the module type.
function registerModuleType(string memory name, bytes4 interfaceId) external;
/// @notice Removes a module type from the registry.
/// @dev Enforced to be only callable by the protocol admin in governance.
/// @param name The name of the module type to be removed.
function removeModuleType(string memory name) external;
/// @notice Registers a new module in the registry.
/// @dev Enforced to be only callable by the protocol admin in governance.
/// @param name The name of the module.
/// @param moduleAddress The address of the module.
function registerModule(string memory name, address moduleAddress) external;
/// @notice Registers a new module in the registry with an associated module type.
/// @param name The name of the module to be registered.
/// @param moduleAddress The address of the module.
/// @param moduleType The type of the module being registered.
function registerModule(string memory name, address moduleAddress, string memory moduleType) external;
/// @notice Removes a module from the registry.
/// @dev Enforced to be only callable by the protocol admin in governance.
/// @param name The name of the module.
function removeModule(string memory name) external;
/// @notice Checks if a module is registered in the protocol.
/// @param moduleAddress The address of the module.
/// @return isRegistered True if the module is registered, false otherwise.
function isRegistered(address moduleAddress) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { IMetadataProvider } from "./IMetadataProvider.sol";
import { IIPAssetRegistry } from "../IIPAssetRegistry.sol";
/// @title Metadata Provider Interface
interface IMetadataProviderMigratable is IMetadataProvider {
/// @notice Returns the protocol-wide IP asset registry.
function IP_ASSET_REGISTRY() external view returns (IIPAssetRegistry);
/// @notice Returns the new metadata provider IP assets may migrate to.
function upgradeProvider() external returns (IMetadataProvider);
/// @notice Sets a upgrade provider for users to migrate their metadata to.
/// @param provider The address of the new metadata provider to migrate to.
function setUpgradeProvider(address provider) external;
/// @notice Updates the provider used by the IP asset, migrating existing metadata to the new provider, and adding
/// new metadata.
/// @param ipId The address identifier of the IP asset.
/// @param extraMetadata Additional metadata in bytes used by the new metadata provider.
function upgrade(address payable ipId, bytes memory extraMetadata) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @notice Resolver Interface
interface IResolver {
/// @notice Checks whether the resolver IP interface is supported.
function supportsInterface(bytes4 id) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { IAccessController } from "../interfaces/IAccessController.sol";
import { IPAccountChecker } from "../lib/registries/IPAccountChecker.sol";
import { IIPAccountRegistry } from "../interfaces/registries/IIPAccountRegistry.sol";
import { Errors } from "../lib/Errors.sol";
/// @title AccessControlled
/// @notice Provides a base contract for access control functionalities.
/// @dev This abstract contract implements basic access control mechanisms with an emphasis
/// on IP account verification and permission checks.
/// It is designed to be used as a base contract for other contracts that require access control.
/// It provides modifiers and functions to verify if the caller has the necessary permission
/// and is a registered IP account.
abstract contract AccessControlled {
using IPAccountChecker for IIPAccountRegistry;
/// @notice The IAccessController instance for permission checks.
IAccessController public immutable ACCESS_CONTROLLER;
/// @notice The IIPAccountRegistry instance for IP account verification.
IIPAccountRegistry public immutable IP_ACCOUNT_REGISTRY;
/// @dev Initializes the contract by setting the ACCESS_CONTROLLER and IP_ACCOUNT_REGISTRY addresses.
/// @param accessController The address of the AccessController contract.
/// @param ipAccountRegistry The address of the IPAccountRegistry contract.
constructor(address accessController, address ipAccountRegistry) {
if (accessController == address(0)) revert Errors.AccessControlled__ZeroAddress();
if (ipAccountRegistry == address(0)) revert Errors.AccessControlled__ZeroAddress();
ACCESS_CONTROLLER = IAccessController(accessController);
IP_ACCOUNT_REGISTRY = IIPAccountRegistry(ipAccountRegistry);
}
/// @notice Verifies that the caller has the necessary permission for the given IPAccount.
/// @dev Modifier that calls _verifyPermission to check if the provided IP account has the required permission.
/// modules can use this modifier to check if the caller has the necessary permission.
/// @param ipAccount The address of the IP account to verify.
modifier verifyPermission(address ipAccount) {
_verifyPermission(ipAccount);
_;
}
/// @notice Ensures that the caller is a registered IP account.
/// @dev Modifier that checks if the msg.sender is a registered IP account.
/// modules can use this modifier to check if the caller is a registered IP account.
/// so that enforce only registered IP Account can call the functions.
modifier onlyIpAccount() {
if (!IP_ACCOUNT_REGISTRY.isIpAccount(msg.sender)) {
revert Errors.AccessControlled__CallerIsNotIpAccount(msg.sender);
}
_;
}
/// @dev Internal function to verify if the caller (msg.sender) has the required permission to execute
/// the function on provided ipAccount.
/// @param ipAccount The address of the IP account to verify.
function _verifyPermission(address ipAccount) internal view {
if (!IP_ACCOUNT_REGISTRY.isIpAccount(ipAccount)) {
revert Errors.AccessControlled__NotIpAccount(ipAccount);
}
if (msg.sender != ipAccount) {
// revert if the msg.sender does not have permission
ACCESS_CONTROLLER.checkPermission(ipAccount, msg.sender, address(this), msg.sig);
}
}
/// @dev Internal function to check if the caller (msg.sender) has the required permission to execute
/// the function on provided ipAccount, returning a boolean.
/// @param ipAccount The address of the IP account to check.
/// @return bool Returns true if the caller has permission, false otherwise.
function _hasPermission(address ipAccount) internal view returns (bool) {
if (!IP_ACCOUNT_REGISTRY.isIpAccount(ipAccount)) {
return false;
}
if (msg.sender == ipAccount) {
return true;
}
try ACCESS_CONTROLLER.checkPermission(ipAccount, msg.sender, address(this), msg.sig) {
return true;
} catch {
return false;
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @title Key Value Resolver Interface
interface IKeyValueResolver {
/// @notice Emits when a new key-value pair is set for the resolver.
event KeyValueSet(address indexed ipId, string indexed key, string value);
/// @notice Sets the string value for a specified key of an IP ID.
/// @dev Enforced to be only callable by users with valid permission to call on behalf of the ipId.
/// @param ipId The canonical identifier of the IP asset.
/// @param key The string parameter key to update.
/// @param val The value to set for the specified key.
function setValue(address ipId, string calldata key, string calldata val) external;
/// @notice Retrieves the string value associated with a key for an IP asset.
/// @param key The string parameter key to query.
/// @return value The value associated with the specified key.
function value(address ipId, string calldata key) external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165Checker.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Library used to query support of an interface declared via {IERC165}.
*
* Note that these functions return the actual result of the query: they do not
* `revert` if an interface is not supported. It is up to the caller to decide
* what to do in these cases.
*/
library ERC165Checker {
// As per the EIP-165 spec, no interface should ever match 0xffffffff
bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff;
/**
* @dev Returns true if `account` supports the {IERC165} interface.
*/
function supportsERC165(address account) internal view returns (bool) {
// Any contract that implements ERC165 must explicitly indicate support of
// InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
return
supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&
!supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID);
}
/**
* @dev Returns true if `account` supports the interface defined by
* `interfaceId`. Support for {IERC165} itself is queried automatically.
*
* See {IERC165-supportsInterface}.
*/
function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
// query support of both ERC165 as per the spec and support of _interfaceId
return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);
}
/**
* @dev Returns a boolean array where each value corresponds to the
* interfaces passed in and whether they're supported or not. This allows
* you to batch check interfaces for a contract where your expectation
* is that some interfaces may not be supported.
*
* See {IERC165-supportsInterface}.
*/
function getSupportedInterfaces(
address account,
bytes4[] memory interfaceIds
) internal view returns (bool[] memory) {
// an array of booleans corresponding to interfaceIds and whether they're supported or not
bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
// query support of ERC165 itself
if (supportsERC165(account)) {
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);
}
}
return interfaceIdsSupported;
}
/**
* @dev Returns true if `account` supports all the interfaces defined in
* `interfaceIds`. Support for {IERC165} itself is queried automatically.
*
* Batch-querying can lead to gas savings by skipping repeated checks for
* {IERC165} support.
*
* See {IERC165-supportsInterface}.
*/
function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
// query support of ERC165 itself
if (!supportsERC165(account)) {
return false;
}
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
return false;
}
}
// all interfaces supported
return true;
}
/**
* @notice Query if a contract implements an interface, does not check ERC165 support
* @param account The address of the contract to query for support of an interface
* @param interfaceId The interface identifier, as specified in ERC-165
* @return true if the contract at account indicates support of the interface with
* identifier interfaceId, false otherwise
* @dev Assumes that account contains a contract that supports ERC165, otherwise
* the behavior of this method is undefined. This precondition can be checked
* with {supportsERC165}.
*
* Some precompiled contracts will falsely indicate support for a given interface, so caution
* should be exercised when using this function.
*
* Interface identification is specified in ERC-165.
*/
function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
// prepare call
bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId));
// perform static call
bool success;
uint256 returnSize;
uint256 returnValue;
assembly {
success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
returnSize := returndatasize()
returnValue := mload(0x00)
}
return success && returnSize >= 0x20 && returnValue > 0;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import { Errors } from "../lib/Errors.sol";
import { IGovernance } from "../interfaces/governance/IGovernance.sol";
import { IGovernable } from "../interfaces/governance/IGovernable.sol";
import { GovernanceLib } from "../lib/GovernanceLib.sol";
/// @title Governable
/// @dev All contracts managed by governance should inherit from this contract.
abstract contract Governable is IGovernable {
/// @notice The address of the governance.
address public governance;
/// @dev Ensures that the function is called by the protocol admin.
modifier onlyProtocolAdmin() {
if (!IGovernance(governance).hasRole(GovernanceLib.PROTOCOL_ADMIN, msg.sender)) {
revert Errors.Governance__OnlyProtocolAdmin();
}
_;
}
modifier whenNotPaused() {
if (IGovernance(governance).getState() == GovernanceLib.ProtocolState.Paused) {
revert Errors.Governance__ProtocolPaused();
}
_;
}
/// @notice Constructs a new Governable contract.
/// @param governance_ The address of the governance.
constructor(address governance_) {
if (governance_ == address(0)) revert Errors.Governance__ZeroAddress();
governance = governance_;
emit GovernanceUpdated(governance);
}
/// @notice Sets a new governance address.
/// @param newGovernance The address of the new governance.
function setGovernance(address newGovernance) external onlyProtocolAdmin {
if (newGovernance == address(0)) revert Errors.Governance__ZeroAddress();
if (!ERC165Checker.supportsInterface(newGovernance, type(IGovernance).interfaceId))
revert Errors.Governance__UnsupportedInterface("IGovernance");
if (IGovernance(newGovernance).getState() != IGovernance(governance).getState())
revert Errors.Governance__InconsistentState();
governance = newGovernance;
emit GovernanceUpdated(newGovernance);
}
/// @notice Returns the current governance address.
/// @return governance The address of the current governance.
function getGovernance() external view returns (address) {
return governance;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { IModule } from "../../modules/base/IModule.sol";
/// @title RoyaltyModule interface
interface IRoyaltyModule is IModule {
/// @notice Event emitted when a royalty policy is whitelisted
/// @param royaltyPolicy The address of the royalty policy
/// @param allowed Indicates if the royalty policy is whitelisted or not
event RoyaltyPolicyWhitelistUpdated(address royaltyPolicy, bool allowed);
/// @notice Event emitted when a royalty token is whitelisted
/// @param token The address of the royalty token
/// @param allowed Indicates if the royalty token is whitelisted or not
event RoyaltyTokenWhitelistUpdated(address token, bool allowed);
/// @notice Event emitted when royalties are paid
/// @param receiverIpId The ID of IP asset that receives the royalties
/// @param payerIpId The ID of IP asset that pays the royalties
/// @param sender The address that pays the royalties on behalf of the payer ID of IP asset
/// @param token The token that is used to pay the royalties
/// @param amount The amount that is paid
event RoyaltyPaid(address receiverIpId, address payerIpId, address sender, address token, uint256 amount);
/// @notice Event emitted when the license minting fee is paid
/// @param receiverIpId The ipId that receives the royalties
/// @param payerAddress The address that pays the royalties
/// @param token The token that is used to pay the royalties
/// @param amount The amount paid
event LicenseMintingFeePaid(address receiverIpId, address payerAddress, address token, uint256 amount);
/// @notice Returns the licensing module address
function LICENSING_MODULE() external view returns (address);
/// @notice Indicates if a royalty policy is whitelisted
/// @param royaltyPolicy The address of the royalty policy
/// @return isWhitelisted True if the royalty policy is whitelisted
function isWhitelistedRoyaltyPolicy(address royaltyPolicy) external view returns (bool);
/// @notice Indicates if a royalty token is whitelisted
/// @param token The address of the royalty token
/// @return isWhitelisted True if the royalty token is whitelisted
function isWhitelistedRoyaltyToken(address token) external view returns (bool);
/// @notice Indicates the royalty policy for a given IP asset
/// @param ipId The ID of IP asset
/// @return royaltyPolicy The address of the royalty policy
function royaltyPolicies(address ipId) external view returns (address);
/// @notice Whitelist a royalty policy
/// @dev Enforced to be only callable by the protocol admin
/// @param royaltyPolicy The address of the royalty policy
/// @param allowed Indicates if the royalty policy is whitelisted or not
function whitelistRoyaltyPolicy(address royaltyPolicy, bool allowed) external;
/// @notice Whitelist a royalty token
/// @dev Enforced to be only callable by the protocol admin
/// @param token The token address
/// @param allowed Indicates if the token is whitelisted or not
function whitelistRoyaltyToken(address token, bool allowed) external;
/// @notice Executes royalty related logic on license minting
/// @dev Enforced to be only callable by LicensingModule
/// @param ipId The ipId whose license is being minted (licensor)
/// @param royaltyPolicy The royalty policy address of the license being minted
/// @param licenseData The license data custom to each the royalty policy
/// @param externalData The external data custom to each the royalty policy
function onLicenseMinting(
address ipId,
address royaltyPolicy,
bytes calldata licenseData,
bytes calldata externalData
) external;
/// @notice Executes royalty related logic on linking to parents
/// @dev Enforced to be only callable by LicensingModule
/// @param ipId The children ipId that is being linked to parents
/// @param royaltyPolicy The common royalty policy address of all the licenses being burned
/// @param parentIpIds The parent ipIds that the children ipId is being linked to
/// @param licenseData The license data custom to each the royalty policy
/// @param externalData The external data custom to each the royalty policy
function onLinkToParents(
address ipId,
address royaltyPolicy,
address[] calldata parentIpIds,
bytes[] memory licenseData,
bytes calldata externalData
) external;
/// @notice Allows the function caller to pay royalties to the receiver IP asset on behalf of the payer IP asset.
/// @param receiverIpId The ID of the IP asset that receives the royalties
/// @param payerIpId The ID of the IP asset that pays the royalties
/// @param token The token to use to pay the royalties
/// @param amount The amount to pay
function payRoyaltyOnBehalf(address receiverIpId, address payerIpId, address token, uint256 amount) external;
/// @notice Allows to pay the minting fee for a license
/// @param receiverIpId The ipId that receives the royalties
/// @param payerAddress The address that pays the royalties
/// @param licenseRoyaltyPolicy The royalty policy of the license being minted
/// @param token The token to use to pay the royalties
/// @param amount The amount to pay
function payLicenseMintingFee(
address receiverIpId,
address payerAddress,
address licenseRoyaltyPolicy,
address token,
uint256 amount
) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @title RoyaltyPolicy interface
interface IRoyaltyPolicy {
/// @notice Executes royalty related logic on minting a license
/// @dev Enforced to be only callable by RoyaltyModule
/// @param ipId The ipId whose license is being minted (licensor)
/// @param licenseData The license data custom to each the royalty policy
/// @param externalData The external data custom to each the royalty policy
function onLicenseMinting(address ipId, bytes calldata licenseData, bytes calldata externalData) external;
/// @notice Executes royalty related logic on linking to parents
/// @dev Enforced to be only callable by RoyaltyModule
/// @param ipId The children ipId that is being linked to parents
/// @param parentIpIds The parent ipIds that the children ipId is being linked to
/// @param licenseData The license data custom to each the royalty policy
/// @param externalData The external data custom to each the royalty policy
function onLinkToParents(
address ipId,
address[] calldata parentIpIds,
bytes[] memory licenseData,
bytes calldata externalData
) external;
/// @notice Allows the caller to pay royalties to the given IP asset
/// @param caller The caller is the address from which funds will transferred from
/// @param ipId The ipId of the receiver of the royalties
/// @param token The token to pay
/// @param amount The amount to pay
function onRoyaltyPayment(address caller, address ipId, address token, uint256 amount) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (token/ERC1155/IERC1155.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*/
interface IERC1155 is IERC165 {
/**
* @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the value of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(
address[] calldata accounts,
uint256[] calldata ids
) external view returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`.
*
* WARNING: This function can potentially allow a reentrancy attack when transferring tokens
* to an untrusted contract, when invoking {onERC1155Received} on the receiver.
* Ensure to follow the checks-effects-interactions pattern and consider employing
* reentrancy guards when interacting with untrusted contracts.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `value` amount.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* WARNING: This function can potentially allow a reentrancy attack when transferring tokens
* to an untrusted contract, when invoking {onERC1155BatchReceived} on the receiver.
* Ensure to follow the checks-effects-interactions pattern and consider employing
* reentrancy guards when interacting with untrusted contracts.
*
* Emits either a {TransferSingle} or a {TransferBatch} event, depending on the length of the array arguments.
*
* Requirements:
*
* - `ids` and `values` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @title Metadata Provider Interface
interface IMetadataProvider {
/// @notice Emits when canonical metadata was set for a specific IP asset.
/// @param ipId The address of the IP asset.
/// @param metadata The encoded metadata associated with the IP asset.
event MetadataSet(address ipId, bytes metadata);
/// @notice Gets the metadata associated with an IP asset.
/// @param ipId The address identifier of the IP asset.
/// @return metadata The encoded metadata associated with the IP asset.
function getMetadata(address ipId) external view returns (bytes memory);
/// @notice Sets the metadata associated with an IP asset.
/// @param ipId The address identifier of the IP asset.
/// @param metadata The metadata in bytes to associate with the IP asset.
function setMetadata(address ipId, bytes memory metadata) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { AccessPermission } from "../lib/AccessPermission.sol";
interface IAccessController {
/// @notice Emitted when a permission is set.
/// @param ipAccount The address of the IP account that grants the permission for `signer`
/// @param signer The address that can call `to` on behalf of the IP account
/// @param to The address that can be called by the `signer` (currently only modules can be `to`)
/// @param func The function selector of `to` that can be called by the `signer` on behalf of the `ipAccount`
/// @param permission The permission level
event PermissionSet(
address ipAccountOwner,
address indexed ipAccount,
address indexed signer,
address indexed to,
bytes4 func,
uint8 permission
);
/// @notice Sets a batch of permissions in a single transaction.
/// @dev This function allows setting multiple permissions at once. Pausable.
/// @param permissions An array of `Permission` structs, each representing the permission to be set.
function setBatchPermissions(AccessPermission.Permission[] memory permissions) external;
/// @notice Sets the permission for all IPAccounts
/// @dev Enforced to be only callable by the protocol admin in governance.
/// @param signer The address that can call `to` on behalf of the IP account
/// @param to The address that can be called by the `signer` (currently only modules can be `to`)
/// @param func The function selector of `to` that can be called by the `signer` on behalf of the `ipAccount`
/// @param permission The new permission level
function setGlobalPermission(address signer, address to, bytes4 func, uint8 permission) external;
/// @notice Sets the permission for a specific function call
/// @dev Each policy is represented as a mapping from an IP account address to a signer address to a recipient
/// address to a function selector to a permission level. The permission level can be 0 (ABSTAIN), 1 (ALLOW), or
/// 2 (DENY).
/// @dev By default, all policies are set to 0 (ABSTAIN), which means that the permission is not set.
/// The owner of ipAccount by default has all permission.
/// address(0) => wildcard
/// bytes4(0) => wildcard
/// Specific permission overrides wildcard permission.
/// @param ipAccount The address of the IP account that grants the permission for `signer`
/// @param signer The address that can call `to` on behalf of the `ipAccount`
/// @param to The address that can be called by the `signer` (currently only modules can be `to`)
/// @param func The function selector of `to` that can be called by the `signer` on behalf of the `ipAccount`
/// @param permission The new permission level
function setPermission(address ipAccount, address signer, address to, bytes4 func, uint8 permission) external;
/// @notice Checks the permission level for a specific function call. Reverts if permission is not granted.
/// Otherwise, the function is a noop.
/// @dev This function checks the permission level for a specific function call.
/// If a specific permission is set, it overrides the general (wildcard) permission.
/// If the current level permission is ABSTAIN, the final permission is determined by the upper level.
/// @param ipAccount The address of the IP account that grants the permission for `signer`
/// @param signer The address that can call `to` on behalf of the `ipAccount`
/// @param to The address that can be called by the `signer` (currently only modules can be `to`)
/// @param func The function selector of `to` that can be called by the `signer` on behalf of the `ipAccount`
function checkPermission(address ipAccount, address signer, address to, bytes4 func) external view;
/// @notice Returns the permission level for a specific function call.
/// @param ipAccount The address of the IP account that grants the permission for `signer`
/// @param signer The address that can call `to` on behalf of the `ipAccount`
/// @param to The address that can be called by the `signer` (currently only modules can be `to`)
/// @param func The function selector of `to` that can be called by the `signer` on behalf of the `ipAccount`
/// @return permission The current permission level for the function call on `to` by the `signer` for `ipAccount`
function getPermission(address ipAccount, address signer, address to, bytes4 func) external view returns (uint8);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import { IERC6551Account } from "erc6551/interfaces/IERC6551Account.sol";
import { IIPAccountRegistry } from "../../interfaces/registries/IIPAccountRegistry.sol";
import { IIPAccount } from "../..//interfaces/IIPAccount.sol";
/// @title IPAccountChecker
/// @dev This library provides utility functions to check the registration and validity of IP Accounts.
/// It uses the ERC165 standard for contract introspection and the IIPAccountRegistry interface
/// for account registration checks.
library IPAccountChecker {
/// @notice Returns true if the IPAccount is registered.
/// @param chainId_ The chain ID where the IP Account is located.
/// @param tokenContract_ The address of the token contract associated with the IP Account.
/// @param tokenId_ The ID of the token associated with the IP Account.
/// @return True if the IP Account is registered, false otherwise.
function isRegistered(
IIPAccountRegistry ipAccountRegistry_,
uint256 chainId_,
address tokenContract_,
uint256 tokenId_
) external view returns (bool) {
return ipAccountRegistry_.ipAccount(chainId_, tokenContract_, tokenId_).code.length != 0;
}
/// @notice Checks if the given address is a valid IP Account.
/// @param ipAccountRegistry_ The IP Account registry contract.
/// @param ipAccountAddress_ The address to check.
/// @return True if the address is a valid IP Account, false otherwise.
function isIpAccount(
IIPAccountRegistry ipAccountRegistry_,
address ipAccountAddress_
) external view returns (bool) {
if (ipAccountAddress_ == address(0)) return false;
if (ipAccountAddress_.code.length == 0) return false;
if (!ERC165Checker.supportsERC165(ipAccountAddress_)) return false;
if (!ERC165Checker.supportsInterface(ipAccountAddress_, type(IERC6551Account).interfaceId)) return false;
if (!ERC165Checker.supportsInterface(ipAccountAddress_, type(IIPAccount).interfaceId)) return false;
(uint chainId, address tokenContract, uint tokenId) = IIPAccount(payable(ipAccountAddress_)).token();
return ipAccountAddress_ == ipAccountRegistry_.ipAccount(chainId, tokenContract, tokenId);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol";
import { GovernanceLib } from "../../lib/GovernanceLib.sol";
/// @title IGovernance
/// @dev This interface defines the governance functionality for the protocol.
interface IGovernance is IAccessControl {
/// @notice Emitted when the protocol state is set
/// @param account The address that triggered the state change
/// @param prevState The previous state of the protocol
/// @param newState The new state of the protocol
/// @param timestamp The time when the state change occurred
event StateSet(
address indexed account,
GovernanceLib.ProtocolState prevState,
GovernanceLib.ProtocolState newState,
uint256 timestamp
);
/// @notice Sets the state of the protocol
/// @dev This function can only be called by an account with the appropriate role
/// @param newState The new state to set for the protocol
function setState(GovernanceLib.ProtocolState newState) external;
/// @notice Returns the current state of the protocol
/// @return state The current state of the protocol
function getState() external view returns (GovernanceLib.ProtocolState);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @title IGovernable
/// @notice This is the interface for the Lens Protocol main governance functions.
interface IGovernable {
/// @notice Emitted when the governance is updated
/// @param newGovernance The address of the new governance
event GovernanceUpdated(address indexed newGovernance);
/// @notice Sets the governance address
/// @param newGovernance The address of the new governance
function setGovernance(address newGovernance) external;
/// @notice Returns the current governance address
/// @return The address of the current governance
function getGovernance() external view returns (address);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @title Governance
/// @dev This library provides types for Story Protocol Governance.
library GovernanceLib {
bytes32 public constant PROTOCOL_ADMIN = bytes32(0);
/// @notice An enum containing the different states the protocol can be in.
/// @param Unpaused The unpaused state.
/// @param Paused The paused state.
enum ProtocolState {
Unpaused,
Paused
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @title Access Permission Library
/// @notice Library for IPAccount access control permissions.
/// These permissions are used by the AccessController.
library AccessPermission {
/// @notice ABSTAIN means having not enough information to make decision at current level, deferred decision to up
/// level permission.
uint8 public constant ABSTAIN = 0;
/// @notice ALLOW means the permission is granted to transaction signer to call the function.
uint8 public constant ALLOW = 1;
/// @notice DENY means the permission is denied to transaction signer to call the function.
uint8 public constant DENY = 2;
/// @notice This struct is used to represent permissions in batch operations within the AccessController.
/// @param ipAccount The address of the IP account that grants the permission for `signer`
/// @param signer The address that can call `to` on behalf of the `ipAccount`
/// @param to The address that can be called by the `signer` (currently only modules can be `to`)
/// @param func The function selector of `to` that can be called by the `signer` on behalf of the `ipAccount`
/// @param permission The permission level for the transaction (0 = ABSTAIN, 1 = ALLOW, 2 = DENY).
struct Permission {
address ipAccount;
address signer;
address to;
bytes4 func;
uint8 permission;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @dev the ERC-165 identifier for this interface is `0x6faff5f1`
interface IERC6551Account {
/**
* @dev Allows the account to receive Ether.
*
* Accounts MUST implement a `receive` function.
*
* Accounts MAY perform arbitrary logic to restrict conditions
* under which Ether can be received.
*/
receive() external payable;
/**
* @dev Returns the identifier of the non-fungible token which owns the account.
*
* The return value of this function MUST be constant - it MUST NOT change over time.
*
* @return chainId The EIP-155 ID of the chain the token exists on
* @return tokenContract The contract address of the token
* @return tokenId The ID of the token
*/
function token()
external
view
returns (uint256 chainId, address tokenContract, uint256 tokenId);
/**
* @dev Returns a value that SHOULD be modified each time the account changes state.
*
* @return The current account state
*/
function state() external view returns (uint256);
/**
* @dev Returns a magic value indicating whether a given signer is authorized to act on behalf
* of the account.
*
* MUST return the bytes4 magic value 0x523e3260 if the given signer is valid.
*
* By default, the holder of the non-fungible token the account is bound to MUST be considered
* a valid signer.
*
* Accounts MAY implement additional authorization logic which invalidates the holder as a
* signer or grants signing permissions to other non-holder accounts.
*
* @param signer The address to check signing authorization for
* @param context Additional data used to determine whether the signer is valid
* @return magicValue Magic value indicating whether the signer is valid
*/
function isValidSigner(address signer, bytes calldata context)
external
view
returns (bytes4 magicValue);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { IERC721Receiver } from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import { IERC1155Receiver } from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import { IERC6551Account } from "erc6551/interfaces/IERC6551Account.sol";
/// @title IIPAccount
/// @dev IPAccount is a token-bound account that adopts the EIP-6551 standard.
/// These accounts are deployed at deterministic addresses through the official 6551 account registry.
/// As a deployed smart contract, IPAccount can store IP-related information,
/// like ownership of other NFTs such as license NFT or Royalty NFT.
/// IPAccount can interact with modules by making calls as a normal transaction sender.
/// This allows for seamless operations on the state and data of IP.
/// IPAccount is core identity for all actions.
interface IIPAccount is IERC6551Account, IERC721Receiver, IERC1155Receiver {
/// @notice Emitted when a transaction is executed.
/// @param to The recipient of the transaction.
/// @param value The amount of Ether sent.
/// @param data The data sent along with the transaction.
/// @param nonce The nonce of the transaction.
event Executed(address indexed to, uint256 value, bytes data, uint256 nonce);
/// @notice Emitted when a transaction is executed on behalf of the signer.
/// @param to The recipient of the transaction.
/// @param value The amount of Ether sent.
/// @param data The data sent along with the transaction.
/// @param nonce The nonce of the transaction.
/// @param deadline The deadline of the transaction signature.
/// @param signer The signer of the transaction.
/// @param signature The signature of the transaction, EIP-712 encoded.
event ExecutedWithSig(
address indexed to,
uint256 value,
bytes data,
uint256 nonce,
uint256 deadline,
address indexed signer,
bytes signature
);
/// @notice Returns the IPAccount's internal nonce for transaction ordering.
function state() external view returns (uint256);
/// @notice Returns the identifier of the non-fungible token which owns the account
/// @return chainId The EIP-155 ID of the chain the token exists on
/// @return tokenContract The contract address of the token
/// @return tokenId The ID of the token
function token() external view returns (uint256, address, uint256);
/// @notice Checks if the signer is valid for the given data
/// @param signer The signer to check
/// @param data The data to check against
/// @return The function selector if the signer is valid, 0 otherwise
function isValidSigner(address signer, bytes calldata data) external view returns (bytes4);
/// @notice Returns the owner of the IP Account.
/// @return owner The address of the owner.
function owner() external view returns (address);
/// @notice Executes a transaction from the IP Account on behalf of the signer.
/// @param to The recipient of the transaction.
/// @param value The amount of Ether to send.
/// @param data The data to send along with the transaction.
/// @param signer The signer of the transaction.
/// @param deadline The deadline of the transaction signature.
/// @param signature The signature of the transaction, EIP-712 encoded.
/// @return result The return data from the transaction.
function executeWithSig(
address to,
uint256 value,
bytes calldata data,
address signer,
uint256 deadline,
bytes calldata signature
) external payable returns (bytes memory);
/// @notice Executes a transaction from the IP Account.
/// @param to The recipient of the transaction.
/// @param value The amount of Ether to send.
/// @param data The data to send along with the transaction.
/// @return result The return data from the transaction.
function execute(address to, uint256 value, bytes calldata data) external payable returns (bytes memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Interface that must be implemented by smart contracts in order to receive
* ERC-1155 token transfers.
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}{
"remappings": [
"@ethereum-waffle/=node_modules/@ethereum-waffle/",
"@openzeppelin/=node_modules/@openzeppelin/",
"forge-std/=node_modules/forge-std/src/",
"ds-test/=node_modules/ds-test/src/",
"base64-sol/=node_modules/base64-sol/",
"eth-gas-reporter/=node_modules/eth-gas-reporter/",
"hardhat-deploy/=node_modules/hardhat-deploy/",
"hardhat/=node_modules/hardhat/",
"erc6551/=node_modules/erc6551/",
"openzeppelin-contracts/=lib/reference/lib/openzeppelin-contracts/",
"reference/=lib/reference/"
],
"optimizer": {
"enabled": true,
"runs": 20000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"libraries": {
"contracts/lib/registries/IPAccountChecker.sol": {
"IPAccountChecker": "0x36e93affeca875ebcef53e922a4b716ad2a508a9"
}
}
}Contract ABI
API[{"inputs":[{"internalType":"address","name":"assetRegistry","type":"address"},{"internalType":"address","name":"licensingModule","type":"address"},{"internalType":"address","name":"resolverAddr","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"RegistrationModule__InvalidOwner","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"ipId","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"licenseIds","type":"uint256[]"}],"name":"DerivativeIPRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"ipId","type":"address"},{"indexed":true,"internalType":"uint256","name":"policyId","type":"uint256"}],"name":"RootIPRegistered","type":"event"},{"inputs":[],"name":"ipResolver","outputs":[{"internalType":"contract IPResolver","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"licenseIds","type":"uint256[]"},{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"ipName","type":"string"},{"internalType":"bytes32","name":"contentHash","type":"bytes32"},{"internalType":"string","name":"externalURL","type":"string"},{"internalType":"bytes","name":"royaltyContext","type":"bytes"}],"name":"registerDerivativeIp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"policyId","type":"uint256"},{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"ipName","type":"string"},{"internalType":"bytes32","name":"contentHash","type":"bytes32"},{"internalType":"string","name":"externalURL","type":"string"}],"name":"registerRootIp","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b506040516110f43803806110f483398101604081905261002f9161008e565b600080546001600160a01b03199081166001600160a01b0393841617909155600280548216938316939093179092556001805490921692169190911790556100d1565b80516001600160a01b038116811461008957600080fd5b919050565b6000806000606084860312156100a357600080fd5b6100ac84610072565b92506100ba60208501610072565b91506100c860408501610072565b90509250925092565b611014806100e06000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806317f248851161005057806317f24885146100dd5780634f52e7a2146100f2578063ec4efa391461012a57600080fd5b806301ffc9a71461006c57806306fdde0314610094575b600080fd5b61007f61007a3660046109c6565b61014a565b60405190151581526020015b60405180910390f35b6100d06040518060400160405280601381526020017f524547495354524154494f4e5f4d4f44554c450000000000000000000000000081525081565b60405161008b9190610a73565b6100f06100eb366004610c23565b6101e3565b005b610105610100366004610d0b565b6105dd565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161008b565b6000546101059073ffffffffffffffffffffffffffffffffffffffff1681565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f06fdde030000000000000000000000000000000000000000000000000000000014806101dd57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810188905260009073ffffffffffffffffffffffffffffffffffffffff8a1690636352211e90602401602060405180830381865afa158015610251573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102759190610da5565b90503373ffffffffffffffffffffffffffffffffffffffff82161480159061033057506040517fe985e9c500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301523360248301528a169063e985e9c590604401602060405180830381865afa15801561030a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061032e9190610dc2565b155b15610367576040517f7748d9ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006040518060a001604052808981526020018881526020014267ffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff16815260200187878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040516103f49190602001610de4565b60405160208183030381529060405290506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d61f3d468d8d60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff166001886040518763ffffffff1660e01b815260040161048d96959493929190610e82565b6020604051808303816000875af11580156104ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d09190610da5565b9050600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639f69e70d8e8e8489896040518663ffffffff1660e01b8152600401610535959493929190610f26565b600060405180830381600087803b15801561054f57600080fd5b505af1158015610563573d6000803e3d6000fd5b505050508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f0300748d3720c0777d8645f4affde2a3a29c8515e10a7a31345d954bd9aed7b48f8f6040516105c6929190610fa9565b60405180910390a350505050505050505050505050565b6040517f6352211e00000000000000000000000000000000000000000000000000000000815260048101869052600090819073ffffffffffffffffffffffffffffffffffffffff891690636352211e90602401602060405180830381865afa15801561064d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106719190610da5565b90503373ffffffffffffffffffffffffffffffffffffffff82161480159061072c57506040517fe985e9c500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff828116600483015233602483015289169063e985e9c590604401602060405180830381865afa158015610706573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072a9190610dc2565b155b15610763576040517f7748d9ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006040518060a001604052808881526020018781526020014267ffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff16815260200186868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040516107f09190602001610de4565b60405160208183030381529060405290506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d61f3d468c8c60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff166001886040518763ffffffff1660e01b815260040161088996959493929190610e82565b6020604051808303816000875af11580156108a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108cc9190610da5565b90508a15610973576002546040517f7305424f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018e905290911690637305424f906044016020604051808303816000875af115801561094d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109719190610fc5565b505b6040518b9073ffffffffffffffffffffffffffffffffffffffff83169033907fa6e4d1983948888a2be7e084c14834fc01066c7b1173b1d505a1a882ae310a3e90600090a49a9950505050505050505050565b6000602082840312156109d857600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610a0857600080fd5b9392505050565b6000815180845260005b81811015610a3557602081850181015186830182015201610a19565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000610a086020830184610a0f565b60008083601f840112610a9857600080fd5b50813567ffffffffffffffff811115610ab057600080fd5b6020830191508360208260051b8501011115610acb57600080fd5b9250929050565b73ffffffffffffffffffffffffffffffffffffffff81168114610af457600080fd5b50565b8035610b0281610ad2565b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f830112610b4757600080fd5b813567ffffffffffffffff80821115610b6257610b62610b07565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715610ba857610ba8610b07565b81604052838152866020858801011115610bc157600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008083601f840112610bf357600080fd5b50813567ffffffffffffffff811115610c0b57600080fd5b602083019150836020828501011115610acb57600080fd5b60008060008060008060008060008060e08b8d031215610c4257600080fd5b8a3567ffffffffffffffff80821115610c5a57600080fd5b610c668e838f01610a86565b909c509a508a9150610c7a60208e01610af7565b995060408d0135985060608d0135915080821115610c9757600080fd5b610ca38e838f01610b36565b975060808d0135965060a08d0135915080821115610cc057600080fd5b610ccc8e838f01610be1565b909650945060c08d0135915080821115610ce557600080fd5b50610cf28d828e01610be1565b915080935050809150509295989b9194979a5092959850565b600080600080600080600060c0888a031215610d2657600080fd5b873596506020880135610d3881610ad2565b955060408801359450606088013567ffffffffffffffff80821115610d5c57600080fd5b610d688b838c01610b36565b955060808a0135945060a08a0135915080821115610d8557600080fd5b50610d928a828b01610be1565b989b979a50959850939692959293505050565b600060208284031215610db757600080fd5b8151610a0881610ad2565b600060208284031215610dd457600080fd5b81518015158114610a0857600080fd5b602081526000825160a06020840152610e0060c0840182610a0f565b90506020840151604084015267ffffffffffffffff604085015116606084015273ffffffffffffffffffffffffffffffffffffffff606085015116608084015260808401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160a0850152610e798282610a0f565b95945050505050565b868152600073ffffffffffffffffffffffffffffffffffffffff8088166020840152866040840152808616606084015250831515608083015260c060a0830152610ecf60c0830184610a0f565b98975050505050505050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115610f0d57600080fd5b8260051b80836020870137939093016020019392505050565b606081526000610f3a606083018789610edb565b73ffffffffffffffffffffffffffffffffffffffff8616602084015282810360408401528381528385602083013760006020858301015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8601168201019150509695505050505050565b602081526000610fbd602083018486610edb565b949350505050565b600060208284031215610fd757600080fd5b505191905056fea264697066735822122090f494cd6df0a7acd2fa2e1aee0e8ecaa8c301f7c2ecd8c6fdbc58a04f93644864736f6c63430008170033000000000000000000000000292639452a975630802c17c9267169d93bd5a793000000000000000000000000950d766a1a0afdc33c3e653c861a8765cb42dbdc0000000000000000000000003809f4128b0b33afb17576edafd7d4f4e2abe933
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100675760003560e01c806317f248851161005057806317f24885146100dd5780634f52e7a2146100f2578063ec4efa391461012a57600080fd5b806301ffc9a71461006c57806306fdde0314610094575b600080fd5b61007f61007a3660046109c6565b61014a565b60405190151581526020015b60405180910390f35b6100d06040518060400160405280601381526020017f524547495354524154494f4e5f4d4f44554c450000000000000000000000000081525081565b60405161008b9190610a73565b6100f06100eb366004610c23565b6101e3565b005b610105610100366004610d0b565b6105dd565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161008b565b6000546101059073ffffffffffffffffffffffffffffffffffffffff1681565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f06fdde030000000000000000000000000000000000000000000000000000000014806101dd57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810188905260009073ffffffffffffffffffffffffffffffffffffffff8a1690636352211e90602401602060405180830381865afa158015610251573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102759190610da5565b90503373ffffffffffffffffffffffffffffffffffffffff82161480159061033057506040517fe985e9c500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301523360248301528a169063e985e9c590604401602060405180830381865afa15801561030a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061032e9190610dc2565b155b15610367576040517f7748d9ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006040518060a001604052808981526020018881526020014267ffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff16815260200187878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040516103f49190602001610de4565b60405160208183030381529060405290506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d61f3d468d8d60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff166001886040518763ffffffff1660e01b815260040161048d96959493929190610e82565b6020604051808303816000875af11580156104ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d09190610da5565b9050600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639f69e70d8e8e8489896040518663ffffffff1660e01b8152600401610535959493929190610f26565b600060405180830381600087803b15801561054f57600080fd5b505af1158015610563573d6000803e3d6000fd5b505050508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f0300748d3720c0777d8645f4affde2a3a29c8515e10a7a31345d954bd9aed7b48f8f6040516105c6929190610fa9565b60405180910390a350505050505050505050505050565b6040517f6352211e00000000000000000000000000000000000000000000000000000000815260048101869052600090819073ffffffffffffffffffffffffffffffffffffffff891690636352211e90602401602060405180830381865afa15801561064d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106719190610da5565b90503373ffffffffffffffffffffffffffffffffffffffff82161480159061072c57506040517fe985e9c500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff828116600483015233602483015289169063e985e9c590604401602060405180830381865afa158015610706573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072a9190610dc2565b155b15610763576040517f7748d9ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006040518060a001604052808881526020018781526020014267ffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff16815260200186868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040516107f09190602001610de4565b60405160208183030381529060405290506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d61f3d468c8c60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff166001886040518763ffffffff1660e01b815260040161088996959493929190610e82565b6020604051808303816000875af11580156108a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108cc9190610da5565b90508a15610973576002546040517f7305424f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018e905290911690637305424f906044016020604051808303816000875af115801561094d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109719190610fc5565b505b6040518b9073ffffffffffffffffffffffffffffffffffffffff83169033907fa6e4d1983948888a2be7e084c14834fc01066c7b1173b1d505a1a882ae310a3e90600090a49a9950505050505050505050565b6000602082840312156109d857600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610a0857600080fd5b9392505050565b6000815180845260005b81811015610a3557602081850181015186830182015201610a19565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000610a086020830184610a0f565b60008083601f840112610a9857600080fd5b50813567ffffffffffffffff811115610ab057600080fd5b6020830191508360208260051b8501011115610acb57600080fd5b9250929050565b73ffffffffffffffffffffffffffffffffffffffff81168114610af457600080fd5b50565b8035610b0281610ad2565b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f830112610b4757600080fd5b813567ffffffffffffffff80821115610b6257610b62610b07565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715610ba857610ba8610b07565b81604052838152866020858801011115610bc157600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008083601f840112610bf357600080fd5b50813567ffffffffffffffff811115610c0b57600080fd5b602083019150836020828501011115610acb57600080fd5b60008060008060008060008060008060e08b8d031215610c4257600080fd5b8a3567ffffffffffffffff80821115610c5a57600080fd5b610c668e838f01610a86565b909c509a508a9150610c7a60208e01610af7565b995060408d0135985060608d0135915080821115610c9757600080fd5b610ca38e838f01610b36565b975060808d0135965060a08d0135915080821115610cc057600080fd5b610ccc8e838f01610be1565b909650945060c08d0135915080821115610ce557600080fd5b50610cf28d828e01610be1565b915080935050809150509295989b9194979a5092959850565b600080600080600080600060c0888a031215610d2657600080fd5b873596506020880135610d3881610ad2565b955060408801359450606088013567ffffffffffffffff80821115610d5c57600080fd5b610d688b838c01610b36565b955060808a0135945060a08a0135915080821115610d8557600080fd5b50610d928a828b01610be1565b989b979a50959850939692959293505050565b600060208284031215610db757600080fd5b8151610a0881610ad2565b600060208284031215610dd457600080fd5b81518015158114610a0857600080fd5b602081526000825160a06020840152610e0060c0840182610a0f565b90506020840151604084015267ffffffffffffffff604085015116606084015273ffffffffffffffffffffffffffffffffffffffff606085015116608084015260808401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160a0850152610e798282610a0f565b95945050505050565b868152600073ffffffffffffffffffffffffffffffffffffffff8088166020840152866040840152808616606084015250831515608083015260c060a0830152610ecf60c0830184610a0f565b98975050505050505050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115610f0d57600080fd5b8260051b80836020870137939093016020019392505050565b606081526000610f3a606083018789610edb565b73ffffffffffffffffffffffffffffffffffffffff8616602084015282810360408401528381528385602083013760006020858301015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8601168201019150509695505050505050565b602081526000610fbd602083018486610edb565b949350505050565b600060208284031215610fd757600080fd5b505191905056fea264697066735822122090f494cd6df0a7acd2fa2e1aee0e8ecaa8c301f7c2ecd8c6fdbc58a04f93644864736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000292639452a975630802c17c9267169d93bd5a793000000000000000000000000950d766a1a0afdc33c3e653c861a8765cb42dbdc0000000000000000000000003809f4128b0b33afb17576edafd7d4f4e2abe933
-----Decoded View---------------
Arg [0] : assetRegistry (address): 0x292639452A975630802C17c9267169D93BD5a793
Arg [1] : licensingModule (address): 0x950d766A1a0afDc33c3e653C861A8765cb42DbdC
Arg [2] : resolverAddr (address): 0x3809f4128B0B33AFb17576edafD7D4F4E2ABE933
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000292639452a975630802c17c9267169d93bd5a793
Arg [1] : 000000000000000000000000950d766a1a0afdc33c3e653c861a8765cb42dbdc
Arg [2] : 0000000000000000000000003809f4128b0b33afb17576edafd7d4f4e2abe933
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.