Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
| Transaction Hash |
Method
|
Block
|
From
|
To
|
Amount
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
To
|
Amount
|
||
|---|---|---|---|---|---|---|---|
| 0x61010060 | 5768460 | 594 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
CoreMetadataModule
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 { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import { IIPAccount } from "../../interfaces/IIPAccount.sol";
import { AccessControlled } from "../../access/AccessControlled.sol";
import { BaseModule } from "../BaseModule.sol";
import { Errors } from "../../lib/Errors.sol";
import { IPAccountStorageOps } from "../../lib/IPAccountStorageOps.sol";
import { CORE_METADATA_MODULE_KEY } from "../../lib/modules/Module.sol";
import { ICoreMetadataModule } from "../../interfaces/modules/metadata/ICoreMetadataModule.sol";
/// @title CoreMetadataModule
/// @notice Manages the core metadata for IP assets within the Story Protocol.
/// @dev This contract allows setting core metadata attributes for IP assets.
/// It implements the ICoreMetadataModule interface.
/// The metadata can be set and updated by the owner of the IP asset.
/// The metadata can be frozen to prevent further changes.
contract CoreMetadataModule is BaseModule, AccessControlled, ICoreMetadataModule {
using IPAccountStorageOps for IIPAccount;
string public override name = CORE_METADATA_MODULE_KEY;
/// @notice Modifier to ensure that metadata can only be changed when mutable.
modifier onlyMutable(address ipId) {
if (IIPAccount(payable(ipId)).getBool("IMMUTABLE")) {
revert Errors.CoreMetadataModule__MetadataAlreadyFrozen();
}
_;
}
/// @notice Creates a new CoreMetadataModule instance.
/// @param accessController The address of the AccessController contract.
/// @param ipAccountRegistry The address of the IPAccountRegistry contract.
constructor(
address accessController,
address ipAccountRegistry
) AccessControlled(accessController, ipAccountRegistry) {}
/// @notice Update the nftTokenURI for an IP asset,
/// by retrieve the latest TokenURI from IP NFT to which the IP Asset bound.
/// @dev Will revert if IP asset's metadata is frozen.
/// @param ipId The address of the IP asset.
/// @param nftMetadataHash A bytes32 hash representing the metadata of the NFT.
/// This metadata is associated with the IP Asset and is accessible via the NFT's TokenURI.
/// Use bytes32(0) to indicate that the metadata is not available.
function updateNftTokenURI(address ipId, bytes32 nftMetadataHash) external verifyPermission(ipId) {
_updateNftTokenURI(ipId, nftMetadataHash);
}
/// @notice Sets the metadataURI for an IP asset.
/// @dev Will revert if IP asset's metadata is frozen.
/// @param ipId The address of the IP asset.
/// @param metadataURI The metadataURI to set for the IP asset.
/// @param metadataHash The hash of metadata at metadataURI.
/// Use bytes32(0) to indicate that the metadata is not available.
function setMetadataURI(
address ipId,
string memory metadataURI,
bytes32 metadataHash
) external verifyPermission(ipId) {
_setMetadataURI(ipId, metadataURI, metadataHash);
}
/// @notice Sets all core metadata for an IP asset.
/// @dev Will revert if IP asset's metadata is frozen.
/// @param ipId The address of the IP asset.
/// @param metadataURI The metadataURI to set for the IP asset.
/// @param metadataHash The hash of metadata at metadataURI.
/// Use bytes32(0) to indicate that the metadata is not available.
/// @param nftMetadataHash A bytes32 hash representing the metadata of the NFT.
/// This metadata is associated with the IP Asset and is accessible via the NFT's TokenURI.
/// Use bytes32(0) to indicate that the metadata is not available.
function setAll(
address ipId,
string memory metadataURI,
bytes32 metadataHash,
bytes32 nftMetadataHash
) external verifyPermission(ipId) {
_updateNftTokenURI(ipId, nftMetadataHash);
_setMetadataURI(ipId, metadataURI, metadataHash);
}
/// @notice make all metadata of the IP Asset immutable.
/// @param ipId The address of the IP asset.
function freezeMetadata(address ipId) external verifyPermission(ipId) {
IIPAccount(payable(ipId)).setBool("IMMUTABLE", true);
emit MetadataFrozen(ipId);
}
/// @notice Check if the metadata of the IP Asset is immutable.
/// @param ipId The address of the IP asset.
function isMetadataFrozen(address ipId) external view returns (bool) {
return IIPAccount(payable(ipId)).getBool("IMMUTABLE");
}
/// @dev Implements the IERC165 interface.
function supportsInterface(bytes4 interfaceId) public view virtual override(BaseModule, IERC165) returns (bool) {
return interfaceId == type(ICoreMetadataModule).interfaceId || super.supportsInterface(interfaceId);
}
function _updateNftTokenURI(address ipId, bytes32 nftMetadataHash) internal onlyMutable(ipId) {
(, address tokenAddress, uint256 tokenId) = IIPAccount(payable(ipId)).token();
string memory nftTokenURI = IERC721Metadata(tokenAddress).tokenURI(tokenId);
IIPAccount(payable(ipId)).setString("NFT_TOKEN_URI", nftTokenURI);
IIPAccount(payable(ipId)).setBytes32("NFT_METADATA_HASH", nftMetadataHash);
emit NFTTokenURISet(ipId, nftTokenURI, nftMetadataHash);
}
function _setMetadataURI(address ipId, string memory metadataURI, bytes32 metadataHash) internal onlyMutable(ipId) {
IIPAccount(payable(ipId)).setString("METADATA_URI", metadataURI);
IIPAccount(payable(ipId)).setBytes32("METADATA_HASH", metadataHash);
emit MetadataURISet(ipId, metadataURI, metadataHash);
}
}// 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: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol)
pragma solidity ^0.8.20;
import {IERC721} from "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Metadata is IERC721 {
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
}// 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";
import { IIPAccountStorage } from "./IIPAccountStorage.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, IIPAccountStorage {
/// @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: BUSL-1.1
pragma solidity 0.8.23;
import { IAccessController } from "../interfaces/access/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.
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
IAccessController public immutable ACCESS_CONTROLLER;
/// @notice The IIPAccountRegistry instance for IP account verification.
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
IIPAccountRegistry public immutable IP_ACCOUNT_REGISTRY;
/// @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 Constructor
/// @param accessController The address of the AccessController contract.
/// @param ipAccountRegistry The address of the IPAccountRegistry contract.
/// @custom:oz-upgrades-unsafe-allow constructor
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);
}
/// @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;
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;
/// @title Errors Library
/// @notice Library for all Story Protocol contract errors.
library Errors {
////////////////////////////////////////////////////////////////////////////
// IP Account //
////////////////////////////////////////////////////////////////////////////
/// @notice Zero address provided for Access Controller.
error IPAccount__ZeroAccessController();
/// @notice Invalid signer provided.
error IPAccount__InvalidSigner();
/// @notice Invalid signature provided, must be an EIP-712 signature.
error IPAccount__InvalidSignature();
/// @notice Signature is expired.
error IPAccount__ExpiredSignature();
/// @notice Provided calldata is invalid.
error IPAccount__InvalidCalldata();
////////////////////////////////////////////////////////////////////////////
// IP Account Storage //
////////////////////////////////////////////////////////////////////////////
/// @notice Caller writing to IP Account storage is not a registered module.
error IPAccountStorage__NotRegisteredModule(address module);
////////////////////////////////////////////////////////////////////////////
// IP Account Registry //
////////////////////////////////////////////////////////////////////////////
/// @notice Zero address provided for IP Account implementation.
error IPAccountRegistry_ZeroIpAccountImpl();
////////////////////////////////////////////////////////////////////////////
// IP Asset Registry //
////////////////////////////////////////////////////////////////////////////
/// @notice Zero address provided for Access Manager in initializer.
error IPAssetRegistry__ZeroAccessManager();
/// @notice The IP asset has already been registered.
error IPAssetRegistry__AlreadyRegistered();
/// @notice The NFT token contract is not valid ERC721 contract.
error IPAssetRegistry__UnsupportedIERC721(address contractAddress);
/// @notice The NFT token contract does not support ERC721Metadata.
error IPAssetRegistry__UnsupportedIERC721Metadata(address contractAddress);
/// @notice The NFT token id does not exist or invalid.
error IPAssetRegistry__InvalidToken(address contractAddress, uint256 tokenId);
////////////////////////////////////////////////////////////////////////////
// License Registry //
////////////////////////////////////////////////////////////////////////////
/// @notice Zero address provided for Access Manager in initializer.
error LicenseRegistry__ZeroAccessManager();
/// @notice Zero address provided for IP Asset Registry.
error LicensingModule__ZeroRoyaltyModule();
/// @notice Zero address provided for Licensing Module.
error LicensingModule__ZeroLicenseRegistry();
/// @notice Zero address provided for Dispute Module.
error LicensingModule__ZeroDisputeModule();
/// @notice Zero address provided for License Token.
error LicensingModule__ZeroLicenseToken();
/// @notice Zero address provided for Module Registry.
error LicensingModule__ZeroModuleRegistry();
/// @notice Zero address provided for Licensing Module.
error LicenseRegistry__ZeroLicensingModule();
/// @notice Zero address provided for Dispute Module.
error LicenseRegistry__ZeroDisputeModule();
/// @notice Caller is not the Licensing Module.
error LicenseRegistry__CallerNotLicensingModule();
/// @notice Emitted when trying to transfer a license that is not transferable (by policy)
error LicenseRegistry__NotTransferable();
/// @notice License Template is not registered in the License Registry.
error LicenseRegistry__UnregisteredLicenseTemplate(address licenseTemplate);
/// @notice License Terms or License Template not found.
error LicenseRegistry__LicenseTermsNotExists(address licenseTemplate, uint256 licenseTermsId);
/// @notice Licensor IP does not have the provided license terms attached.
error LicenseRegistry__LicensorIpHasNoLicenseTerms(address ipId, address licenseTemplate, uint256 licenseTermsId);
/// @notice Invalid License Template address provided.
error LicenseRegistry__NotLicenseTemplate(address licenseTemplate);
/// @notice IP is expired.
error LicenseRegistry__IpExpired(address ipId);
/// @notice Parent IP is expired.
error LicenseRegistry__ParentIpExpired(address ipId);
/// @notice Parent IP is dispute tagged.
error LicenseRegistry__ParentIpTagged(address ipId);
/// @notice Parent IP does not have the provided license terms attached.
error LicenseRegistry__ParentIpHasNoLicenseTerms(address ipId, uint256 licenseTermsId);
/// @notice Empty Parent IP list provided.
error LicenseRegistry__NoParentIp();
/// @notice Provided derivative IP already has license terms attached.
error LicenseRegistry__DerivativeIpAlreadyHasLicense(address childIpId);
/// @notice Provided derivative IP is already registered.
error LicenseRegistry__DerivativeAlreadyRegistered(address childIpId);
/// @notice Provided derivative IP is the same as the parent IP.
error LicenseRegistry__DerivativeIsParent(address ipId);
/// @notice Provided license template does not match the parent IP's current license template.
error LicenseRegistry__ParentIpUnmatchedLicenseTemplate(address ipId, address licenseTemplate);
/// @notice Index out of bounds.
error LicenseRegistry__IndexOutOfBounds(address ipId, uint256 index, uint256 length);
/// @notice Provided license template and terms ID is already attached to IP.
error LicenseRegistry__LicenseTermsAlreadyAttached(address ipId, address licenseTemplate, uint256 licenseTermsId);
/// @notice Provided license template does not match the IP's current license template.
error LicenseRegistry__UnmatchedLicenseTemplate(address ipId, address licenseTemplate, address newLicenseTemplate);
/// @notice Provided license template and terms ID is a duplicate.
error LicenseRegistry__DuplicateLicense(address ipId, address licenseTemplate, uint256 licenseTermsId);
////////////////////////////////////////////////////////////////////////////
// License Token //
////////////////////////////////////////////////////////////////////////////
/// @notice Zero address provided for Access Manager in initializer.
error LicenseToken__ZeroAccessManager();
/// @notice Zero address provided for Licensing Module.
error LicenseToken__ZeroLicensingModule();
/// @notice Zero address provided for Dispute Module.
error LicenseToken__ZeroDisputeModule();
/// @notice Caller is not the Licensing Module.
error LicenseToken__CallerNotLicensingModule();
/// @notice License token is revoked.
error LicenseToken__RevokedLicense(uint256 tokenId);
/// @notice License token is not transferable.
error LicenseToken__NotTransferable();
/// @notice License token is not owned by the caller.
error LicenseToken__NotLicenseTokenOwner(uint256 tokenId, address iPowner, address tokenOwner);
/// @notice All license tokens must be from the same license template.
error LicenseToken__AllLicenseTokensMustFromSameLicenseTemplate(
address licenseTemplate,
address anotherLicenseTemplate
);
////////////////////////////////////////////////////////////////////////////
// Licensing Module //
////////////////////////////////////////////////////////////////////////////
/// @notice Zero address provided for Access Manager in initializer.
error LicensingModule__ZeroAccessManager();
/// @notice Receiver is zero address.
error LicensingModule__ReceiverZeroAddress();
/// @notice Mint amount is zero.
error LicensingModule__MintAmountZero();
/// @notice IP is dispute tagged.
error LicensingModule__DisputedIpId();
/// @notice License template and terms ID is not found.
error LicensingModule__LicenseTermsNotFound(address licenseTemplate, uint256 licenseTermsId);
/// @notice Derivative IP cannot add license terms.
error LicensingModule__DerivativesCannotAddLicenseTerms();
/// @notice Receiver check failed.
error LicensingModule__ReceiverCheckFailed(address receiver);
/// @notice IP list and license terms list length mismatch.
error LicensingModule__LicenseTermsLengthMismatch(uint256 ipLength, uint256 licenseTermsLength);
/// @notice Parent IP list is empty.
error LicensingModule__NoParentIp();
/// @notice Incompatible royalty policy.
error LicensingModule__IncompatibleRoyaltyPolicy(address royaltyPolicy, address anotherRoyaltyPolicy);
/// @notice License template and terms are not compatible for the derivative IP.
error LicensingModule__LicenseNotCompatibleForDerivative(address childIpId);
/// @notice License token list is empty.
error LicensingModule__NoLicenseToken();
/// @notice License tokens are not compatible for the derivative IP.
error LicensingModule__LicenseTokenNotCompatibleForDerivative(address childIpId, uint256[] licenseTokenIds);
/// @notice License template denied minting license token during the verification stage.
error LicensingModule__LicenseDenyMintLicenseToken(
address licenseTemplate,
uint256 licenseTermsId,
address licensorIpId
);
/// @notice Licensing hook is invalid either not support ILicensingHook interface or not registered as module
error LicensingModule__InvalidLicensingHook(address hook);
/// @notice The license terms ID is invalid or license template doesn't exist.
error LicensingModule__InvalidLicenseTermsId(address licenseTemplate, uint256 licenseTermsId);
////////////////////////////////////////////////////////////////////////////
// Dispute Module //
////////////////////////////////////////////////////////////////////////////
/// @notice Zero address provided for Access Manager in initializer.
error DisputeModule__ZeroAccessManager();
/// @notice Zero address provided for License Registry.
error DisputeModule__ZeroLicenseRegistry();
/// @notice Zero address provided for IP Asset Registry.
error DisputeModule__ZeroIPAssetRegistry();
/// @notice Zero address provided for Access Controller.
error DisputeModule__ZeroAccessController();
/// @notice Zero address provided for Arbitration Policy.
error DisputeModule__ZeroArbitrationPolicy();
/// @notice Zero address provided for Arbitration Relayer.
error DisputeModule__ZeroArbitrationRelayer();
/// @notice Zero bytes provided for Dispute Tag.
error DisputeModule__ZeroDisputeTag();
/// @notice Zero bytes provided for Dispute Evidence.
error DisputeModule__ZeroLinkToDisputeEvidence();
/// @notice Not a whitelisted arbitration policy.
error DisputeModule__NotWhitelistedArbitrationPolicy();
/// @notice Not a whitelisted arbitration relayer.
error DisputeModule__NotWhitelistedArbitrationRelayer();
/// @notice Not a whitelisted dispute tag.
error DisputeModule__NotWhitelistedDisputeTag();
/// @notice Not the dispute initiator.
error DisputeModule__NotDisputeInitiator();
/// @notice Not in dispute state, the dispute is not IN_DISPUTE.
error DisputeModule__NotInDisputeState();
/// @notice Not able to resolve a dispute, either the dispute is IN_DISPUTE or empty.
error DisputeModule__NotAbleToResolve();
/// @notice Not a registered IP.
error DisputeModule__NotRegisteredIpId();
/// @notice Provided parent IP and the parent dispute's target IP is different.
error DisputeModule__ParentIpIdMismatch();
/// @notice Provided parent dispute's target IP is not dispute tagged.
error DisputeModule__ParentNotTagged();
/// @notice Provided parent dispute's target IP is not the derivative IP's parent.
error DisputeModule__NotDerivative();
/// @notice Provided parent dispute has not been resolved.
error DisputeModule__ParentDisputeNotResolved();
////////////////////////////////////////////////////////////////////////////
// ArbitrationPolicy SP //
////////////////////////////////////////////////////////////////////////////
/// @notice Zero address provided for Access Manager in initializer.
error ArbitrationPolicySP__ZeroAccessManager();
/// @notice Zero address provided for Dispute Module.
error ArbitrationPolicySP__ZeroDisputeModule();
/// @notice Zero address provided for Payment Token.
error ArbitrationPolicySP__ZeroPaymentToken();
/// @notice Caller is not the Dispute Module.
error ArbitrationPolicySP__NotDisputeModule();
////////////////////////////////////////////////////////////////////////////
// Royalty Module //
////////////////////////////////////////////////////////////////////////////
/// @notice Zero address provided for Access Manager in initializer.
error RoyaltyModule__ZeroAccessManager();
/// @notice Zero address provided for Dispute Module.
error RoyaltyModule__ZeroDisputeModule();
/// @notice Zero address provided for License Registry.
error RoyaltyModule__ZeroLicenseRegistry();
/// @notice Zero address provided for Licensing Module.
error RoyaltyModule__ZeroLicensingModule();
/// @notice Zero address provided for Royalty Policy.
error RoyaltyModule__ZeroRoyaltyPolicy();
/// @notice Zero address provided for Royalty Token.
error RoyaltyModule__ZeroRoyaltyToken();
/// @notice Not a whitelisted royalty policy.
error RoyaltyModule__NotWhitelistedRoyaltyPolicy();
/// @notice Not a whitelisted royalty token.
error RoyaltyModule__NotWhitelistedRoyaltyToken();
/// @notice Royalty policy for IP is unset.
error RoyaltyModule__NoRoyaltyPolicySet();
/// @notice Royalty policy between IPs are incompatible (different).
error RoyaltyModule__IncompatibleRoyaltyPolicy();
/// @notice Caller is unauthorized.
error RoyaltyModule__NotAllowedCaller();
/// @notice IP can only mint licenses of selected royalty policy.
error RoyaltyModule__CanOnlyMintSelectedPolicy();
/// @notice Parent IP list for linking is empty.
error RoyaltyModule__NoParentsOnLinking();
/// @notice IP is expired.
error RoyaltyModule__IpIsExpired();
/// @notice IP is dipute tagged.
error RoyaltyModule__IpIsTagged();
////////////////////////////////////////////////////////////////////////////
// Royalty Policy LAP //
////////////////////////////////////////////////////////////////////////////
/// @notice Zero address provided for Access Manager in initializer.
error RoyaltyPolicyLAP__ZeroAccessManager();
/// @notice Zero address provided for IP Royalty Vault Beacon.
error RoyaltyPolicyLAP__ZeroIpRoyaltyVaultBeacon();
/// @notice Zero address provided for Royalty Module.
error RoyaltyPolicyLAP__ZeroRoyaltyModule();
/// @notice Zero address provided for Licensing Module.
error RoyaltyPolicyLAP__ZeroLicensingModule();
/// @notice Caller is not the Royalty Module.
error RoyaltyPolicyLAP__NotRoyaltyModule();
/// @notice Size of parent IP list is above the LAP royalty policy limit.
error RoyaltyPolicyLAP__AboveParentLimit();
/// @notice Amount of ancestors for derivative IP is above the LAP royalty policy limit.
error RoyaltyPolicyLAP__AboveAncestorsLimit();
/// @notice Total royalty stack exceeds the protocol limit.
error RoyaltyPolicyLAP__AboveRoyaltyStackLimit();
/// @notice Size of parent royalties list and parent IP list mismatch.
error RoyaltyPolicyLAP__InvalidParentRoyaltiesLength();
/// @notice IP cannot be linked to a parent, because it is either already linked to parents or derivatives (root).
error RoyaltyPolicyLAP__UnlinkableToParents();
/// @notice Policy is already initialized and IP is at the ancestors limit, so it can't mint more licenses.
error RoyaltyPolicyLAP__LastPositionNotAbleToMintLicense();
////////////////////////////////////////////////////////////////////////////
// IP Royalty Vault //
////////////////////////////////////////////////////////////////////////////
/// @notice Zero address provided for Royalty Policy LAP.
error IpRoyaltyVault__ZeroRoyaltyPolicyLAP();
/// @notice Zero address provided for Dispute Module.
error IpRoyaltyVault__ZeroDisputeModule();
/// @notice Caller is not the Royalty Policy LAP.
error IpRoyaltyVault__NotRoyaltyPolicyLAP();
/// @notice Snapshot interval is too short, wait for the interval to pass for the next snapshot.
error IpRoyaltyVault__SnapshotIntervalTooShort();
/// @notice Royalty Tokens is already claimed.
error IpRoyaltyVault__AlreadyClaimed();
/// @notice Royalty Tokens claimer is not an ancestor of derivative IP.
error IpRoyaltyVault__ClaimerNotAnAncestor();
/// @notice IP is dispute tagged.
error IpRoyaltyVault__IpTagged();
/// @notice IP Royalty Vault is paused.
error IpRoyaltyVault__EnforcedPause();
////////////////////////////////////////////////////////////////////////////
// Module Registry //
////////////////////////////////////////////////////////////////////////////
/// @notice Zero address provided for Access Manager in initializer.
error ModuleRegistry__ZeroAccessManager();
/// @notice Module is zero address.
error ModuleRegistry__ModuleAddressZeroAddress();
/// @notice Provided module address is not a contract.
error ModuleRegistry__ModuleAddressNotContract();
/// @notice Module is already registered.
error ModuleRegistry__ModuleAlreadyRegistered();
/// @notice Provided module name is empty string.
error ModuleRegistry__NameEmptyString();
/// @notice Provided module name is already regsitered.
error ModuleRegistry__NameAlreadyRegistered();
/// @notice Module name does not match the given name.
error ModuleRegistry__NameDoesNotMatch();
/// @notice Module is not registered
error ModuleRegistry__ModuleNotRegistered();
/// @notice Provided interface ID is zero bytes4.
error ModuleRegistry__InterfaceIdZero();
/// @notice Module type is already registered.
error ModuleRegistry__ModuleTypeAlreadyRegistered();
/// @notice Module type is not registered.
error ModuleRegistry__ModuleTypeNotRegistered();
/// @notice Module address does not support the interface ID (module type).
error ModuleRegistry__ModuleNotSupportExpectedModuleTypeInterfaceId();
/// @notice Module type is empty string.
error ModuleRegistry__ModuleTypeEmptyString();
////////////////////////////////////////////////////////////////////////////
// Access Controller //
////////////////////////////////////////////////////////////////////////////
/// @notice Zero address provided for Access Manager in initializer.
error AccessController__ZeroAccessManager();
/// @notice Zero address provided for IP Account Registry.
error AccessController__ZeroIPAccountRegistry();
/// @notice Zero address provided for Module Registry.
error AccessController__ZeroModuleRegistry();
/// @notice IP Account is zero address.
error AccessController__IPAccountIsZeroAddress();
/// @notice IP Account is not a valid SP IP Account address.
error AccessController__IPAccountIsNotValid(address ipAccount);
/// @notice Signer is zero address.
error AccessController__SignerIsZeroAddress();
/// @notice Caller is not the IP Account or its owner.
error AccessController__CallerIsNotIPAccountOrOwner();
/// @notice Invalid permission value, must be 0 (ABSTAIN), 1 (ALLOW) or 2 (DENY).
error AccessController__PermissionIsNotValid();
/// @notice Both the caller and recipient (to) are not registered modules.
error AccessController__BothCallerAndRecipientAreNotRegisteredModule(address signer, address to);
/// @notice Permission denied.
error AccessController__PermissionDenied(address ipAccount, address signer, address to, bytes4 func);
/// @notice Both recipient (to) and function selectors are zero address means delegate all permissions to signer.
error AccessController__ToAndFuncAreZeroAddressShouldCallSetAllPermissions();
////////////////////////////////////////////////////////////////////////////
// Access Controlled //
////////////////////////////////////////////////////////////////////////////
/// @notice Zero address passed.
error AccessControlled__ZeroAddress();
/// @notice IP Account is not a valid SP IP Account address.
error AccessControlled__NotIpAccount(address ipAccount);
/// @notice Caller is not the IP Account.
error AccessControlled__CallerIsNotIpAccount(address caller);
////////////////////////////////////////////////////////////////////////////
// Core Metadata Module //
////////////////////////////////////////////////////////////////////////////
/// @notice Core metadata is already frozen (immutable).
error CoreMetadataModule__MetadataAlreadyFrozen();
////////////////////////////////////////////////////////////////////////////
// Protocol Pause Admin //
////////////////////////////////////////////////////////////////////////////
/// @notice Zero address passed.
error ProtocolPauseAdmin__ZeroAddress();
/// @notice Adding a contract that is paused.
error ProtocolPauseAdmin__AddingPausedContract();
/// @notice Contract is already added to the pausable list.
error ProtocolPauseAdmin__PausableAlreadyAdded();
/// @notice Removing a contract that is not in the pausable list.
error ProtocolPauseAdmin__PausableNotFound();
}// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.23;
import { IIPAccountStorage } from "../interfaces/IIPAccountStorage.sol";
import { ShortString, ShortStrings } from "@openzeppelin/contracts/utils/ShortStrings.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
/// @title IPAccount Storage Operations Library
/// @notice Provides utility functions that extend the basic functionalities of IPAccountStorage,
/// facilitating enhanced module interaction with IPAccount Namespaced Storage.
/// @dev This library enables modules to access and manipulate IPAccount Namespaced Storage
/// with additional features such as using `address` type namespaces and `ShortString` keys.
/// It serves as an addon to the fundamental IPAccountStorage functions, allowing for more complex and
/// flexible interactions with the namespaced storage.
library IPAccountStorageOps {
using ShortStrings for *;
using Strings for *;
/// @dev Sets a string value under a given key within the default namespace, determined by `msg.sender`.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The key under which to store the value.
/// @param value The string value to be stored.
function setString(IIPAccountStorage ipStorage, bytes32 key, string memory value) internal {
ipStorage.setBytes(key, bytes(value));
}
/// @dev Retrieves a string value by a given key from the default namespace.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The key whose value is to be retrieved.
/// @return The string value stored under the specified key.
function getString(IIPAccountStorage ipStorage, bytes32 key) internal view returns (string memory) {
return string(ipStorage.getBytes(key));
}
/// @dev Retrieves a string value by a given key from a specified namespace.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param namespace The namespace from which to retrieve the value.
/// @param key The key whose value is to be retrieved.
/// @return The string value stored under the specified key in the given namespace.
function getString(
IIPAccountStorage ipStorage,
bytes32 namespace,
bytes32 key
) internal view returns (string memory) {
return string(ipStorage.getBytes(namespace, key));
}
/// @notice Sets a string value in the storage using a `ShortString` key.
/// @dev Converts the `ShortString` key to a `bytes32` representation before storing the value.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The `ShortString` key under which to store the value.
/// @param value The string value to be stored.
function setString(IIPAccountStorage ipStorage, ShortString key, string memory value) internal {
setString(ipStorage, toBytes32(key), value);
}
/// @notice Retrieves a string value from the storage using a `ShortString` key.
/// @dev Converts the `ShortString` key to a `bytes32` representation before retrieving the value.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The `ShortString` key whose value is to be retrieved.
/// @return The string value stored under the specified key.
function getString(IIPAccountStorage ipStorage, ShortString key) internal view returns (string memory) {
return getString(ipStorage, toBytes32(key));
}
/// @notice Retrieves a string value from the storage under a specified namespace using a bytes32 key.
/// @dev Retrieves the string value from the specified namespace using the provided key.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param namespace The namespace under which to retrieve the value.
/// @param key The bytes32 key whose value is to be retrieved.
function getString(
IIPAccountStorage ipStorage,
address namespace,
bytes32 key
) internal view returns (string memory) {
return getString(ipStorage, toBytes32(namespace), key);
}
/// @notice Retrieves a string value from the storage under a specified namespace using a `ShortString` key.
/// @dev Retrieves the string value from the specified namespace using the provided `ShortString` key.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param namespace The namespace under which to retrieve the value.
/// @param key The `ShortString` key whose value is to be retrieved.
function getString(
IIPAccountStorage ipStorage,
address namespace,
ShortString key
) internal view returns (string memory) {
return getString(ipStorage, toBytes32(namespace), toBytes32(key));
}
/// @dev Sets an address value under a given key within the default namespace, determined by `msg.sender`.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The key under which to store the value.
/// @param value The address value to be stored.
function setAddress(IIPAccountStorage ipStorage, bytes32 key, address value) internal {
ipStorage.setBytes32(key, toBytes32(value));
}
/// @dev Retrieves an address value by a given key from the default namespace.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The key whose value is to be retrieved.
/// @return The address value stored under the specified key.
function getAddress(IIPAccountStorage ipStorage, bytes32 key) internal view returns (address) {
return address(uint160(uint256(ipStorage.getBytes32(key))));
}
/// @dev Retrieves an address value by a given key from a specified namespace.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param namespace The namespace from which to retrieve the value.
/// @param key The key whose value is to be retrieved.
/// @return The address value stored under the specified key in the given namespace.
function getAddress(IIPAccountStorage ipStorage, bytes32 namespace, bytes32 key) internal view returns (address) {
return address(uint160(uint256(ipStorage.getBytes32(namespace, key))));
}
/// @notice Sets an address value in the storage using a `ShortString` key.
/// @dev Converts the `ShortString` key to a `bytes32` representation before storing the value,
/// facilitating address storage in a compact format.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The `ShortString` key under which to store the address value.
/// @param value The address value to be stored.
function setAddress(IIPAccountStorage ipStorage, ShortString key, address value) internal {
setAddress(ipStorage, toBytes32(key), value);
}
/// @notice Retrieves an address value from the storage using a `ShortString` key.
/// @dev Converts the `ShortString` key to a `bytes32` representation before retrieving the value,
/// ensuring the integrity of the address data.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The `ShortString` key whose address value is to be retrieved.
/// @return The address value stored under the specified key.
function getAddress(IIPAccountStorage ipStorage, ShortString key) internal view returns (address) {
return getAddress(ipStorage, toBytes32(key));
}
/// @notice Retrieves an address value from the storage under a specified namespace using a bytes32 key.
/// @dev Retrieves the address value from the specified namespace using the provided key.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param namespace The namespace under which to retrieve the value.
/// @param key The bytes32 key whose address value is to be retrieved.
/// @return The address value stored under the specified key in the given namespace.
function getAddress(IIPAccountStorage ipStorage, address namespace, bytes32 key) internal view returns (address) {
return getAddress(ipStorage, toBytes32(namespace), key);
}
/// @notice Retrieves an address value from the storage under a specified namespace using a `ShortString` key.
/// @dev Retrieves the address value from the specified namespace using the provided `ShortString` key.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param namespace The namespace under which to retrieve the value.
/// @param key The `ShortString` key whose address value is to be retrieved.
/// @return The address value stored under the specified key in the given namespace.
function getAddress(
IIPAccountStorage ipStorage,
address namespace,
ShortString key
) internal view returns (address) {
return getAddress(ipStorage, toBytes32(namespace), toBytes32(key));
}
/// @dev Sets a uint256 value under a given key within the default namespace, determined by `msg.sender`.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The key under which to store the value.
/// @param value The uint256 value to be stored.
function setUint256(IIPAccountStorage ipStorage, bytes32 key, uint256 value) internal {
ipStorage.setBytes32(key, bytes32(value));
}
/// @dev Retrieves a uint256 value by a given key from the default namespace.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The key whose value is to be retrieved.
/// @return The uint256 value stored under the specified key.
function getUint256(IIPAccountStorage ipStorage, bytes32 key) internal view returns (uint256) {
return uint256(ipStorage.getBytes32(key));
}
/// @dev Retrieves a uint256 value by a given key from a specified namespace.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param namespace The namespace from which to retrieve the value.
/// @param key The key whose value is to be retrieved.
/// @return The uint256 value stored under the specified key in the given namespace.
function getUint256(IIPAccountStorage ipStorage, bytes32 namespace, bytes32 key) internal view returns (uint256) {
return uint256(ipStorage.getBytes32(namespace, key));
}
/// @notice Sets a uint256 value in the storage using a `ShortString` key.
/// @dev Converts the `ShortString` key to a `bytes32` representation before storing the value,
/// facilitating uint256 storage in a compact format.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The `ShortString` key under which to store the uint256 value.
/// @param value The uint256 value to be stored.
function setUint256(IIPAccountStorage ipStorage, ShortString key, uint256 value) internal {
setUint256(ipStorage, toBytes32(key), value);
}
/// @notice Retrieves a uint256 value from the storage using a `ShortString` key.
/// @dev Converts the `ShortString` key to a `bytes32` representation before retrieving the value,
/// ensuring the integrity of the uint256 data.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The `ShortString` key whose uint256 value is to be retrieved.
/// @return The uint256 value stored under the specified key.
function getUint256(IIPAccountStorage ipStorage, ShortString key) internal view returns (uint256) {
return getUint256(ipStorage, toBytes32(key));
}
/// @notice Retrieves a uint256 value from the storage under a specified namespace using a bytes32 key.
/// @dev Retrieves the uint256 value from the specified namespace using the provided key.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param namespace The namespace under which to retrieve the value.
/// @param key The bytes32 key whose uint256 value is to be retrieved.
/// @return The uint256 value stored under the specified key in the given namespace.
function getUint256(IIPAccountStorage ipStorage, address namespace, bytes32 key) internal view returns (uint256) {
return getUint256(ipStorage, toBytes32(namespace), key);
}
/// @notice Retrieves a uint256 value from the storage under a specified namespace using a `ShortString` key.
/// @dev Retrieves the uint256 value from the specified namespace using the provided `ShortString` key.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param namespace The namespace under which to retrieve the value.
/// @param key The `ShortString` key whose uint256 value is to be retrieved.
/// @return The uint256 value stored under the specified key in the given namespace.
function getUint256(
IIPAccountStorage ipStorage,
address namespace,
ShortString key
) internal view returns (uint256) {
return getUint256(ipStorage, toBytes32(namespace), toBytes32(key));
}
/// @dev Sets a boolean value under a given key within the default namespace, determined by `msg.sender`.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The key under which to store the value.
/// @param value The boolean value to be stored.
function setBool(IIPAccountStorage ipStorage, bytes32 key, bool value) internal {
ipStorage.setBytes32(key, value ? bytes32(uint256(1)) : bytes32(0));
}
/// @dev Retrieves a boolean value by a given key from the default namespace.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The key whose value is to be retrieved.
/// @return The boolean value stored under the specified key.
function getBool(IIPAccountStorage ipStorage, bytes32 key) internal view returns (bool) {
return ipStorage.getBytes32(key) != 0;
}
/// @dev Retrieves a boolean value by a given key from a specified namespace.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param namespace The namespace from which to retrieve the value.
/// @param key The key whose value is to be retrieved.
/// @return The boolean value stored under the specified key in the given namespace.
function getBool(IIPAccountStorage ipStorage, bytes32 namespace, bytes32 key) internal view returns (bool) {
return ipStorage.getBytes32(namespace, key) != 0;
}
/// @notice Sets a bool value in the storage using a `ShortString` key.
/// @dev Converts the `ShortString` key to a `bytes32` representation before storing the value,
/// facilitating bool storage in a compact format.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The `ShortString` key under which to store the bool value.
/// @param value The bool value to be stored.
function setBool(IIPAccountStorage ipStorage, ShortString key, bool value) internal {
setBool(ipStorage, toBytes32(key), value);
}
/// @notice Retrieves a bool value from the storage using a `ShortString` key.
/// @dev Converts the `ShortString` key to a `bytes32` representation before retrieving the value,
/// ensuring the integrity of the bool data.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The `ShortString` key whose bool value is to be retrieved.
/// @return The bool value stored under the specified key.
function getBool(IIPAccountStorage ipStorage, ShortString key) internal view returns (bool) {
return getBool(ipStorage, toBytes32(key));
}
/// @notice Retrieves a bool value from the storage under a specified namespace using a bytes32 key.
/// @dev Retrieves the bool value from the specified namespace using the provided key.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param namespace The namespace under which to retrieve the value.
/// @param key The bytes32 key whose bool value is to be retrieved.
/// @return The bool value stored under the specified key in the given namespace.
function getBool(IIPAccountStorage ipStorage, address namespace, bytes32 key) internal view returns (bool) {
return getBool(ipStorage, toBytes32(namespace), key);
}
/// @notice Retrieves a bool value from the storage under a specified namespace using a `ShortString` key.
/// @dev Retrieves the bool value from the specified namespace using the provided `ShortString` key.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param namespace The namespace under which to retrieve the value.
/// @param key The `ShortString` key whose bool value is to be retrieved.
/// @return The bool value stored under the specified key in the given namespace.
function getBool(IIPAccountStorage ipStorage, address namespace, ShortString key) internal view returns (bool) {
return getBool(ipStorage, toBytes32(namespace), toBytes32(key));
}
/// @notice Sets a bytes value in the storage using a `ShortString` key.
/// @dev Converts the `ShortString` key to a `bytes32` representation before storing the value,
/// facilitating bytes storage in a compact format.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The `ShortString` key under which to store the bytes value.
/// @param value The bytes value to be stored.
function setBytes(IIPAccountStorage ipStorage, ShortString key, bytes memory value) internal {
ipStorage.setBytes(toBytes32(key), value);
}
/// @notice Sets a bytes value in the storage using two `ShortString` keys.
/// @param ipStorage The instance of the IPAccountStorage contract.
function setBytes(IIPAccountStorage ipStorage, ShortString key1, ShortString key2, bytes memory value) internal {
ipStorage.setBytes(toBytes32(string(abi.encodePacked(key1.toString(), key2.toString()))), value);
}
/// @notice Retrieves a bytes value from the storage using a `ShortString` key.
/// @dev Converts the `ShortString` key to a `bytes32` representation before retrieving the value,
/// ensuring the integrity of the bytes data.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The `ShortString` key whose bytes value is to be retrieved.
/// @return The bytes value stored under the specified key.
function getBytes(IIPAccountStorage ipStorage, ShortString key) internal view returns (bytes memory) {
return ipStorage.getBytes(toBytes32(key));
}
/// @notice Retrieves a bytes value from the storage under a specified namespace using a bytes32 key.
/// @dev Retrieves the bytes value from the specified namespace using the provided key.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param namespace The namespace under which to retrieve the value.
/// @param key The bytes32 key whose bytes value is to be retrieved.
/// @return The bytes value stored under the specified key in the given namespace.
function getBytes(
IIPAccountStorage ipStorage,
address namespace,
bytes32 key
) internal view returns (bytes memory) {
return ipStorage.getBytes(toBytes32(namespace), key);
}
/// @notice Retrieves a bytes value from the storage under a specified namespace using a `ShortString` key.
/// @dev Retrieves the bytes value from the specified namespace using the provided `ShortString` key.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param namespace The namespace under which to retrieve the value.
/// @param key The `ShortString` key whose bytes value is to be retrieved.
/// @return The bytes value stored under the specified key in the given namespace.
function getBytes(
IIPAccountStorage ipStorage,
address namespace,
ShortString key
) internal view returns (bytes memory) {
return ipStorage.getBytes(toBytes32(namespace), toBytes32(key));
}
/// @notice Retrieves a bytes value from the storage using two `ShortString` keys.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @return The bytes value stored under the combination of two keys.
function getBytes(
IIPAccountStorage ipStorage,
ShortString key1,
ShortString key2
) internal view returns (bytes memory) {
return ipStorage.getBytes(toBytes32(string(abi.encodePacked(key1.toString(), key2.toString()))));
}
/// @notice Retrieves a bytes value from the storage under a specified namespace using two `ShortString` keys.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param namespace The namespace under which to retrieve the value.
/// @return The bytes value stored under the combination of two keys.
function getBytes(
IIPAccountStorage ipStorage,
address namespace,
ShortString key1,
ShortString key2
) internal view returns (bytes memory) {
return
ipStorage.getBytes(
toBytes32(namespace),
toBytes32(string(abi.encodePacked(key1.toString(), key2.toString())))
);
}
/// @notice Sets a bytes32 value in the storage using a `ShortString` key.
/// @dev Converts the `ShortString` key to a `bytes32` representation before storing the value,
/// facilitating bytes32 storage in a compact format.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The `ShortString` key under which to store the bytes32 value.
/// @param value The bytes32 value to be stored.
function setBytes32(IIPAccountStorage ipStorage, ShortString key, bytes32 value) internal {
ipStorage.setBytes32(toBytes32(key), value);
}
/// @notice Retrieves a bytes32 value from the storage using a `ShortString` key.
/// @dev Converts the `ShortString` key to a `bytes32` representation before retrieving the value,
/// ensuring the integrity of the bytes32 data.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param key The `ShortString` key whose bytes32 value is to be retrieved.
/// @return The bytes32 value stored under the specified key.
function getBytes32(IIPAccountStorage ipStorage, ShortString key) internal view returns (bytes32) {
return ipStorage.getBytes32(toBytes32(key));
}
/// @notice Retrieves a bytes32 value from the storage under a specified namespace using a bytes32 key.
/// @dev Retrieves the bytes32 value from the specified namespace using the provided key.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param namespace The namespace under which to retrieve the value.
/// @param key The bytes32 key whose bytes32 value is to be retrieved.
/// @return The bytes32 value stored under the specified key in the given namespace.
function getBytes32(IIPAccountStorage ipStorage, address namespace, bytes32 key) internal view returns (bytes32) {
return ipStorage.getBytes32(toBytes32(namespace), key);
}
/// @notice Retrieves a bytes32 value from the storage under a specified namespace using a `ShortString` key.
/// @dev Retrieves the bytes32 value from the specified namespace using the provided `ShortString` key.
/// @param ipStorage The instance of the IPAccountStorage contract.
/// @param namespace The namespace under which to retrieve the value.
/// @param key The `ShortString` key whose bytes32 value is to be retrieved.
/// @return The bytes32 value stored under the specified key in the given namespace.
function getBytes32(
IIPAccountStorage ipStorage,
address namespace,
ShortString key
) internal view returns (bytes32) {
return ipStorage.getBytes32(toBytes32(namespace), toBytes32(key));
}
function toBytes32(string memory s) internal pure returns (bytes32) {
return ShortString.unwrap(s.toShortString());
}
function toBytes32(address a) internal pure returns (bytes32) {
return bytes32(uint256(uint160(a)));
}
function toBytes32(ShortString sstr) internal pure returns (bytes32) {
// remove the length byte from the ShortString
// so that bytes32 result is identical with converting string to bytes32 directly
return ShortString.unwrap(sstr) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00;
}
}// 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 LICENSING_MODULE_KEY = "LICENSING_MODULE"; string constant DISPUTE_MODULE_KEY = "DISPUTE_MODULE"; string constant ROYALTY_MODULE_KEY = "ROYALTY_MODULE"; string constant TOKEN_WITHDRAWAL_MODULE_KEY = "TOKEN_MANAGEMENT_MODULE"; string constant CORE_METADATA_MODULE_KEY = "CORE_METADATA_MODULE"; string constant CORE_METADATA_VIEW_MODULE_KEY = "CORE_METADATA_VIEW_MODULE";
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;
import { IModule } from "../../../../contracts/interfaces/modules/base/IModule.sol";
/// @title CoreMetadataModule
/// @notice Manages the core metadata for IP assets within the Story Protocol.
/// @dev This contract allows setting and updating core metadata attributes for IP assets.
interface ICoreMetadataModule is IModule {
/// @notice Emitted when the nftTokenURI for an IP asset is set.
event NFTTokenURISet(address indexed ipId, string nftTokenURI, bytes32 nftMetadataHash);
/// @notice Emitted when the metadataURI for an IP asset is set.
event MetadataURISet(address indexed ipId, string metadataURI, bytes32 metadataHash);
/// @notice Emitted when all metadata for an IP asset are frozen.
event MetadataFrozen(address indexed ipId);
/// @notice Update the nftTokenURI for an IP asset,
/// by retrieve the latest TokenURI from IP NFT to which the IP Asset bound.
/// @dev Will revert if IP asset's metadata is frozen.
/// @param ipId The address of the IP asset.
/// @param nftMetadataHash A bytes32 hash representing the metadata of the NFT.
/// This metadata is associated with the IP Asset and is accessible via the NFT's TokenURI.
/// Use bytes32(0) to indicate that the metadata is not available.
function updateNftTokenURI(address ipId, bytes32 nftMetadataHash) external;
/// @notice Sets the metadataURI for an IP asset.
/// @dev Will revert if IP asset's metadata is frozen.
/// @param ipId The address of the IP asset.
/// @param metadataURI The metadataURI to set for the IP asset.
/// @param metadataHash The hash of metadata at metadataURI.
/// Use bytes32(0) to indicate that the metadata is not available.
function setMetadataURI(address ipId, string memory metadataURI, bytes32 metadataHash) external;
/// @notice Sets all core metadata for an IP asset.
/// @dev Will revert if IP asset's metadata is frozen.
/// @param ipId The address of the IP asset.
/// @param metadataURI The metadataURI to set for the IP asset.
/// @param metadataHash The hash of metadata at metadataURI.
/// Use bytes32(0) to indicate that the metadata is not available.
/// @param nftMetadataHash A bytes32 hash representing the metadata of the NFT.
/// This metadata is associated with the IP Asset and is accessible via the NFT's TokenURI.
/// Use bytes32(0) to indicate that the metadata is not available.
function setAll(address ipId, string memory metadataURI, bytes32 metadataHash, bytes32 nftMetadataHash) external;
/// @notice make all metadata of the IP Asset immutable.
/// @param ipId The address of the IP asset.
function freezeMetadata(address ipId) external;
/// @notice Check if the metadata of the IP Asset is immutable.
/// @param ipId The address of the IP asset.
function isMetadataFrozen(address ipId) external view returns (bool);
}// 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: 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);
}// 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: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.23;
/// @title IPAccount Namespaced Storage Interface
/// @dev Provides a structured way to store IPAccount's state using a namespaced storage pattern.
/// This interface facilitates conflict-free data writing by different Modules into the same IPAccount
/// by utilizing namespaces.
/// The default namespace for write operations is determined by the `msg.sender`, ensuring that only the owning Module
/// (i.e., the Module calling the write functions) can write data into its respective namespace.
/// However, read operations are unrestricted and can access any namespace.
///
/// Rules:
/// - The default namespace for a Module is its own address.
/// - Every Module can read data from any namespace.
/// - Only the owning Module (i.e., the Module whose address is used as the namespace) can write data into
/// its respective namespace.
interface IIPAccountStorage {
/// @dev Sets a bytes value under a given key within the default namespace, determined by `msg.sender`.
/// @param key The key under which to store the value.
/// @param value The bytes value to be stored.
function setBytes(bytes32 key, bytes calldata value) external;
/// @dev Retrieves a bytes value by a given key from the default namespace.
/// @param key The key whose value is to be retrieved.
/// @return The bytes value stored under the specified key.
function getBytes(bytes32 key) external view returns (bytes memory);
/// @dev Retrieves a bytes value by a given key from a specified namespace.
/// @param namespace The namespace from which to retrieve the value.
/// @param key The key whose value is to be retrieved.
/// @return The bytes value stored under the specified key in the given namespace.
function getBytes(bytes32 namespace, bytes32 key) external view returns (bytes memory);
/// @dev Sets a bytes32 value under a given key within the default namespace, determined by `msg.sender`.
/// @param key The key under which to store the value.
/// @param value The bytes32 value to be stored.
function setBytes32(bytes32 key, bytes32 value) external;
/// @dev Retrieves a bytes32 value by a given key from the default namespace.
/// @param key The key whose value is to be retrieved.
/// @return The bytes32 value stored under the specified key.
function getBytes32(bytes32 key) external view returns (bytes32);
/// @dev Retrieves a bytes32 value by a given key from a specified namespace.
/// @param namespace The namespace from which to retrieve the value.
/// @param key The key whose value is to be retrieved.
/// @return The bytes32 value stored under the specified key in the given namespace.
function getBytes32(bytes32 namespace, bytes32 key) external view returns (bytes32);
}// 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 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 Sets permission to a signer for all functions across all modules.
/// @param ipAccount The address of the IP account that grants the permission for `signer`.
/// @param signer The address of the signer receiving the permissions.
/// @param permission The new permission.
function setAllPermissions(address ipAccount, address signer, 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";
import { IIPAccountStorage } from "../../interfaces/IIPAccountStorage.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_
) internal 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_
) internal 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;
if (!ERC165Checker.supportsInterface(ipAccountAddress_, type(IIPAccountStorage).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;
/// @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: 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: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol)
pragma solidity ^0.8.20;
import {StorageSlot} from "./StorageSlot.sol";
// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
// | length | 0x BB |
type ShortString is bytes32;
/**
* @dev This library provides functions to convert short memory strings
* into a `ShortString` type that can be used as an immutable variable.
*
* Strings of arbitrary length can be optimized using this library if
* they are short enough (up to 31 bytes) by packing them with their
* length (1 byte) in a single EVM word (32 bytes). Additionally, a
* fallback mechanism can be used for every other case.
*
* Usage example:
*
* ```solidity
* contract Named {
* using ShortStrings for *;
*
* ShortString private immutable _name;
* string private _nameFallback;
*
* constructor(string memory contractName) {
* _name = contractName.toShortStringWithFallback(_nameFallback);
* }
*
* function name() external view returns (string memory) {
* return _name.toStringWithFallback(_nameFallback);
* }
* }
* ```
*/
library ShortStrings {
// Used as an identifier for strings longer than 31 bytes.
bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
error StringTooLong(string str);
error InvalidShortString();
/**
* @dev Encode a string of at most 31 chars into a `ShortString`.
*
* This will trigger a `StringTooLong` error is the input string is too long.
*/
function toShortString(string memory str) internal pure returns (ShortString) {
bytes memory bstr = bytes(str);
if (bstr.length > 31) {
revert StringTooLong(str);
}
return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
}
/**
* @dev Decode a `ShortString` back to a "normal" string.
*/
function toString(ShortString sstr) internal pure returns (string memory) {
uint256 len = byteLength(sstr);
// using `new string(len)` would work locally but is not memory safe.
string memory str = new string(32);
/// @solidity memory-safe-assembly
assembly {
mstore(str, len)
mstore(add(str, 0x20), sstr)
}
return str;
}
/**
* @dev Return the length of a `ShortString`.
*/
function byteLength(ShortString sstr) internal pure returns (uint256) {
uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
if (result > 31) {
revert InvalidShortString();
}
return result;
}
/**
* @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
*/
function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
if (bytes(value).length < 32) {
return toShortString(value);
} else {
StorageSlot.getStringSlot(store).value = value;
return ShortString.wrap(FALLBACK_SENTINEL);
}
}
/**
* @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*/
function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
return toString(value);
} else {
return store;
}
}
/**
* @dev Return the length of a string that was encoded to `ShortString` or written to storage using
* {setWithFallback}.
*
* WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
* actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
*/
function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
return byteLength(value);
} else {
return bytes(store).length;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}// 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
// 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: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}{
"remappings": [
"ds-test/=node_modules/ds-test/src/",
"forge-std/=node_modules/forge-std/src/",
"@openzeppelin/=node_modules/@openzeppelin/",
"@openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/",
"@create3-deployer/=lib/create3-deployer/",
"base64-sol/=node_modules/base64-sol/",
"create3-deployer/=lib/create3-deployer/",
"erc6551/=node_modules/erc6551/",
"eth-gas-reporter/=node_modules/eth-gas-reporter/",
"hardhat-deploy/=node_modules/hardhat-deploy/",
"hardhat/=node_modules/hardhat/",
"openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/",
"solady/=node_modules/solady/",
"solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/"
],
"optimizer": {
"enabled": true,
"runs": 20000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false,
"libraries": {
"test/foundry/utils/Users.t.sol": {
"UsersLib": "0x4790fd9437BfBDfB46bce1d48BcB90F4d3611F51"
}
}
}Contract ABI
API[{"inputs":[{"internalType":"address","name":"accessController","type":"address"},{"internalType":"address","name":"ipAccountRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"ipAccount","type":"address"}],"name":"AccessControlled__NotIpAccount","type":"error"},{"inputs":[],"name":"AccessControlled__ZeroAddress","type":"error"},{"inputs":[],"name":"CoreMetadataModule__MetadataAlreadyFrozen","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"ipId","type":"address"}],"name":"MetadataFrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"ipId","type":"address"},{"indexed":false,"internalType":"string","name":"metadataURI","type":"string"},{"indexed":false,"internalType":"bytes32","name":"metadataHash","type":"bytes32"}],"name":"MetadataURISet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"ipId","type":"address"},{"indexed":false,"internalType":"string","name":"nftTokenURI","type":"string"},{"indexed":false,"internalType":"bytes32","name":"nftMetadataHash","type":"bytes32"}],"name":"NFTTokenURISet","type":"event"},{"inputs":[],"name":"ACCESS_CONTROLLER","outputs":[{"internalType":"contract IAccessController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"IP_ACCOUNT_REGISTRY","outputs":[{"internalType":"contract IIPAccountRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"ipId","type":"address"}],"name":"freezeMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"ipId","type":"address"}],"name":"isMetadataFrozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"ipId","type":"address"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"bytes32","name":"metadataHash","type":"bytes32"},{"internalType":"bytes32","name":"nftMetadataHash","type":"bytes32"}],"name":"setAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"ipId","type":"address"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"bytes32","name":"metadataHash","type":"bytes32"}],"name":"setMetadataURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"ipId","type":"address"},{"internalType":"bytes32","name":"nftMetadataHash","type":"bytes32"}],"name":"updateNftTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
610100604052601460c09081527f434f52455f4d455441444154415f4d4f44554c4500000000000000000000000060e0526000906200003f908262000184565b503480156200004d57600080fd5b506040516200176a3803806200176a83398101604081905262000070916200026d565b81816001600160a01b0382166200009a576040516320a816ad60e01b815260040160405180910390fd5b6001600160a01b038116620000c2576040516320a816ad60e01b815260040160405180910390fd5b6001600160a01b039182166080521660a05250620002a59050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200010857607f821691505b6020821081036200012957634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200017f576000816000526020600020601f850160051c810160208610156200015a5750805b601f850160051c820191505b818110156200017b5782815560010162000166565b5050505b505050565b81516001600160401b03811115620001a057620001a0620000dd565b620001b881620001b18454620000f3565b846200012f565b602080601f831160018114620001f05760008415620001d75750858301515b600019600386901b1c1916600185901b1785556200017b565b600085815260208120601f198616915b82811015620002215788860151825594840194600190910190840162000200565b5085821015620002405787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b80516001600160a01b03811681146200026857600080fd5b919050565b600080604083850312156200028157600080fd5b6200028c8362000250565b91506200029c6020840162000250565b90509250929050565b60805160a051611492620002d860003960008181610136015261048101526000818160ea015261059101526114926000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80638225ffcb11610076578063b39865611161005b578063b398656114610180578063b76520c614610193578063d3cae294146101a657600080fd5b80638225ffcb14610158578063a89db2e41461016d57600080fd5b806301ffc9a7146100a857806306fdde03146100d05780631b8b1073146100e5578063702acd8514610131575b600080fd5b6100bb6100b6366004610fdf565b6101b9565b60405190151581526020015b60405180910390f35b6100d8610215565b6040516100c7919061108f565b61010c7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100c7565b61010c7f000000000000000000000000000000000000000000000000000000000000000081565b61016b6101663660046111de565b6102a3565b005b61016b61017b366004611237565b6102be565b61016b61018e366004611254565b61034f565b61016b6101a1366004611280565b610368565b6100bb6101b4366004611237565b61038e565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167ffd8fea1c00000000000000000000000000000000000000000000000000000000148061020f575061020f826103d0565b92915050565b60008054610222906112e0565b80601f016020809104026020016040519081016040528092919081815260200182805461024e906112e0565b801561029b5780601f106102705761010080835404028352916020019161029b565b820191906000526020600020905b81548152906001019060200180831161027e57829003601f168201915b505050505081565b826102ad81610467565b6102b88484846105ea565b50505050565b806102c881610467565b61030a73ffffffffffffffffffffffffffffffffffffffff83167f494d4d555441424c450000000000000000000000000000000000000000000000600161079f565b60405173ffffffffffffffffffffffffffffffffffffffff8316907f613dbfa0da3ed47f98224302f9ec276c6b989b387fd6e613a2a2ce8fa2de2d9c90600090a25050565b8161035981610467565b610363838361083f565b505050565b8361037281610467565b61037c858361083f565b6103878585856105ea565b5050505050565b600061020f73ffffffffffffffffffffffffffffffffffffffff83167f494d4d555441424c450000000000000000000000000000000000000000000000610b24565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f06fdde0300000000000000000000000000000000000000000000000000000000148061020f57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161461020f565b6104a773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001682610bbf565b6104f9576040517fd64edf9000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260240160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff8216146105e7576040517f7dfd0ddb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301523360248301523060448301526000357fffffffff000000000000000000000000000000000000000000000000000000001660648301527f00000000000000000000000000000000000000000000000000000000000000001690637dfd0ddb9060840160006040518083038186803b1580156105d357600080fd5b505afa158015610387573d6000803e3d6000fd5b50565b8261062b73ffffffffffffffffffffffffffffffffffffffff82167f494d4d555441424c450000000000000000000000000000000000000000000000610b24565b15610662576040517f2418226600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106a373ffffffffffffffffffffffffffffffffffffffff85167f4d455441444154415f555249000000000000000000000000000000000000000085610e16565b6040517f4e91db080000000000000000000000000000000000000000000000000000000081527f4d455441444154415f484153480000000000000000000000000000000000000060048201526024810183905273ffffffffffffffffffffffffffffffffffffffff851690634e91db0890604401600060405180830381600087803b15801561073157600080fd5b505af1158015610745573d6000803e3d6000fd5b505050508373ffffffffffffffffffffffffffffffffffffffff167f3b2d707542587feff5c7fe05482776be67fd747e64c2545089b52f395d47de768484604051610791929190611333565b60405180910390a250505050565b8273ffffffffffffffffffffffffffffffffffffffff16634e91db0883836107c85760006107cb565b60015b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925260248201526044015b600060405180830381600087803b15801561082257600080fd5b505af1158015610836573d6000803e3d6000fd5b50505050505050565b8161088073ffffffffffffffffffffffffffffffffffffffff82167f494d4d555441424c450000000000000000000000000000000000000000000000610b24565b156108b7576040517f2418226600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808473ffffffffffffffffffffffffffffffffffffffff1663fc0c546a6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610905573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109299190611355565b6040517fc87b56dd0000000000000000000000000000000000000000000000000000000081526004810182905291945092506000915073ffffffffffffffffffffffffffffffffffffffff84169063c87b56dd90602401600060405180830381865afa15801561099d573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526109e3919081019061138e565b9050610a2673ffffffffffffffffffffffffffffffffffffffff87167f4e46545f544f4b454e5f5552490000000000000000000000000000000000000083610e16565b6040517f4e91db080000000000000000000000000000000000000000000000000000000081527f4e46545f4d455441444154415f4841534800000000000000000000000000000060048201526024810186905273ffffffffffffffffffffffffffffffffffffffff871690634e91db0890604401600060405180830381600087803b158015610ab457600080fd5b505af1158015610ac8573d6000803e3d6000fd5b505050508573ffffffffffffffffffffffffffffffffffffffff167f4f10167731fb167d83b433ff4ef88092caafdc25681547a8045f4c299a5245c58287604051610b14929190611333565b60405180910390a2505050505050565b6040517fa6ed563e0000000000000000000000000000000000000000000000000000000081526004810182905260009073ffffffffffffffffffffffffffffffffffffffff84169063a6ed563e90602401602060405180830381865afa158015610b92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb69190611405565b15159392505050565b600073ffffffffffffffffffffffffffffffffffffffff8216610be45750600061020f565b8173ffffffffffffffffffffffffffffffffffffffff163b600003610c0b5750600061020f565b610c1482610e6a565b610c205750600061020f565b610c4a827f6faff5f100000000000000000000000000000000000000000000000000000000610ece565b610c565750600061020f565b610c80827febe268b300000000000000000000000000000000000000000000000000000000610ece565b610c8c5750600061020f565b610cb6827ff6c924e700000000000000000000000000000000000000000000000000000000610ece565b610cc25750600061020f565b60008060008473ffffffffffffffffffffffffffffffffffffffff1663fc0c546a6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610d12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d369190611355565b6040517f87020f950000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff8084166024830152604482018390529396509194509250908716906387020f9590606401602060405180830381865afa158015610db9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ddd919061141e565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614935050505092915050565b6040517f2e28d08400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690632e28d08490610808908590859060040161143b565b6000610e96827f01ffc9a700000000000000000000000000000000000000000000000000000000610ef1565b801561020f5750610ec7827fffffffff00000000000000000000000000000000000000000000000000000000610ef1565b1592915050565b6000610ed983610e6a565b8015610eea5750610eea8383610ef1565b9392505050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000821660248201526000908190604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825192935060009283928392909183918a617530fa92503d91506000519050828015610fc8575060208210155b8015610fd45750600081115b979650505050505050565b600060208284031215610ff157600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610eea57600080fd5b60005b8381101561103c578181015183820152602001611024565b50506000910152565b6000815180845261105d816020860160208601611021565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610eea6020830184611045565b73ffffffffffffffffffffffffffffffffffffffff811681146105e757600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561113a5761113a6110c4565b604052919050565b600067ffffffffffffffff82111561115c5761115c6110c4565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261119957600080fd5b81356111ac6111a782611142565b6110f3565b8181528460208386010111156111c157600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000606084860312156111f357600080fd5b83356111fe816110a2565b9250602084013567ffffffffffffffff81111561121a57600080fd5b61122686828701611188565b925050604084013590509250925092565b60006020828403121561124957600080fd5b8135610eea816110a2565b6000806040838503121561126757600080fd5b8235611272816110a2565b946020939093013593505050565b6000806000806080858703121561129657600080fd5b84356112a1816110a2565b9350602085013567ffffffffffffffff8111156112bd57600080fd5b6112c987828801611188565b949794965050505060408301359260600135919050565b600181811c908216806112f457607f821691505b60208210810361132d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6040815260006113466040830185611045565b90508260208301529392505050565b60008060006060848603121561136a57600080fd5b83519250602084015161137c816110a2565b80925050604084015190509250925092565b6000602082840312156113a057600080fd5b815167ffffffffffffffff8111156113b757600080fd5b8201601f810184136113c857600080fd5b80516113d66111a782611142565b8181528560208385010111156113eb57600080fd5b6113fc826020830160208601611021565b95945050505050565b60006020828403121561141757600080fd5b5051919050565b60006020828403121561143057600080fd5b8151610eea816110a2565b8281526040602082015260006114546040830184611045565b94935050505056fea2646970667358221220274c1b56766b500ee97f927c8fc7728467115a22603722ba65a628e3f0c3e61364736f6c63430008170033000000000000000000000000f9936a224b3deb6f9a4645ccafa66f7ece83cf0a000000000000000000000000d43fe0d865cb5c26b1351d3eaf2e3064be3276f6
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100a35760003560e01c80638225ffcb11610076578063b39865611161005b578063b398656114610180578063b76520c614610193578063d3cae294146101a657600080fd5b80638225ffcb14610158578063a89db2e41461016d57600080fd5b806301ffc9a7146100a857806306fdde03146100d05780631b8b1073146100e5578063702acd8514610131575b600080fd5b6100bb6100b6366004610fdf565b6101b9565b60405190151581526020015b60405180910390f35b6100d8610215565b6040516100c7919061108f565b61010c7f000000000000000000000000f9936a224b3deb6f9a4645ccafa66f7ece83cf0a81565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100c7565b61010c7f000000000000000000000000d43fe0d865cb5c26b1351d3eaf2e3064be3276f681565b61016b6101663660046111de565b6102a3565b005b61016b61017b366004611237565b6102be565b61016b61018e366004611254565b61034f565b61016b6101a1366004611280565b610368565b6100bb6101b4366004611237565b61038e565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167ffd8fea1c00000000000000000000000000000000000000000000000000000000148061020f575061020f826103d0565b92915050565b60008054610222906112e0565b80601f016020809104026020016040519081016040528092919081815260200182805461024e906112e0565b801561029b5780601f106102705761010080835404028352916020019161029b565b820191906000526020600020905b81548152906001019060200180831161027e57829003601f168201915b505050505081565b826102ad81610467565b6102b88484846105ea565b50505050565b806102c881610467565b61030a73ffffffffffffffffffffffffffffffffffffffff83167f494d4d555441424c450000000000000000000000000000000000000000000000600161079f565b60405173ffffffffffffffffffffffffffffffffffffffff8316907f613dbfa0da3ed47f98224302f9ec276c6b989b387fd6e613a2a2ce8fa2de2d9c90600090a25050565b8161035981610467565b610363838361083f565b505050565b8361037281610467565b61037c858361083f565b6103878585856105ea565b5050505050565b600061020f73ffffffffffffffffffffffffffffffffffffffff83167f494d4d555441424c450000000000000000000000000000000000000000000000610b24565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f06fdde0300000000000000000000000000000000000000000000000000000000148061020f57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161461020f565b6104a773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d43fe0d865cb5c26b1351d3eaf2e3064be3276f61682610bbf565b6104f9576040517fd64edf9000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260240160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff8216146105e7576040517f7dfd0ddb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301523360248301523060448301526000357fffffffff000000000000000000000000000000000000000000000000000000001660648301527f000000000000000000000000f9936a224b3deb6f9a4645ccafa66f7ece83cf0a1690637dfd0ddb9060840160006040518083038186803b1580156105d357600080fd5b505afa158015610387573d6000803e3d6000fd5b50565b8261062b73ffffffffffffffffffffffffffffffffffffffff82167f494d4d555441424c450000000000000000000000000000000000000000000000610b24565b15610662576040517f2418226600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106a373ffffffffffffffffffffffffffffffffffffffff85167f4d455441444154415f555249000000000000000000000000000000000000000085610e16565b6040517f4e91db080000000000000000000000000000000000000000000000000000000081527f4d455441444154415f484153480000000000000000000000000000000000000060048201526024810183905273ffffffffffffffffffffffffffffffffffffffff851690634e91db0890604401600060405180830381600087803b15801561073157600080fd5b505af1158015610745573d6000803e3d6000fd5b505050508373ffffffffffffffffffffffffffffffffffffffff167f3b2d707542587feff5c7fe05482776be67fd747e64c2545089b52f395d47de768484604051610791929190611333565b60405180910390a250505050565b8273ffffffffffffffffffffffffffffffffffffffff16634e91db0883836107c85760006107cb565b60015b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925260248201526044015b600060405180830381600087803b15801561082257600080fd5b505af1158015610836573d6000803e3d6000fd5b50505050505050565b8161088073ffffffffffffffffffffffffffffffffffffffff82167f494d4d555441424c450000000000000000000000000000000000000000000000610b24565b156108b7576040517f2418226600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808473ffffffffffffffffffffffffffffffffffffffff1663fc0c546a6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610905573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109299190611355565b6040517fc87b56dd0000000000000000000000000000000000000000000000000000000081526004810182905291945092506000915073ffffffffffffffffffffffffffffffffffffffff84169063c87b56dd90602401600060405180830381865afa15801561099d573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526109e3919081019061138e565b9050610a2673ffffffffffffffffffffffffffffffffffffffff87167f4e46545f544f4b454e5f5552490000000000000000000000000000000000000083610e16565b6040517f4e91db080000000000000000000000000000000000000000000000000000000081527f4e46545f4d455441444154415f4841534800000000000000000000000000000060048201526024810186905273ffffffffffffffffffffffffffffffffffffffff871690634e91db0890604401600060405180830381600087803b158015610ab457600080fd5b505af1158015610ac8573d6000803e3d6000fd5b505050508573ffffffffffffffffffffffffffffffffffffffff167f4f10167731fb167d83b433ff4ef88092caafdc25681547a8045f4c299a5245c58287604051610b14929190611333565b60405180910390a2505050505050565b6040517fa6ed563e0000000000000000000000000000000000000000000000000000000081526004810182905260009073ffffffffffffffffffffffffffffffffffffffff84169063a6ed563e90602401602060405180830381865afa158015610b92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb69190611405565b15159392505050565b600073ffffffffffffffffffffffffffffffffffffffff8216610be45750600061020f565b8173ffffffffffffffffffffffffffffffffffffffff163b600003610c0b5750600061020f565b610c1482610e6a565b610c205750600061020f565b610c4a827f6faff5f100000000000000000000000000000000000000000000000000000000610ece565b610c565750600061020f565b610c80827febe268b300000000000000000000000000000000000000000000000000000000610ece565b610c8c5750600061020f565b610cb6827ff6c924e700000000000000000000000000000000000000000000000000000000610ece565b610cc25750600061020f565b60008060008473ffffffffffffffffffffffffffffffffffffffff1663fc0c546a6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610d12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d369190611355565b6040517f87020f950000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff8084166024830152604482018390529396509194509250908716906387020f9590606401602060405180830381865afa158015610db9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ddd919061141e565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614935050505092915050565b6040517f2e28d08400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690632e28d08490610808908590859060040161143b565b6000610e96827f01ffc9a700000000000000000000000000000000000000000000000000000000610ef1565b801561020f5750610ec7827fffffffff00000000000000000000000000000000000000000000000000000000610ef1565b1592915050565b6000610ed983610e6a565b8015610eea5750610eea8383610ef1565b9392505050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000821660248201526000908190604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825192935060009283928392909183918a617530fa92503d91506000519050828015610fc8575060208210155b8015610fd45750600081115b979650505050505050565b600060208284031215610ff157600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610eea57600080fd5b60005b8381101561103c578181015183820152602001611024565b50506000910152565b6000815180845261105d816020860160208601611021565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610eea6020830184611045565b73ffffffffffffffffffffffffffffffffffffffff811681146105e757600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561113a5761113a6110c4565b604052919050565b600067ffffffffffffffff82111561115c5761115c6110c4565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261119957600080fd5b81356111ac6111a782611142565b6110f3565b8181528460208386010111156111c157600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000606084860312156111f357600080fd5b83356111fe816110a2565b9250602084013567ffffffffffffffff81111561121a57600080fd5b61122686828701611188565b925050604084013590509250925092565b60006020828403121561124957600080fd5b8135610eea816110a2565b6000806040838503121561126757600080fd5b8235611272816110a2565b946020939093013593505050565b6000806000806080858703121561129657600080fd5b84356112a1816110a2565b9350602085013567ffffffffffffffff8111156112bd57600080fd5b6112c987828801611188565b949794965050505060408301359260600135919050565b600181811c908216806112f457607f821691505b60208210810361132d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6040815260006113466040830185611045565b90508260208301529392505050565b60008060006060848603121561136a57600080fd5b83519250602084015161137c816110a2565b80925050604084015190509250925092565b6000602082840312156113a057600080fd5b815167ffffffffffffffff8111156113b757600080fd5b8201601f810184136113c857600080fd5b80516113d66111a782611142565b8181528560208385010111156113eb57600080fd5b6113fc826020830160208601611021565b95945050505050565b60006020828403121561141757600080fd5b5051919050565b60006020828403121561143057600080fd5b8151610eea816110a2565b8281526040602082015260006114546040830184611045565b94935050505056fea2646970667358221220274c1b56766b500ee97f927c8fc7728467115a22603722ba65a628e3f0c3e61364736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000f9936a224b3deb6f9a4645ccafa66f7ece83cf0a000000000000000000000000d43fe0d865cb5c26b1351d3eaf2e3064be3276f6
-----Decoded View---------------
Arg [0] : accessController (address): 0xF9936a224b3Deb6f9A4645ccAfa66f7ECe83CF0A
Arg [1] : ipAccountRegistry (address): 0xd43fE0d865cb5C26b1351d3eAf2E3064BE3276F6
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000f9936a224b3deb6f9a4645ccafa66f7ece83cf0a
Arg [1] : 000000000000000000000000d43fe0d865cb5c26b1351d3eaf2e3064be3276f6
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.