Sepolia Testnet

Contract

0x613128e88b568768764824f898C8135efED97fA6
Source Code Source Code

Overview

ETH Balance

0 ETH

More Info

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Amount
Register Root Ip84950472025-06-07 7:11:36227 days ago1749280296IN
0x613128e8...efED97fA6
0 ETH0.000674941.50010551
Register Root Ip69232822024-10-22 14:42:12454 days ago1729608132IN
0x613128e8...efED97fA6
0 ETH0.001220443.15686107
Register Root Ip65946962024-08-29 15:52:12508 days ago1724946732IN
0x613128e8...efED97fA6
0 ETH0.03913505101.25342942
Register Root Ip65943112024-08-29 14:23:12508 days ago1724941392IN
0x613128e8...efED97fA6
0 ETH0.0209847954.27672268
Register Root Ip65659232024-08-25 2:35:00513 days ago1724553300IN
0x613128e8...efED97fA6
0 ETH0.002111995.45237501
Register Root Ip65659232024-08-25 2:35:00513 days ago1724553300IN
0x613128e8...efED97fA6
0 ETH0.002112585.45237501
Register Root Ip65659232024-08-25 2:35:00513 days ago1724553300IN
0x613128e8...efED97fA6
0 ETH0.002112395.45237501
Register Root Ip65659232024-08-25 2:35:00513 days ago1724553300IN
0x613128e8...efED97fA6
0 ETH0.002112265.45237501
Register Root Ip65659232024-08-25 2:35:00513 days ago1724553300IN
0x613128e8...efED97fA6
0 ETH0.002112325.45237501
Register Root Ip65659232024-08-25 2:35:00513 days ago1724553300IN
0x613128e8...efED97fA6
0 ETH0.002112135.45237501
Register Root Ip65659232024-08-25 2:35:00513 days ago1724553300IN
0x613128e8...efED97fA6
0 ETH0.002112195.45237501
Register Root Ip65659232024-08-25 2:35:00513 days ago1724553300IN
0x613128e8...efED97fA6
0 ETH0.002112135.45237501
Register Root Ip65659232024-08-25 2:35:00513 days ago1724553300IN
0x613128e8...efED97fA6
0 ETH0.002112135.45237501
Register Root Ip65659232024-08-25 2:35:00513 days ago1724553300IN
0x613128e8...efED97fA6
0 ETH0.002111995.45237501
Register Root Ip65659232024-08-25 2:35:00513 days ago1724553300IN
0x613128e8...efED97fA6
0 ETH0.002112455.45237501
Register Root Ip65659232024-08-25 2:35:00513 days ago1724553300IN
0x613128e8...efED97fA6
0 ETH0.002112135.45237501
Register Root Ip65659222024-08-25 2:34:48513 days ago1724553288IN
0x613128e8...efED97fA6
0 ETH0.002202055.68468014
Register Root Ip65659222024-08-25 2:34:48513 days ago1724553288IN
0x613128e8...efED97fA6
0 ETH0.002202465.68468014
Register Root Ip65659222024-08-25 2:34:48513 days ago1724553288IN
0x613128e8...efED97fA6
0 ETH0.002202055.68468014
Register Root Ip65659222024-08-25 2:34:48513 days ago1724553288IN
0x613128e8...efED97fA6
0 ETH0.002202255.68468014
Register Root Ip65659212024-08-25 2:34:36513 days ago1724553276IN
0x613128e8...efED97fA6
0 ETH0.002217445.72405422
Register Root Ip65659212024-08-25 2:34:36513 days ago1724553276IN
0x613128e8...efED97fA6
0 ETH0.002217855.72405422
Register Root Ip65659212024-08-25 2:34:36513 days ago1724553276IN
0x613128e8...efED97fA6
0 ETH0.002217645.72405422
Register Root Ip65659212024-08-25 2:34:36513 days ago1724553276IN
0x613128e8...efED97fA6
0 ETH0.002217375.72405422
Register Root Ip65659212024-08-25 2:34:36513 days ago1724553276IN
0x613128e8...efED97fA6
0 ETH0.000155645.72405422
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
Amount
Transfer*84950472025-06-07 7:11:36227 days ago1749280296
0x613128e8...efED97fA6
0 ETH
Transfer*84950472025-06-07 7:11:36227 days ago1749280296
0x613128e8...efED97fA6
0 ETH
Transfer*69232822024-10-22 14:42:12454 days ago1729608132
0x613128e8...efED97fA6
0 ETH
Transfer*69232822024-10-22 14:42:12454 days ago1729608132
0x613128e8...efED97fA6
0 ETH
Transfer*65946962024-08-29 15:52:12508 days ago1724946732
0x613128e8...efED97fA6
0 ETH
Transfer*65946962024-08-29 15:52:12508 days ago1724946732
0x613128e8...efED97fA6
0 ETH
Transfer*65943112024-08-29 14:23:12508 days ago1724941392
0x613128e8...efED97fA6
0 ETH
Transfer*65943112024-08-29 14:23:12508 days ago1724941392
0x613128e8...efED97fA6
0 ETH
Transfer*65659232024-08-25 2:35:00513 days ago1724553300
0x613128e8...efED97fA6
0 ETH
Transfer*65659232024-08-25 2:35:00513 days ago1724553300
0x613128e8...efED97fA6
0 ETH
Transfer*65659232024-08-25 2:35:00513 days ago1724553300
0x613128e8...efED97fA6
0 ETH
Transfer*65659232024-08-25 2:35:00513 days ago1724553300
0x613128e8...efED97fA6
0 ETH
Transfer*65659232024-08-25 2:35:00513 days ago1724553300
0x613128e8...efED97fA6
0 ETH
Transfer*65659232024-08-25 2:35:00513 days ago1724553300
0x613128e8...efED97fA6
0 ETH
Transfer*65659232024-08-25 2:35:00513 days ago1724553300
0x613128e8...efED97fA6
0 ETH
Transfer*65659232024-08-25 2:35:00513 days ago1724553300
0x613128e8...efED97fA6
0 ETH
Transfer*65659232024-08-25 2:35:00513 days ago1724553300
0x613128e8...efED97fA6
0 ETH
Transfer*65659232024-08-25 2:35:00513 days ago1724553300
0x613128e8...efED97fA6
0 ETH
Transfer*65659232024-08-25 2:35:00513 days ago1724553300
0x613128e8...efED97fA6
0 ETH
Transfer*65659232024-08-25 2:35:00513 days ago1724553300
0x613128e8...efED97fA6
0 ETH
Transfer*65659232024-08-25 2:35:00513 days ago1724553300
0x613128e8...efED97fA6
0 ETH
Transfer*65659232024-08-25 2:35:00513 days ago1724553300
0x613128e8...efED97fA6
0 ETH
Transfer*65659232024-08-25 2:35:00513 days ago1724553300
0x613128e8...efED97fA6
0 ETH
Transfer*65659232024-08-25 2:35:00513 days ago1724553300
0x613128e8...efED97fA6
0 ETH
Transfer*65659232024-08-25 2:35:00513 days ago1724553300
0x613128e8...efED97fA6
0 ETH
View All Internal Transactions
Loading...
Loading

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
RegistrationModule

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 20000 runs

Other Settings:
paris EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";

import { IPResolver } from "../resolvers/IPResolver.sol";
import { IRegistrationModule } from "../interfaces/modules/IRegistrationModule.sol";
import { REGISTRATION_MODULE_KEY } from "../lib/modules/Module.sol";
import { Errors } from "../lib/Errors.sol";
import { IP } from "../lib/IP.sol";
import { BaseModule } from "../modules/BaseModule.sol";
import { ILicensingModule } from "../interfaces/modules/licensing/ILicensingModule.sol";
import { IIPAssetRegistry } from "../interfaces/registries/IIPAssetRegistry.sol";

/// @title Registration Module
/// @notice The registration module is responsible for registration of IP into
///         the protocol. During registration, this module will register an IP
///         into the protocol, create a resolver, and bind to it any licenses
///         and terms specified by the IP registrant (IP account owner).
contract RegistrationModule is BaseModule, IRegistrationModule {
    string public constant override name = REGISTRATION_MODULE_KEY;

    /// @notice Returns the metadata resolver used by the registration module.
    IPResolver public ipResolver;

    /// @dev The canonical protocol-wide IP Asset Registry
    IIPAssetRegistry private _IP_ASSET_REGISTRY;

    /// @dev The canonical protocol-wide Licensing Module
    ILicensingModule private _LICENSING_MODULE;

    constructor(address assetRegistry, address licensingModule, address resolverAddr) {
        ipResolver = IPResolver(resolverAddr);
        _LICENSING_MODULE = ILicensingModule(licensingModule);
        _IP_ASSET_REGISTRY = IIPAssetRegistry(assetRegistry);
    }

    // TODO: Rethink the semantics behind "root-level IPs" vs. "normal IPs".
    // TODO: Update function parameters to utilize a struct instead.
    // TODO: Revisit requiring binding an existing NFT to a "root-level IP".
    // If root-level IPs are an organizational primitive, why require NFTs?
    // TODO: Change to a different resolver optimized for root IP metadata.
    /// @notice Registers a root-level IP into the protocol. Root-level IPs can be thought of as organizational hubs
    /// for encapsulating policies that actual IPs can use to register through. As such, a root-level IP is not an
    /// actual IP, but a container for IP policy management for their child IP assets.
    /// @param policyId The policy that identifies the licensing terms of the IP.
    /// @param tokenContract The address of the NFT bound to the root-level IP.
    /// @param tokenId The token id of the NFT bound to the root-level IP.
    /// @param ipName The name assigned to the new IP.
    /// @param contentHash The content hash of the IP being registered.
    /// @param externalURL An external URI to link to the IP.
    function registerRootIp(
        uint256 policyId,
        address tokenContract,
        uint256 tokenId,
        string memory ipName,
        bytes32 contentHash,
        string calldata externalURL
    ) external returns (address) {
        // Perform registrant authorization.
        // Check that the caller is authorized to perform the registration.
        // TODO: Perform additional registration authorization logic, allowing
        //       registrants or root-IP creators to specify their own auth logic.
        address owner = IERC721(tokenContract).ownerOf(tokenId);
        if (msg.sender != owner && !IERC721(tokenContract).isApprovedForAll(owner, msg.sender)) {
            revert Errors.RegistrationModule__InvalidOwner();
        }

        bytes memory metadata = abi.encode(
            IP.MetadataV1({
                name: ipName,
                hash: contentHash,
                registrationDate: uint64(block.timestamp),
                registrant: msg.sender,
                uri: externalURL
            })
        );

        // Perform core IP registration and IP account creation.
        address ipId = _IP_ASSET_REGISTRY.register(
            block.chainid,
            tokenContract,
            tokenId,
            address(ipResolver),
            true,
            metadata
        );

        // Perform core IP policy creation.
        if (policyId != 0) {
            // If we know the policy ID, we can register it directly on creation.
            // TODO: return policy index
            _LICENSING_MODULE.addPolicyToIp(ipId, policyId);
        }

        emit RootIPRegistered(msg.sender, ipId, policyId);

        return ipId;
    }

    // TODO: Replace all metadata with a generic bytes parameter type, and do encoding on the periphery contract
    // level instead.
    /// @notice Registers derivative IPs into the protocol. Derivative IPs are IP assets that inherit policies from
    /// parent IPs by burning acquired license NFTs.
    /// @param licenseIds The licenses to incorporate for the new IP.
    /// @param tokenContract The address of the NFT bound to the derivative IP.
    /// @param tokenId The token id of the NFT bound to the derivative IP.
    /// @param ipName The name assigned to the new IP.
    /// @param contentHash The content hash of the IP being registered.
    /// @param externalURL An external URI to link to the IP.
    /// @param royaltyContext The royalty context for the derivative IP.
    /// TODO: Replace all metadata with a generic bytes parameter type, and do
    ///       encoding on the periphery contract level instead.
    function registerDerivativeIp(
        uint256[] calldata licenseIds,
        address tokenContract,
        uint256 tokenId,
        string memory ipName,
        bytes32 contentHash,
        string calldata externalURL,
        bytes calldata royaltyContext
    ) external {
        // Check that the caller is authorized to perform the registration.
        // TODO: Perform additional registration authorization logic, allowing
        //       registrants or IP creators to specify their own auth logic.
        address owner = IERC721(tokenContract).ownerOf(tokenId);
        if (msg.sender != owner && !IERC721(tokenContract).isApprovedForAll(owner, msg.sender)) {
            revert Errors.RegistrationModule__InvalidOwner();
        }

        bytes memory metadata = abi.encode(
            IP.MetadataV1({
                name: ipName,
                hash: contentHash,
                registrationDate: uint64(block.timestamp),
                registrant: msg.sender,
                uri: externalURL
            })
        );
        address ipId = _IP_ASSET_REGISTRY.register(
            block.chainid,
            tokenContract,
            tokenId,
            address(ipResolver),
            true,
            metadata
        );

        // Perform core IP derivative licensing - the license must be owned by the caller.
        _LICENSING_MODULE.linkIpToParents(licenseIds, ipId, royaltyContext);

        emit DerivativeIPRegistered(msg.sender, ipId, licenseIds);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
     *   {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { ResolverBase } from "./ResolverBase.sol";
import { KeyValueResolver } from "../resolvers/KeyValueResolver.sol";
import { IP_RESOLVER_MODULE_KEY } from "../lib/modules/Module.sol";

/// @title IP Resolver
/// @notice Canonical IP resolver contract used for Story Protocol.
/// TODO: Add support for interface resolvers, where one can add a contract
///        and supported interface (address, interfaceId) to tie to an IP asset.
/// TODO: Add support for multicall, so multiple records may be set at once.
contract IPResolver is KeyValueResolver {
    string public constant override name = IP_RESOLVER_MODULE_KEY;

    constructor(address accessController, address ipAssetRegistry) ResolverBase(accessController, ipAssetRegistry) {}

    /// @notice IERC165 interface support.
    function supportsInterface(bytes4 id) public view virtual override returns (bool) {
        return super.supportsInterface(id);
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { IPResolver } from "../../resolvers/IPResolver.sol";

interface IRegistrationModule {
    /// @notice Emitted when a root-level IP is registered.
    /// @param caller The address of the caller.
    /// @param ipId The address of the IP that was registered.
    /// @param policyId The policy that identifies the licensing terms of the IP.
    event RootIPRegistered(address indexed caller, address indexed ipId, uint256 indexed policyId);

    /// @notice Emitted when a derivative IP is registered.
    /// @param caller The address of the caller.
    /// @param ipId The address of the IP that was registered.
    /// @param licenseIds The licenses that were used to register the derivative IP.
    event DerivativeIPRegistered(address indexed caller, address indexed ipId, uint256[] licenseIds);

    /// @notice Returns the metadata resolver used by the registration module.
    function ipResolver() external view returns (IPResolver);

    /// @notice Registers a root-level IP into the protocol. Root-level IPs can be thought of as organizational hubs
    /// for encapsulating policies that actual IPs can use to register through. As such, a root-level IP is not an
    /// actual IP, but a container for IP policy management for their child IP assets.
    /// @param policyId The policy that identifies the licensing terms of the IP.
    /// @param tokenContract The address of the NFT bound to the root-level IP.
    /// @param tokenId The token id of the NFT bound to the root-level IP.
    /// @param ipName The name assigned to the new IP.
    /// @param contentHash The content hash of the IP being registered.
    /// @param externalURL An external URI to link to the IP.
    function registerRootIp(
        uint256 policyId,
        address tokenContract,
        uint256 tokenId,
        string memory ipName,
        bytes32 contentHash,
        string calldata externalURL
    ) external returns (address);

    /// @notice Registers derivative IPs into the protocol. Derivative IPs are IP assets that inherit policies from
    /// parent IPs by burning acquired license NFTs.
    /// @param licenseIds The licenses to incorporate for the new IP.
    /// @param tokenContract The address of the NFT bound to the derivative IP.
    /// @param tokenId The token id of the NFT bound to the derivative IP.
    /// @param ipName The name assigned to the new IP.
    /// @param contentHash The content hash of the IP being registered.
    /// @param externalURL An external URI to link to the IP.
    /// @param royaltyContext The royalty context for the derivative IP.
    function registerDerivativeIp(
        uint256[] calldata licenseIds,
        address tokenContract,
        uint256 tokenId,
        string memory ipName,
        bytes32 contentHash,
        string calldata externalURL,
        bytes calldata royaltyContext
    ) external;
}

File 5 of 43 : Module.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

// Default Module Type, all modules in this type by default
string constant MODULE_TYPE_DEFAULT = "MODULE";

string constant MODULE_TYPE_HOOK = "HOOK_MODULE";

// String values for core protocol modules.
string constant IP_RESOLVER_MODULE_KEY = "IP_RESOLVER_MODULE";

// String values for core protocol modules.
string constant REGISTRATION_MODULE_KEY = "REGISTRATION_MODULE";

// String values for core protocol modules.
string constant LICENSING_MODULE_KEY = "LICENSING_MODULE";

// String values for core protocol modules.
string constant DISPUTE_MODULE_KEY = "DISPUTE_MODULE";

string constant ROYALTY_MODULE_KEY = "ROYALTY_MODULE";

string constant TOKEN_WITHDRAWAL_MODULE_KEY = "TOKEN_MANAGEMENT_MODULE";

File 6 of 43 : Errors.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

/// @title Errors Library
/// @notice Library for all Story Protocol contract errors.
library Errors {
    ////////////////////////////////////////////////////////////////////////////
    //                                Governance                              //
    ////////////////////////////////////////////////////////////////////////////
    error Governance__OnlyProtocolAdmin();
    error Governance__ZeroAddress();
    error Governance__ProtocolPaused();
    error Governance__InconsistentState();
    error Governance__NewStateIsTheSameWithOldState();
    error Governance__UnsupportedInterface(string interfaceName);

    ////////////////////////////////////////////////////////////////////////////
    //                                IPAccount                               //
    ////////////////////////////////////////////////////////////////////////////
    error IPAccount__InvalidSigner();
    error IPAccount__InvalidSignature();
    error IPAccount__ExpiredSignature();
    error IPAccount__InvalidCalldata();
    error IPAccount__InvalidAccessController();

    ////////////////////////////////////////////////////////////////////////////
    //                                   Module                               //
    ////////////////////////////////////////////////////////////////////////////

    /// @notice The caller is not allowed to call the provided module.
    error Module_Unauthorized();

    ////////////////////////////////////////////////////////////////////////////
    //                               IPAccountRegistry                        //
    ////////////////////////////////////////////////////////////////////////////
    error IPAccountRegistry_InvalidIpAccountImpl();

    ////////////////////////////////////////////////////////////////////////////
    //                               IPAssetRegistry                         //
    ////////////////////////////////////////////////////////////////////////////

    /// @notice The IP asset has already been registered.
    error IPAssetRegistry__AlreadyRegistered();

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

    /// @notice The IP asset has not yet been registered.
    error IPAssetRegistry__NotYetRegistered();

    /// @notice The IP asset registrant is not authorized.
    error IPAssetRegistry__RegistrantUnauthorized();

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

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

    /// @notice The deployed address of account doesn't match with IP ID.
    error IPAssetRegistry__InvalidAccount();

    /// @notice The metadata provider is not valid.
    error IPAssetRegistry__InvalidMetadataProvider();

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

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

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

    ////////////////////////////////////////////////////////////////////////////
    //                          Metadata Provider                            ///
    ////////////////////////////////////////////////////////////////////////////

    /// @notice Provided hash metadata is not valid.
    error MetadataProvider__HashInvalid();

    /// @notice The caller is not the authorized IP asset owner.
    error MetadataProvider__IPAssetOwnerInvalid();

    /// @notice Provided hash metadata is not valid.
    error MetadataProvider__NameInvalid();

    /// @notice The new metadata provider is not compatible with the old provider.
    error MetadataProvider__MetadataNotCompatible();

    /// @notice Provided registrant metadata is not valid.
    error MetadataProvider__RegistrantInvalid();

    /// @notice Provided registration date is not valid.
    error MetadataProvider__RegistrationDateInvalid();

    /// @notice Caller does not access to set metadata storage for the provider.
    error MetadataProvider__Unauthorized();

    /// @notice A metadata provider upgrade is not currently available.
    error MetadataProvider__UpgradeUnavailable();

    /// @notice The upgrade provider is not valid.
    error MetadataProvider__UpgradeProviderInvalid();

    /// @notice Provided metadata URI is not valid.
    error MetadataProvider__URIInvalid();

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

    error LicenseRegistry__CallerNotLicensingModule();
    error LicenseRegistry__ZeroLicensingModule();
    error LicensingModule__CallerNotLicenseRegistry();
    error LicenseRegistry__RevokedLicense();
    /// @notice emitted when trying to transfer a license that is not transferable (by policy)
    error LicenseRegistry__NotTransferable();
    /// @notice emitted on constructor if dispute module is not set
    error LicenseRegistry__ZeroDisputeModule();

    ////////////////////////////////////////////////////////////////////////////
    //                            LicensingModule                             //
    ////////////////////////////////////////////////////////////////////////////

    error LicensingModule__PolicyAlreadySetForIpId();
    error LicensingModule__FrameworkNotFound();
    error LicensingModule__EmptyLicenseUrl();
    error LicensingModule__InvalidPolicyFramework();
    error LicensingModule__ParamVerifierLengthMismatch();
    error LicensingModule__PolicyNotFound();
    error LicensingModule__NotLicensee();
    error LicensingModule__ParentIdEqualThanChild();
    error LicensingModule__LicensorDoesntHaveThisPolicy();
    error LicensingModule__MintLicenseParamFailed();
    error LicensingModule__LinkParentParamFailed();
    error LicensingModule__TransferParamFailed();
    error LicensingModule__InvalidLicensor();
    error LicensingModule__ParamVerifierAlreadySet();
    error LicensingModule__CommercialTermInNonCommercialPolicy();
    error LicensingModule__EmptyParamName();
    error LicensingModule__UnregisteredFrameworkAddingPolicy();
    error LicensingModule__UnauthorizedAccess();
    error LicensingModule__LicensorNotRegistered();
    error LicensingModule__CallerNotLicensorAndPolicyNotSet();
    error LicensingModule__DerivativesCannotAddPolicy();
    error LicensingModule__IncompatibleRoyaltyPolicyAddress();
    error LicensingModule__IncompatibleRoyaltyPolicyDerivativeRevShare();
    error LicensingModule__IncompatibleLicensorCommercialPolicy();
    error LicensingModule__IncompatibleLicensorRoyaltyDerivativeRevShare();
    error LicensingModule__DerivativeRevShareSumExceedsMaxRNFTSupply();
    error LicensingModule__MismatchBetweenRoyaltyPolicy();
    error LicensingModule__RegisterPolicyFrameworkMismatch();
    error LicensingModule__RoyaltyPolicyNotWhitelisted();
    error LicensingModule__MintingFeeTokenNotWhitelisted();
    error LicensingModule__ReceiverZeroAddress();
    error LicensingModule__MintAmountZero();
    /// @notice emitted when trying to interact with an IP that has been disputed in the DisputeModule
    error LicensingModule__DisputedIpId();
    /// @notice emitted when linking a license from a licensor that has been disputed in the DisputeModule
    error LicensingModule__LinkingRevokedLicense();

    ////////////////////////////////////////////////////////////////////////////
    //                        LicensingModuleAware                            //
    ////////////////////////////////////////////////////////////////////////////

    error LicensingModuleAware__CallerNotLicensingModule();

    ////////////////////////////////////////////////////////////////////////////
    //                         PolicyFrameworkManager                         //
    ////////////////////////////////////////////////////////////////////////////

    error PolicyFrameworkManager__GettingPolicyWrongFramework();
    error PolicyFrameworkManager__CommercializerCheckerDoesNotSupportHook(address commercializer);

    ////////////////////////////////////////////////////////////////////////////
    //                     LicensorApprovalChecker                            //
    ////////////////////////////////////////////////////////////////////////////
    error LicensorApprovalChecker__Unauthorized();

    ////////////////////////////////////////////////////////////////////////////
    //                            Dispute Module                              //
    ////////////////////////////////////////////////////////////////////////////

    error DisputeModule__ZeroArbitrationPolicy();
    error DisputeModule__ZeroArbitrationRelayer();
    error DisputeModule__ZeroDisputeTag();
    error DisputeModule__ZeroLinkToDisputeEvidence();
    error DisputeModule__NotWhitelistedArbitrationPolicy();
    error DisputeModule__NotWhitelistedDisputeTag();
    error DisputeModule__NotWhitelistedArbitrationRelayer();
    error DisputeModule__NotDisputeInitiator();
    error DisputeModule__NotInDisputeState();
    error DisputeModule__NotAbleToResolve();
    error DisputeModule__NotRegisteredIpId();
    error DisputeModule__UnauthorizedAccess();

    error ArbitrationPolicySP__ZeroDisputeModule();
    error ArbitrationPolicySP__ZeroPaymentToken();
    error ArbitrationPolicySP__NotDisputeModule();

    ////////////////////////////////////////////////////////////////////////////
    //                            Royalty Module                              //
    ////////////////////////////////////////////////////////////////////////////

    error RoyaltyModule__ZeroRoyaltyPolicy();
    error RoyaltyModule__NotWhitelistedRoyaltyPolicy();
    error RoyaltyModule__ZeroRoyaltyToken();
    error RoyaltyModule__NotWhitelistedRoyaltyToken();
    error RoyaltyModule__NoRoyaltyPolicySet();
    error RoyaltyModule__IncompatibleRoyaltyPolicy();
    error RoyaltyModule__NotAllowedCaller();
    error RoyaltyModule__ZeroLicensingModule();
    error RoyaltyModule__CanOnlyMintSelectedPolicy();
    error RoyaltyModule__NoParentsOnLinking();
    error RoyaltyModule__NotRegisteredIpId();

    error RoyaltyPolicyLAP__ZeroRoyaltyModule();
    error RoyaltyPolicyLAP__ZeroLiquidSplitFactory();
    error RoyaltyPolicyLAP__ZeroLiquidSplitMain();
    error RoyaltyPolicyLAP__NotRoyaltyModule();
    error RoyaltyPolicyLAP__ZeroLicensingModule();
    error RoyaltyPolicyLAP__AboveParentLimit();
    error RoyaltyPolicyLAP__AboveAncestorsLimit();
    error RoyaltyPolicyLAP__AboveRoyaltyStackLimit();
    error RoyaltyPolicyLAP__InvalidAncestorsLength();
    error RoyaltyPolicyLAP__InvalidAncestors();
    error RoyaltyPolicyLAP__InvalidRoyaltyAmountLength();
    error RoyaltyPolicyLAP__InvalidAncestorsHash();
    error RoyaltyPolicyLAP__InvalidParentRoyaltiesLength();
    error RoyaltyPolicyLAP__InvalidAncestorsRoyalty();
    error RoyaltyPolicyLAP__ImplementationAlreadySet();
    error RoyaltyPolicyLAP__ZeroAncestorsVaultImpl();
    error RoyaltyPolicyLAP__NotFullOwnership();
    error RoyaltyPolicyLAP__UnlinkableToParents();
    error RoyaltyPolicyLAP__TransferFailed();
    error RoyaltyPolicyLAP__LastPositionNotAbleToMintLicense();

    error AncestorsVaultLAP__ZeroRoyaltyPolicyLAP();
    error AncestorsVaultLAP__AlreadyClaimed();
    error AncestorsVaultLAP__InvalidAncestorsHash();
    error AncestorsVaultLAP__InvalidClaimer();
    error AncestorsVaultLAP__ClaimerNotAnAncestor();
    error AncestorsVaultLAP__ETHBalanceNotZero();
    error AncestorsVaultLAP__ERC20BalanceNotZero();
    error AncestorsVaultLAP__TransferFailed();

    ////////////////////////////////////////////////////////////////////////////
    //                             ModuleRegistry                             //
    ////////////////////////////////////////////////////////////////////////////

    error ModuleRegistry__ModuleAddressZeroAddress();
    error ModuleRegistry__ModuleAddressNotContract();
    error ModuleRegistry__ModuleAlreadyRegistered();
    error ModuleRegistry__NameEmptyString();
    error ModuleRegistry__NameAlreadyRegistered();
    error ModuleRegistry__NameDoesNotMatch();
    error ModuleRegistry__ModuleNotRegistered();
    error ModuleRegistry__InterfaceIdZero();
    error ModuleRegistry__ModuleTypeAlreadyRegistered();
    error ModuleRegistry__ModuleTypeNotRegistered();
    error ModuleRegistry__ModuleNotSupportExpectedModuleTypeInterfaceId();
    error ModuleRegistry__ModuleTypeEmptyString();

    ////////////////////////////////////////////////////////////////////////////
    //                               RegistrationModule                       //
    ////////////////////////////////////////////////////////////////////////////

    /// @notice The caller is not the owner of the root IP NFT.
    error RegistrationModule__InvalidOwner();

    ////////////////////////////////////////////////////////////////////////////
    //                             AccessController                           //
    ////////////////////////////////////////////////////////////////////////////

    error AccessController__IPAccountIsZeroAddress();
    error AccessController__IPAccountIsNotValid(address ipAccount);
    error AccessController__SignerIsZeroAddress();
    error AccessController__CallerIsNotIPAccount();
    error AccessController__PermissionIsNotValid();
    error AccessController__BothCallerAndRecipientAreNotRegisteredModule(address signer, address to);
    error AccessController__PermissionDenied(address ipAccount, address signer, address to, bytes4 func);

    ////////////////////////////////////////////////////////////////////////////
    //                             AccessControlled                           //
    ////////////////////////////////////////////////////////////////////////////
    error AccessControlled__ZeroAddress();
    error AccessControlled__NotIpAccount(address ipAccount);
    error AccessControlled__CallerIsNotIpAccount(address caller);
}

File 7 of 43 : IP.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

/// @title IP Library
/// @notice Library for constants, structs, and helper functions used for IP.
library IP {
    /// @notice Core metadata to associate with each IP.
    struct MetadataV1 {
        // The name associated with the IP.
        string name;
        // A keccak-256 hash of the IP content.
        bytes32 hash;
        // The date which the IP was registered.
        uint64 registrationDate;
        // The address of the initial IP registrant.
        address registrant;
        // An external URI associated with the IP.
        string uri;
    }
}

File 8 of 43 : BaseModule.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { IERC165, ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import { IModule } from "../interfaces/modules/base/IModule.sol";

/// @title BaseModule
/// @notice Base implementation for all modules in Story Protocol.
abstract contract BaseModule is ERC165, IModule {
    /// @notice IERC165 interface support.
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return interfaceId == type(IModule).interfaceId || super.supportsInterface(interfaceId);
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { Licensing } from "../../../lib/Licensing.sol";
import { IModule } from "../base/IModule.sol";
import { RoyaltyModule } from "../../../modules/royalty/RoyaltyModule.sol";
import { ILicenseRegistry } from "../../registries/ILicenseRegistry.sol";
import { IDisputeModule } from "../dispute/IDisputeModule.sol";

/// @title ILicensingModule
interface ILicensingModule is IModule {
    /// @notice Status of a policy on IP asset
    /// @param index The local index of the policy in the IP asset
    /// @param isSet True if the policy is set in the IP asset
    /// @param active True if the policy is active
    /// @param isInherited True if the policy is inherited from a parent IP asset
    struct PolicySetup {
        uint256 index;
        bool isSet;
        bool active;
        bool isInherited;
    }

    /// @notice Emitted when a policy framework is created by registering a policy framework manager
    /// @param framework The address of the IPolicyFrameworkManager
    /// @param framework The policy framework data
    event PolicyFrameworkRegistered(address indexed framework, string name, string licenseTextUrl);

    /// @notice Emitted when a policy is added to the contract
    /// @param policyId The id of the policy
    /// @param policyFrameworkManager The address of the policy framework manager
    /// @param frameworkData The policy framework specific encoded data
    /// @param royaltyPolicy The address of the royalty policy
    /// @param royaltyData The royalty policy specific encoded data
    /// @param mintingFee The fee to be paid when minting a license
    /// @param mintingFeeToken The token to be used to pay the minting fee
    event PolicyRegistered(
        uint256 indexed policyId,
        address indexed policyFrameworkManager,
        bytes frameworkData,
        address royaltyPolicy,
        bytes royaltyData,
        uint256 mintingFee,
        address mintingFeeToken
    );

    /// @notice Emitted when a policy is added to an IP
    /// @param caller The address that called the function
    /// @param ipId The id of the IP
    /// @param policyId The id of the policy
    /// @param index The index of the policy in the IP's policy set
    /// @param isInherited Whether the policy was inherited from a parent IP (linking) or set by IP owner
    event PolicyAddedToIpId(
        address indexed caller,
        address indexed ipId,
        uint256 indexed policyId,
        uint256 index,
        bool isInherited
    );

    /// @notice Emitted when an IP is linked to its parent by burning a license
    /// @param caller The address that called the function
    /// @param ipId The id of the IP
    /// @param parentIpIds The ids of the parent IPs
    event IpIdLinkedToParents(address indexed caller, address indexed ipId, address[] parentIpIds);

    /// @notice Returns the canonical protocol-wide RoyaltyModule
    function ROYALTY_MODULE() external view returns (RoyaltyModule);

    /// @notice Returns the canonical protocol-wide LicenseRegistry
    function LICENSE_REGISTRY() external view returns (ILicenseRegistry);

    /// @notice Returns the canonical protocol-wide DisputeModule
    function DISPUTE_MODULE() external view returns (IDisputeModule);

    /// @notice Registers a policy framework manager into the contract, so it can add policy data for licenses.
    /// @param manager the address of the manager. Will be ERC165 checked for IPolicyFrameworkManager
    function registerPolicyFrameworkManager(address manager) external;

    /// @notice Registers a policy into the contract. MUST be called by a registered
    /// framework or it will revert. The policy data and its integrity must be
    /// verified by the policy framework manager.
    /// @param pol The Licensing policy data. MUST have same policy framework as the caller address
    /// @return policyId The id of the newly registered policy
    function registerPolicy(Licensing.Policy memory pol) external returns (uint256 policyId);

    /// @notice Adds a policy to the set of policies of an IP
    /// @param ipId The id of the IP
    /// @param polId The id of the policy
    /// @return indexOnIpId The index of the policy in the IP's policy set
    function addPolicyToIp(address ipId, uint256 polId) external returns (uint256 indexOnIpId);

    /// @notice Mints a license to create derivative IP. License NFTs represent a policy granted by IPs (licensors).
    /// Reverts if caller is not authorized by any of the licensors.
    /// @dev This NFT needs to be burned in order to link a derivative IP with its parents. If this is the first
    /// combination of policy and licensors, a new licenseId will be created (by incrementing prev totalLicenses).
    /// If not, the license is fungible and an id will be reused. The licensing terms that regulate creating new
    /// licenses will be verified to allow minting.
    /// @param policyId The id of the policy with the licensing parameters
    /// @param licensorIpId The id of the licensor IP
    /// @param amount The amount of licenses to mint
    /// @param receiver The address that will receive the license
    /// @param royaltyContext The context for the royalty module to process
    /// @return licenseId The ID of the license NFT(s)
    function mintLicense(
        uint256 policyId,
        address licensorIpId,
        uint256 amount,
        address receiver,
        bytes calldata royaltyContext
    ) external returns (uint256 licenseId);

    /// @notice Links an IP to the licensors listed in the license NFTs, if their policies allow it. Burns the license
    /// NFTs in the proccess. The caller must be the owner of the IP asset and license NFTs.
    /// @param licenseIds The id of the licenses to burn
    /// @param childIpId The id of the child IP to be linked
    /// @param royaltyContext The context for the royalty module to process
    function linkIpToParents(uint256[] calldata licenseIds, address childIpId, bytes calldata royaltyContext) external;

    ///
    /// Getters
    ///

    /// @notice Returns if the framework address is registered in the LicensingModule.
    /// @param policyFramework The address of the policy framework manager
    /// @return isRegistered True if the framework is registered
    function isFrameworkRegistered(address policyFramework) external view returns (bool);

    /// @notice Returns amount of distinct licensing policies in the LicensingModule.
    /// @return totalPolicies The amount of policies
    function totalPolicies() external view returns (uint256);

    /// @notice Returns the policy data for policyId, reverts if not found.
    /// @param policyId The id of the policy
    /// @return pol The policy data
    function policy(uint256 policyId) external view returns (Licensing.Policy memory pol);

    /// @notice Returns the policy id for the given policy data, or 0 if not found.
    /// @param pol The policy data in Policy struct
    /// @return policyId The id of the policy
    function getPolicyId(Licensing.Policy calldata pol) external view returns (uint256 policyId);

    /// @notice Returns the policy aggregator data for the given IP ID in the framework.
    /// @param framework The address of the policy framework manager
    /// @param ipId The id of the IP asset
    /// @return data The encoded policy aggregator data to be decoded by the framework manager
    function policyAggregatorData(address framework, address ipId) external view returns (bytes memory);

    /// @notice Returns if policyId exists in the LicensingModule
    /// @param policyId The id of the policy
    /// @return isDefined True if the policy is defined
    function isPolicyDefined(uint256 policyId) external view returns (bool);

    /// @notice Returns the policy ids attached to an IP
    /// @dev Potentially gas-intensive operation, use with care.
    /// @param isInherited True if the policy is inherited from a parent IP
    /// @param ipId The id of the IP asset
    /// @return policyIds The ids of policy ids for the IP
    function policyIdsForIp(bool isInherited, address ipId) external view returns (uint256[] memory policyIds);

    /// @notice Returns the total number of policies attached to an IP
    /// @param isInherited True if the policy is inherited from a parent IP
    /// @param ipId The id of the IP asset
    /// @return totalPolicies The total number of policies for the IP
    function totalPoliciesForIp(bool isInherited, address ipId) external view returns (uint256);

    /// @notice Returns if a given policyId is attached to an IP
    /// @param isInherited True if the policy is inherited from a parent IP
    /// @param ipId The id of the IP asset
    /// @param policyId The id of the policy
    /// @return isSet True if the policy is set in the IP asset
    function isPolicyIdSetForIp(bool isInherited, address ipId, uint256 policyId) external view returns (bool);

    /// @notice Returns the policy ID for an IP by local index on the IP's policy set
    /// @param isInherited True if the policy is inherited from a parent IP
    /// @param ipId The id of the IP asset to check
    /// @param index The local index of a policy in the IP's policy set
    /// @return policyId The id of the policy
    function policyIdForIpAtIndex(
        bool isInherited,
        address ipId,
        uint256 index
    ) external view returns (uint256 policyId);

    /// @notice Returns the policy data for an IP by the policy's local index on the IP's policy set
    /// @param isInherited True if the policy is inherited from a parent IP
    /// @param ipId The id of the IP asset to check
    /// @param index The local index of a policy in the IP's policy set
    /// @return policy The policy data
    function policyForIpAtIndex(
        bool isInherited,
        address ipId,
        uint256 index
    ) external view returns (Licensing.Policy memory);

    /// @notice Returns the status of a policy in an IP's policy set
    /// @param ipId The id of the IP asset to check
    /// @param policyId The id of the policy
    /// @return index The local index of the policy in the IP's policy set
    /// @return isInherited True if the policy is inherited from a parent IP
    /// @return active True if the policy is active
    function policyStatus(
        address ipId,
        uint256 policyId
    ) external view returns (uint256 index, bool isInherited, bool active);

    /// @notice Returns if the given policy attached to the given IP is inherited from a parent IP.
    /// @param ipId The id of the IP asset that has the policy attached
    /// @param policyId The id of the policy to check if inherited
    /// @return isInherited True if the policy is inherited from a parent IP
    function isPolicyInherited(address ipId, uint256 policyId) external view returns (bool);

    /// @notice Returns if an IP is a derivative of another IP
    /// @param parentIpId The id of the parent IP asset to check
    /// @param childIpId The id of the child IP asset to check
    /// @return isParent True if the child IP is a derivative of the parent IP
    function isParent(address parentIpId, address childIpId) external view returns (bool);

    /// @notice Returns the list of parent IP assets for a given child IP asset
    /// @param ipId The id of the child IP asset to check
    /// @return parentIpIds The ids of the parent IP assets
    function parentIpIds(address ipId) external view returns (address[] memory);

    /// @notice Returns the total number of parents for an IP asset
    /// @param ipId The id of the IP asset to check
    /// @return totalParents The total number of parent IP assets
    function totalParentsForIpId(address ipId) external view returns (uint256);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { IIPAccountRegistry } from "./IIPAccountRegistry.sol";
import { IModuleRegistry } from "./IModuleRegistry.sol";
import { IMetadataProviderMigratable } from "./metadata/IMetadataProviderMigratable.sol";
import { IRegistrationModule } from "../modules/IRegistrationModule.sol";

/// @title Interface for IP Account Registry
/// @notice This interface manages the registration and tracking of IP Accounts
interface IIPAssetRegistry is IIPAccountRegistry {
    // TODO: Deprecate `resolver` in favor of consolidation through the provider.
    /// @notice Attributes for the IP asset type.
    /// @param metadataProvider Metadata provider for Story Protocol canonicalized metadata.
    /// @param resolver Metadata resolver for custom metadata added by the IP owner.
    struct Record {
        IMetadataProviderMigratable metadataProvider;
        address resolver;
    }

    // TODO: Add support for optional licenseIds.
    /// @notice Emits when an IP is officially registered into the protocol.
    /// @param ipId The canonical identifier for the IP.
    /// @param chainId The chain identifier of where the IP resides.
    /// @param tokenContract The address of the IP.
    /// @param tokenId The token identifier of the IP.
    /// @param resolver The address of the resolver linked to the IP.
    /// @param provider The address of the metadata provider linked to the IP.
    /// @param metadata Canonical metadata that was linked to the IP.
    event IPRegistered(
        address ipId,
        uint256 indexed chainId,
        address indexed tokenContract,
        uint256 indexed tokenId,
        address resolver,
        address provider,
        bytes metadata
    );

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

    /// @notice Emits when an operator is approved for IP registration for an NFT owner.
    /// @param owner The address of the IP owner.
    /// @param operator The address of the operator the owneris authorizing.
    /// @param approved Whether or not to approve that operator for registration.
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /// @notice Emits when metadata is set for an IP asset.
    /// @param ipId The canonical identifier of the specified IP.
    /// @param metadataProvider Address of the metadata provider associated with the IP.
    /// @param metadata The canonical metadata in bytes associated with the IP.
    event MetadataSet(address indexed ipId, address indexed metadataProvider, bytes metadata);

    /// @notice The canonical module registry used by the protocol.
    function MODULE_REGISTRY() external view returns (IModuleRegistry);

    /// @notice The registration module that interacts with IPAssetRegistry.
    function REGISTRATION_MODULE() external view returns (IRegistrationModule);

    /// @notice Tracks the total number of IP assets in existence.
    function totalSupply() external view returns (uint256);

    /// @notice Checks whether an operator is approved to register on behalf of an IP owner.
    /// @param owner The address of the IP owner whose approval is being checked for.
    /// @param operator The address of the operator the owner has approved for registration delgation.
    /// @return Whether the operator is approved on behalf of the owner for registering.
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    /// @notice Enables third party operators to register on behalf of an NFT owner.
    /// @param operator The address of the operator the sender authorizes.
    /// @param approved Whether or not to approve that operator for registration.
    function setApprovalForAll(address operator, bool approved) external;

    /// @notice Registers an NFT as IP, creating a corresponding IP record.
    /// @param chainId The chain identifier of where the NFT resides.
    /// @param tokenContract The address of the NFT.
    /// @param tokenId The token identifier of the NFT.
    /// @param resolverAddr The address of the resolver to associate with the IP.
    /// @param createAccount Whether to create an IP account when registering.
    /// @param metadata_ Metadata in bytes to associate with the IP.
    /// @return ipId_ The address of the newly registered IP.
    function register(
        uint256 chainId,
        address tokenContract,
        uint256 tokenId,
        address resolverAddr,
        bool createAccount,
        bytes calldata metadata_
    ) external returns (address);

    /// @notice Registers an NFT as an IP using licenses derived from parent IP asset(s).
    /// @param licenseIds The parent IP asset licenses used to derive the new IP asset.
    /// @param royaltyContext The context for the royalty module to process.
    /// @param chainId The chain identifier of where the NFT resides.
    /// @param tokenContract The address of the NFT.
    /// @param tokenId The token identifier of the NFT.
    /// @param resolverAddr The address of the resolver to associate with the IP.
    /// @param createAccount Whether to create an IP account when registering.
    /// @param metadata_ Metadata in bytes to associate with the IP.
    /// @return ipId_ The address of the newly registered IP.
    function register(
        uint256[] calldata licenseIds,
        bytes calldata royaltyContext,
        uint256 chainId,
        address tokenContract,
        uint256 tokenId,
        address resolverAddr,
        bool createAccount,
        bytes calldata metadata_
    ) external returns (address);

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

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

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

    /// @notice Gets the metadata provider used for new metadata registrations.
    /// @return metadataProvider The address of the metadata provider used for new IP registrations.
    function metadataProvider() external view returns (address);

    /// @notice Gets the metadata provider linked to an IP based on its ID.
    /// @param id The canonical identifier for the IP.
    /// @return metadataProvider The metadata provider that was bound to this IP at creation time.
    function metadataProvider(address id) external view returns (address);

    /// @notice Gets the underlying canonical metadata linked to an IP asset.
    /// @param id The canonical ID of the IP asset.
    /// @return metadata The metadata that was bound to this IP at creation time.
    function metadata(address id) external view returns (bytes memory);

    /// @notice Sets the underlying metadata for an IP asset.
    /// @dev As metadata is immutable but additive, this will only be used when an IP migrates from a new provider that
    /// introduces new attributes.
    /// @param id The canonical ID of the IP.
    /// @param data Canonical metadata to associate with the IP.
    function setMetadata(address id, address metadataProvider, bytes calldata data) external;

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 12 of 43 : ResolverBase.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { BaseModule } from "../modules/BaseModule.sol";
import { IResolver } from "../interfaces/resolvers/IResolver.sol";
import { AccessControlled } from "../access/AccessControlled.sol";

/// @notice IP Resolver Base Contract
abstract contract ResolverBase is IResolver, BaseModule, AccessControlled {
    constructor(address accessController, address assetRegistry) AccessControlled(accessController, assetRegistry) {}

    /// @notice IERC165 interface support.
    function supportsInterface(bytes4 id) public view virtual override(BaseModule, IResolver) returns (bool) {
        return id == type(IResolver).interfaceId || super.supportsInterface(id);
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { IKeyValueResolver } from "../interfaces/resolvers/IKeyValueResolver.sol";
import { ResolverBase } from "../resolvers/ResolverBase.sol";

/// @title Key Value Resolver
/// @notice Resolver used for returning values associated with keys. This is the
///         preferred approach for adding additional attribution to IP that the
///         IP originator thinks is beneficial to have on chain.
abstract contract KeyValueResolver is IKeyValueResolver, ResolverBase {
    /// @dev Stores key-value pairs associated with each IP.
    mapping(address => mapping(string => string)) internal _values;

    /// @notice Sets the string value for a specified key of an IP ID.
    /// @dev Enforced to be only callable by users with valid permission to call on behalf of the ipId.
    /// @param ipId The canonical identifier of the IP asset.
    /// @param key The string parameter key to update.
    /// @param val The value to set for the specified key.
    function setValue(address ipId, string calldata key, string calldata val) external virtual verifyPermission(ipId) {
        _values[ipId][key] = val;
        emit KeyValueSet(ipId, key, val);
    }

    /// @notice Retrieves the string value associated with a key for an IP asset.
    /// @param key The string parameter key to query.
    /// @return value The value associated with the specified key.
    function value(address ipId, string calldata key) external view virtual returns (string memory) {
        return _values[ipId][key];
    }

    /// @notice IERC165 interface support.
    function supportsInterface(bytes4 id) public view virtual override returns (bool) {
        return id == type(IKeyValueResolver).interfaceId || super.supportsInterface(id);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

/// @notice Module Interface
interface IModule is IERC165 {
    /// @notice Returns the string identifier associated with the module.
    function name() external returns (string memory);
}

File 16 of 43 : Licensing.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

/// @title Licensing
/// @notice Types and constants used by the licensing related contracts
library Licensing {
    /// @notice A particular configuration (flavor) of a Policy Framework, setting values for the licensing
    /// terms (parameters) of the framework.
    /// @param isLicenseTransferable Whether or not the license is transferable
    /// @param policyFramework address of the IPolicyFrameworkManager this policy is based on
    /// @param frameworkData Data to be used by the policy framework to verify minting and linking
    /// @param royaltyPolicy address of the royalty policy to be used by the policy framework, if any
    /// @param royaltyData Data to be used by the royalty policy (for example, encoding of the royalty percentage)
    /// @param mintingFee Fee to be paid when minting a license
    /// @param mintingFeeToken Token to be used to pay the minting fee
    struct Policy {
        bool isLicenseTransferable;
        address policyFramework;
        bytes frameworkData;
        address royaltyPolicy;
        bytes royaltyData;
        uint256 mintingFee;
        address mintingFeeToken;
    }

    /// @notice Data that define a License Agreement NFT
    /// @param policyId Id of the policy this license is based on, which will be set in the derivative IP when the
    /// license is burnt for linking
    /// @param licensorIpId Id of the IP this license is for
    /// @param transferable Whether or not the license is transferable
    struct License {
        uint256 policyId;
        address licensorIpId;
        bool transferable;
        // TODO: support for transfer hooks
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

import { BaseModule } from "../BaseModule.sol";
import { Governable } from "../../governance/Governable.sol";
import { IRoyaltyModule } from "../../interfaces/modules/royalty/IRoyaltyModule.sol";
import { IRoyaltyPolicy } from "../../interfaces/modules/royalty/policies/IRoyaltyPolicy.sol";
import { Errors } from "../../lib/Errors.sol";
import { ROYALTY_MODULE_KEY } from "../../lib/modules/Module.sol";
import { BaseModule } from "../BaseModule.sol";

/// @title Story Protocol Royalty Module
/// @notice The Story Protocol royalty module allows to set royalty policies an IP asset and pay royalties as a
///         derivative IP.
contract RoyaltyModule is IRoyaltyModule, Governable, ReentrancyGuard, BaseModule {
    using ERC165Checker for address;

    string public constant override name = ROYALTY_MODULE_KEY;

    /// @notice Returns the licensing module address
    address public LICENSING_MODULE;

    /// @notice Indicates if a royalty policy is whitelisted
    mapping(address royaltyPolicy => bool isWhitelisted) public isWhitelistedRoyaltyPolicy;

    /// @notice Indicates if a royalty token is whitelisted
    mapping(address token => bool) public isWhitelistedRoyaltyToken;

    /// @notice Indicates the royalty policy for a given IP asset
    mapping(address ipId => address royaltyPolicy) public royaltyPolicies;

    constructor(address governance) Governable(governance) {}

    /// @notice Modifier to enforce that the caller is the licensing module
    modifier onlyLicensingModule() {
        if (msg.sender != LICENSING_MODULE) revert Errors.RoyaltyModule__NotAllowedCaller();
        _;
    }

    /// @notice Sets the license registry
    /// @dev Enforced to be only callable by the protocol admin
    /// @param licensingModule The address of the license registry
    function setLicensingModule(address licensingModule) external onlyProtocolAdmin {
        if (licensingModule == address(0)) revert Errors.RoyaltyModule__ZeroLicensingModule();
        LICENSING_MODULE = licensingModule;
    }

    /// @notice Whitelist a royalty policy
    /// @dev Enforced to be only callable by the protocol admin
    /// @param royaltyPolicy The address of the royalty policy
    /// @param allowed Indicates if the royalty policy is whitelisted or not
    function whitelistRoyaltyPolicy(address royaltyPolicy, bool allowed) external onlyProtocolAdmin {
        if (royaltyPolicy == address(0)) revert Errors.RoyaltyModule__ZeroRoyaltyPolicy();

        isWhitelistedRoyaltyPolicy[royaltyPolicy] = allowed;

        emit RoyaltyPolicyWhitelistUpdated(royaltyPolicy, allowed);
    }

    /// @notice Whitelist a royalty token
    /// @dev Enforced to be only callable by the protocol admin
    /// @param token The token address
    /// @param allowed Indicates if the token is whitelisted or not
    function whitelistRoyaltyToken(address token, bool allowed) external onlyProtocolAdmin {
        if (token == address(0)) revert Errors.RoyaltyModule__ZeroRoyaltyToken();

        isWhitelistedRoyaltyToken[token] = allowed;

        emit RoyaltyTokenWhitelistUpdated(token, allowed);
    }

    /// @notice Executes royalty related logic on license minting
    /// @dev Enforced to be only callable by LicensingModule
    /// @param ipId The ipId whose license is being minted (licensor)
    /// @param royaltyPolicy The royalty policy address of the license being minted
    /// @param licenseData The license data custom to each the royalty policy
    /// @param externalData The external data custom to each the royalty policy
    function onLicenseMinting(
        address ipId,
        address royaltyPolicy,
        bytes calldata licenseData,
        bytes calldata externalData
    ) external nonReentrant onlyLicensingModule {
        if (!isWhitelistedRoyaltyPolicy[royaltyPolicy]) revert Errors.RoyaltyModule__NotWhitelistedRoyaltyPolicy();

        address royaltyPolicyIpId = royaltyPolicies[ipId];

        // if the node is a root node, then royaltyPolicyIpId will be address(0) and any type of royalty type can be
        // selected to mint a license if the node is a derivative node, then the any minted licenses by the derivative
        // node should have the same royalty policy as the parent node a derivative node set its royalty policy
        // immutably in onLinkToParents() function below
        if (royaltyPolicyIpId != royaltyPolicy && royaltyPolicyIpId != address(0))
            revert Errors.RoyaltyModule__CanOnlyMintSelectedPolicy();

        IRoyaltyPolicy(royaltyPolicy).onLicenseMinting(ipId, licenseData, externalData);
    }

    /// @notice Executes royalty related logic on linking to parents
    /// @dev Enforced to be only callable by LicensingModule
    /// @param ipId The children ipId that is being linked to parents
    /// @param royaltyPolicy The common royalty policy address of all the licenses being burned
    /// @param parentIpIds The parent ipIds that the children ipId is being linked to
    /// @param licenseData The license data custom to each the royalty policy
    /// @param externalData The external data custom to each the royalty policy
    function onLinkToParents(
        address ipId,
        address royaltyPolicy,
        address[] calldata parentIpIds,
        bytes[] memory licenseData,
        bytes calldata externalData
    ) external nonReentrant onlyLicensingModule {
        if (!isWhitelistedRoyaltyPolicy[royaltyPolicy]) revert Errors.RoyaltyModule__NotWhitelistedRoyaltyPolicy();
        if (parentIpIds.length == 0) revert Errors.RoyaltyModule__NoParentsOnLinking();

        for (uint32 i = 0; i < parentIpIds.length; i++) {
            address parentRoyaltyPolicy = royaltyPolicies[parentIpIds[i]];
            // if the parent node has a royalty policy set, then the derivative node should have the same royalty
            // policy if the parent node does not have a royalty policy set, then the derivative node can set any type
            // of royalty policy as long as the children ip obtained and is burning all licenses with that royalty type
            // from each parent (was checked in licensing module before calling this function)
            if (parentRoyaltyPolicy != royaltyPolicy && parentRoyaltyPolicy != address(0))
                revert Errors.RoyaltyModule__IncompatibleRoyaltyPolicy();
        }

        royaltyPolicies[ipId] = royaltyPolicy;

        IRoyaltyPolicy(royaltyPolicy).onLinkToParents(ipId, parentIpIds, licenseData, externalData);
    }

    /// @notice Allows the function caller to pay royalties to the receiver IP asset on behalf of the payer IP asset.
    /// @param receiverIpId The ipId that receives the royalties
    /// @param payerIpId The ipId that pays the royalties
    /// @param token The token to use to pay the royalties
    /// @param amount The amount to pay
    function payRoyaltyOnBehalf(
        address receiverIpId,
        address payerIpId,
        address token,
        uint256 amount
    ) external nonReentrant {
        if (!isWhitelistedRoyaltyToken[token]) revert Errors.RoyaltyModule__NotWhitelistedRoyaltyToken();

        address payerRoyaltyPolicy = royaltyPolicies[payerIpId];
        // if the payer does not have a royalty policy set, then the payer is not a derivative ip and does not pay
        // royalties the receiver ip can have a zero royalty policy since that could mean it is an ip a root
        if (payerRoyaltyPolicy == address(0)) revert Errors.RoyaltyModule__NoRoyaltyPolicySet();
        if (!isWhitelistedRoyaltyPolicy[payerRoyaltyPolicy]) revert Errors.RoyaltyModule__NotWhitelistedRoyaltyPolicy();

        IRoyaltyPolicy(payerRoyaltyPolicy).onRoyaltyPayment(msg.sender, receiverIpId, token, amount);

        emit RoyaltyPaid(receiverIpId, payerIpId, msg.sender, token, amount);
    }

    /// @notice Allows to pay the minting fee for a license
    /// @param receiverIpId The ipId that receives the royalties
    /// @param payerAddress The address that pays the royalties
    /// @param licenseRoyaltyPolicy The royalty policy of the license being minted
    /// @param token The token to use to pay the royalties
    /// @param amount The amount to pay
    function payLicenseMintingFee(
        address receiverIpId,
        address payerAddress,
        address licenseRoyaltyPolicy,
        address token,
        uint256 amount
    ) external onlyLicensingModule {
        if (!isWhitelistedRoyaltyToken[token]) revert Errors.RoyaltyModule__NotWhitelistedRoyaltyToken();

        if (licenseRoyaltyPolicy == address(0)) revert Errors.RoyaltyModule__NoRoyaltyPolicySet();
        if (!isWhitelistedRoyaltyPolicy[licenseRoyaltyPolicy])
            revert Errors.RoyaltyModule__NotWhitelistedRoyaltyPolicy();

        IRoyaltyPolicy(licenseRoyaltyPolicy).onRoyaltyPayment(payerAddress, receiverIpId, token, amount);

        emit LicenseMintingFeePaid(receiverIpId, payerAddress, token, amount);
    }

    /// @notice IERC165 interface support.
    function supportsInterface(bytes4 interfaceId) public view virtual override(BaseModule, IERC165) returns (bool) {
        return interfaceId == type(IRoyaltyModule).interfaceId || super.supportsInterface(interfaceId);
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { IERC1155 } from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";

import { Licensing } from "../../lib/Licensing.sol";
import { IDisputeModule } from "../modules/dispute/IDisputeModule.sol";
import { ILicensingModule } from "../modules/licensing/ILicensingModule.sol";

/// @title ILicenseRegistry
interface ILicenseRegistry is IERC1155 {
    /// @notice Emitted when a license is minted
    /// @param creator The address that created the license
    /// @param receiver The address that received the license
    /// @param licenseId The ID of the license
    /// @param amount The amount of licenses minted
    /// @param licenseData The license data
    event LicenseMinted(
        address indexed creator,
        address indexed receiver,
        uint256 indexed licenseId,
        uint256 amount,
        Licensing.License licenseData
    );

    /// @notice Returns the canonical protocol-wide LicensingModule
    function LICENSING_MODULE() external view returns (ILicensingModule);

    /// @notice Returns the canonical protocol-wide DisputeModule
    function DISPUTE_MODULE() external view returns (IDisputeModule);

    /// @notice Mints license NFTs representing a policy granted by a set of ipIds (licensors). This NFT needs to be
    /// burned in order to link a derivative IP with its parents. If this is the first combination of policy and
    /// licensors, a new licenseId will be created. If not, the license is fungible and an id will be reused.
    /// @dev Only callable by the licensing module.
    /// @param policyId The ID of the policy to be minted
    /// @param licensorIpId_ The ID of the IP granting the license (ie. licensor)
    /// @param transferable True if the license is transferable
    /// @param amount Number of licenses to mint. License NFT is fungible for same policy and same licensors
    /// @param receiver Receiver address of the minted license NFT(s).
    /// @return licenseId The ID of the minted license NFT(s).
    function mintLicense(
        uint256 policyId,
        address licensorIpId_,
        bool transferable,
        uint256 amount,
        address receiver
    ) external returns (uint256 licenseId);

    /// @notice Burns licenses
    /// @param holder The address that holds the licenses
    /// @param licenseIds The ids of the licenses to burn
    function burnLicenses(address holder, uint256[] calldata licenseIds) external;

    ///
    /// Getters
    ///

    /// @notice Returns the number of licenses registered in the protocol.
    /// @dev Token ID counter total count.
    /// @return mintedLicenses The number of minted licenses
    function mintedLicenses() external view returns (uint256);

    /// @notice Returns true if holder has positive balance for the given license ID.
    /// @return isLicensee True if holder is the licensee for the license (owner of the license NFT), or derivative IP
    /// owner if the license was added to the IP by linking (burning a license).
    function isLicensee(uint256 licenseId, address holder) external view returns (bool);

    /// @notice Returns the license data for the given license ID
    /// @param licenseId The ID of the license
    /// @return licenseData The license data
    function license(uint256 licenseId) external view returns (Licensing.License memory);

    /// @notice Returns the ID of the IP asset that is the licensor of the given license ID
    /// @param licenseId The ID of the license
    /// @return licensorIpId The ID of the licensor
    function licensorIpId(uint256 licenseId) external view returns (address);

    /// @notice Returns the policy ID for the given license ID
    /// @param licenseId The ID of the license
    /// @return policyId The ID of the policy
    function policyIdForLicense(uint256 licenseId) external view returns (uint256);

    /// @notice Returns true if the license has been revoked (licensor tagged after a dispute in
    /// the dispute module). If the tag is removed, the license is not revoked anymore.
    /// @param licenseId The id of the license to check
    /// @return isRevoked True if the license is revoked
    function isLicenseRevoked(uint256 licenseId) external view returns (bool);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

/// @title Dispute Module Interface
interface IDisputeModule {
    /// @notice Dispute struct
    /// @param targetIpId The ipId that is the target of the dispute
    /// @param disputeInitiator The address of the dispute initiator
    /// @param arbitrationPolicy The address of the arbitration policy
    /// @param linkToDisputeEvidence The link of the dispute evidence
    /// @param targetTag The target tag of the dispute
    /// @param currentTag The current tag of the dispute
    struct Dispute {
        address targetIpId;
        address disputeInitiator;
        address arbitrationPolicy;
        bytes32 linkToDisputeEvidence;
        bytes32 targetTag;
        bytes32 currentTag;
    }

    /// @notice Event emitted when a dispute tag whitelist status is updated
    /// @param tag The dispute tag
    /// @param allowed Indicates if the dispute tag is whitelisted
    event TagWhitelistUpdated(bytes32 tag, bool allowed);

    /// @notice Event emitted when an arbitration policy whitelist status is updated
    /// @param arbitrationPolicy The address of the arbitration policy
    /// @param allowed Indicates if the arbitration policy is whitelisted
    event ArbitrationPolicyWhitelistUpdated(address arbitrationPolicy, bool allowed);

    /// @notice Event emitted when an arbitration relayer whitelist status is updated
    /// @param arbitrationPolicy The address of the arbitration policy
    /// @param arbitrationRelayer The address of the arbitration relayer
    /// @param allowed Indicates if the arbitration relayer is whitelisted
    event ArbitrationRelayerWhitelistUpdated(address arbitrationPolicy, address arbitrationRelayer, bool allowed);

    /// @notice Event emitted when the base arbitration policy is set
    /// @param arbitrationPolicy The address of the arbitration policy
    event DefaultArbitrationPolicyUpdated(address arbitrationPolicy);

    /// @notice Event emitted when an arbitration policy is set for an ipId
    /// @param ipId The ipId address
    /// @param arbitrationPolicy The address of the arbitration policy
    event ArbitrationPolicySet(address ipId, address arbitrationPolicy);

    /// @notice Event emitted when a dispute is raised
    /// @param disputeId The dispute id
    /// @param targetIpId The ipId that is the target of the dispute
    /// @param disputeInitiator The address of the dispute initiator
    /// @param arbitrationPolicy The address of the arbitration policy
    /// @param linkToDisputeEvidence The link of the dispute evidence
    /// @param targetTag The target tag of the dispute
    /// @param data Custom data adjusted to each policy
    event DisputeRaised(
        uint256 disputeId,
        address targetIpId,
        address disputeInitiator,
        address arbitrationPolicy,
        bytes32 linkToDisputeEvidence,
        bytes32 targetTag,
        bytes data
    );

    /// @notice Event emitted when a dispute judgement is set
    /// @param disputeId The dispute id
    /// @param decision The decision of the dispute
    /// @param data Custom data adjusted to each policy
    event DisputeJudgementSet(uint256 disputeId, bool decision, bytes data);

    /// @notice Event emitted when a dispute is cancelled
    /// @param disputeId The dispute id
    /// @param data Custom data adjusted to each policy
    event DisputeCancelled(uint256 disputeId, bytes data);

    /// @notice Event emitted when a dispute is resolved
    /// @param disputeId The dispute id
    event DisputeResolved(uint256 disputeId);

    /// @notice Tag to represent the dispute is in dispute state waiting for judgement
    function IN_DISPUTE() external view returns (bytes32);

    /// @notice Dispute ID counter
    function disputeCounter() external view returns (uint256);

    /// @notice The address of the base arbitration policy
    function baseArbitrationPolicy() external view returns (address);

    /// @notice Returns the dispute information for a given dispute id
    /// @param disputeId The dispute id
    /// @return targetIpId The ipId that is the target of the dispute
    /// @return disputeInitiator The address of the dispute initiator
    /// @return arbitrationPolicy The address of the arbitration policy
    /// @return linkToDisputeEvidence The link of the dispute summary
    /// @return targetTag The target tag of the dispute
    /// @return currentTag The current tag of the dispute
    function disputes(
        uint256 disputeId
    )
        external
        view
        returns (
            address targetIpId,
            address disputeInitiator,
            address arbitrationPolicy,
            bytes32 linkToDisputeEvidence,
            bytes32 targetTag,
            bytes32 currentTag
        );

    /// @notice Indicates if a dispute tag is whitelisted
    /// @param tag The dispute tag
    /// @return allowed Indicates if the dispute tag is whitelisted
    function isWhitelistedDisputeTag(bytes32 tag) external view returns (bool allowed);

    /// @notice Indicates if an arbitration policy is whitelisted
    /// @param arbitrationPolicy The address of the arbitration policy
    /// @return allowed Indicates if the arbitration policy is whitelisted
    function isWhitelistedArbitrationPolicy(address arbitrationPolicy) external view returns (bool allowed);

    /// @notice Indicates if an arbitration relayer is whitelisted for a given arbitration policy
    /// @param arbitrationPolicy The address of the arbitration policy
    /// @param arbitrationRelayer The address of the arbitration relayer
    /// @return allowed Indicates if the arbitration relayer is whitelisted
    function isWhitelistedArbitrationRelayer(
        address arbitrationPolicy,
        address arbitrationRelayer
    ) external view returns (bool allowed);

    /// @notice Arbitration policy for a given ipId
    /// @param ipId The ipId
    /// @return policy The address of the arbitration policy
    function arbitrationPolicies(address ipId) external view returns (address policy);

    /// @notice Whitelists a dispute tag
    /// @param tag The dispute tag
    /// @param allowed Indicates if the dispute tag is whitelisted or not
    function whitelistDisputeTag(bytes32 tag, bool allowed) external;

    /// @notice Whitelists an arbitration policy
    /// @param arbitrationPolicy The address of the arbitration policy
    /// @param allowed Indicates if the arbitration policy is whitelisted or not
    function whitelistArbitrationPolicy(address arbitrationPolicy, bool allowed) external;

    /// @notice Whitelists an arbitration relayer for a given arbitration policy
    /// @param arbitrationPolicy The address of the arbitration policy
    /// @param arbPolicyRelayer The address of the arbitration relayer
    /// @param allowed Indicates if the arbitration relayer is whitelisted or not
    function whitelistArbitrationRelayer(address arbitrationPolicy, address arbPolicyRelayer, bool allowed) external;

    /// @notice Sets the base arbitration policy
    /// @param arbitrationPolicy The address of the arbitration policy
    function setBaseArbitrationPolicy(address arbitrationPolicy) external;

    /// @notice Sets the arbitration policy for an ipId
    /// @param ipId The ipId
    /// @param arbitrationPolicy The address of the arbitration policy
    function setArbitrationPolicy(address ipId, address arbitrationPolicy) external;

    /// @notice Raises a dispute on a given ipId
    /// @param targetIpId The ipId that is the target of the dispute
    /// @param linkToDisputeEvidence The link of the dispute evidence
    /// @param targetTag The target tag of the dispute
    /// @param data The data to initialize the policy
    /// @return disputeId The id of the newly raised dispute
    function raiseDispute(
        address targetIpId,
        string memory linkToDisputeEvidence,
        bytes32 targetTag,
        bytes calldata data
    ) external returns (uint256 disputeId);

    /// @notice Sets the dispute judgement on a given dispute. Only whitelisted arbitration relayers can call to judge.
    /// @param disputeId The dispute id
    /// @param decision The decision of the dispute
    /// @param data The data to set the dispute judgement
    function setDisputeJudgement(uint256 disputeId, bool decision, bytes calldata data) external;

    /// @notice Cancels an ongoing dispute
    /// @param disputeId The dispute id
    /// @param data The data to cancel the dispute
    function cancelDispute(uint256 disputeId, bytes calldata data) external;

    /// @notice Resolves a dispute after it has been judged
    /// @param disputeId The dispute id
    function resolveDispute(uint256 disputeId) external;

    /// @notice Returns true if the ipId is tagged with any tag (meaning at least one dispute went through)
    /// @param ipId The ipId
    /// @return isTagged True if the ipId is tagged
    function isIpTagged(address ipId) external view returns (bool);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

/// @title Interface for IP Account Registry
/// @notice This interface manages the registration and tracking of IP Accounts
interface IIPAccountRegistry {
    /// @notice Event emitted when a new IP Account is created
    /// @param account The address of the new IP Account
    /// @param implementation The address of the IP Account implementation
    /// @param chainId The chain ID where the token contract was deployed
    /// @param tokenContract The address of the token contract associated with the IP Account
    /// @param tokenId The ID of the token associated with the IP Account
    event IPAccountRegistered(
        address indexed account,
        address indexed implementation,
        uint256 indexed chainId,
        address tokenContract,
        uint256 tokenId
    );

    /// @notice Returns the IPAccount implementation address
    function IP_ACCOUNT_IMPL() external view returns (address);

    /// @notice Returns the IPAccount salt
    function IP_ACCOUNT_SALT() external view returns (bytes32);

    /// @notice Returns the public ERC6551 registry address
    function ERC6551_PUBLIC_REGISTRY() external view returns (address);

    /// @notice Deploys an IPAccount contract with the IPAccount implementation and returns the address of the new IP
    /// @dev The IPAccount deployment deltegates to public ERC6551 Registry
    /// @param chainId The chain ID where the IP Account will be created
    /// @param tokenContract The address of the token contract to be associated with the IP Account
    /// @param tokenId The ID of the token to be associated with the IP Account
    /// @return ipAccountAddress The address of the newly created IP Account
    function registerIpAccount(uint256 chainId, address tokenContract, uint256 tokenId) external returns (address);

    /// @notice Returns the IPAccount address for the given NFT token.
    /// @param chainId The chain ID where the IP Account is located
    /// @param tokenContract The address of the token contract associated with the IP Account
    /// @param tokenId The ID of the token associated with the IP Account
    /// @return ipAccountAddress The address of the IP Account associated with the given NFT token
    function ipAccount(uint256 chainId, address tokenContract, uint256 tokenId) external view returns (address);

    /// @notice Returns the IPAccount implementation address.
    /// @return The address of the IPAccount implementation
    function getIPAccountImpl() external view returns (address);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

/// @title IModuleRegistry
/// @dev This interface defines the methods for a module registry in the Story Protocol.
interface IModuleRegistry {
    /// @notice Emitted when a new module is added to the registry.
    /// @param name The name of the module.
    /// @param module The address of the module.
    event ModuleAdded(string name, address indexed module, bytes4 indexed moduleTypeInterfaceId, string moduleType);

    /// @notice Emitted when a module is removed from the registry.
    /// @param name The name of the module.
    /// @param module The address of the module.
    event ModuleRemoved(string name, address indexed module);

    /// @notice Returns the address of a registered module by its name.
    /// @param name The name of the module.
    /// @return moduleAddress The address of the module.
    function getModule(string memory name) external view returns (address);

    /// @notice Returns the module type of a registered module by its address.
    /// @param moduleAddress The address of the module.
    /// @return moduleType The type of the module as a string.
    function getModuleType(address moduleAddress) external view returns (string memory);

    /// @notice Returns the interface ID of a registered module type.
    /// @param moduleType The name of the module type.
    /// @return moduleTypeInterfaceId The interface ID of the module type as bytes4.
    function getModuleTypeInterfaceId(string memory moduleType) external view returns (bytes4);

    /// @notice Registers a new module type in the registry associate with an interface.
    /// @dev Enforced to be only callable by the protocol admin in governance.
    /// @param name The name of the module type to be registered.
    /// @param interfaceId The interface ID associated with the module type.
    function registerModuleType(string memory name, bytes4 interfaceId) external;

    /// @notice Removes a module type from the registry.
    /// @dev Enforced to be only callable by the protocol admin in governance.
    /// @param name The name of the module type to be removed.
    function removeModuleType(string memory name) external;

    /// @notice Registers a new module in the registry.
    /// @dev Enforced to be only callable by the protocol admin in governance.
    /// @param name The name of the module.
    /// @param moduleAddress The address of the module.
    function registerModule(string memory name, address moduleAddress) external;

    /// @notice Registers a new module in the registry with an associated module type.
    /// @param name The name of the module to be registered.
    /// @param moduleAddress The address of the module.
    /// @param moduleType The type of the module being registered.
    function registerModule(string memory name, address moduleAddress, string memory moduleType) external;

    /// @notice Removes a module from the registry.
    /// @dev Enforced to be only callable by the protocol admin in governance.
    /// @param name The name of the module.
    function removeModule(string memory name) external;

    /// @notice Checks if a module is registered in the protocol.
    /// @param moduleAddress The address of the module.
    /// @return isRegistered True if the module is registered, false otherwise.
    function isRegistered(address moduleAddress) external view returns (bool);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { IMetadataProvider } from "./IMetadataProvider.sol";
import { IIPAssetRegistry } from "../IIPAssetRegistry.sol";

/// @title Metadata Provider Interface
interface IMetadataProviderMigratable is IMetadataProvider {
    /// @notice Returns the protocol-wide IP asset registry.
    function IP_ASSET_REGISTRY() external view returns (IIPAssetRegistry);

    /// @notice Returns the new metadata provider IP assets may migrate to.
    function upgradeProvider() external returns (IMetadataProvider);

    /// @notice Sets a upgrade provider for users to migrate their metadata to.
    /// @param provider The address of the new metadata provider to migrate to.
    function setUpgradeProvider(address provider) external;

    /// @notice Updates the provider used by the IP asset, migrating existing metadata to the new provider, and adding
    /// new metadata.
    /// @param ipId The address identifier of the IP asset.
    /// @param extraMetadata Additional metadata in bytes used by the new metadata provider.
    function upgrade(address payable ipId, bytes memory extraMetadata) external;
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

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

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { IAccessController } from "../interfaces/IAccessController.sol";
import { IPAccountChecker } from "../lib/registries/IPAccountChecker.sol";
import { IIPAccountRegistry } from "../interfaces/registries/IIPAccountRegistry.sol";
import { Errors } from "../lib/Errors.sol";

/// @title AccessControlled
/// @notice Provides a base contract for access control functionalities.
/// @dev This abstract contract implements basic access control mechanisms with an emphasis
/// on IP account verification and permission checks.
/// It is designed to be used as a base contract for other contracts that require access control.
/// It provides modifiers and functions to verify if the caller has the necessary permission
/// and is a registered IP account.
abstract contract AccessControlled {
    using IPAccountChecker for IIPAccountRegistry;

    /// @notice The IAccessController instance for permission checks.
    IAccessController public immutable ACCESS_CONTROLLER;
    /// @notice The IIPAccountRegistry instance for IP account verification.
    IIPAccountRegistry public immutable IP_ACCOUNT_REGISTRY;

    /// @dev Initializes the contract by setting the ACCESS_CONTROLLER and IP_ACCOUNT_REGISTRY addresses.
    /// @param accessController The address of the AccessController contract.
    /// @param ipAccountRegistry The address of the IPAccountRegistry contract.
    constructor(address accessController, address ipAccountRegistry) {
        if (accessController == address(0)) revert Errors.AccessControlled__ZeroAddress();
        if (ipAccountRegistry == address(0)) revert Errors.AccessControlled__ZeroAddress();
        ACCESS_CONTROLLER = IAccessController(accessController);
        IP_ACCOUNT_REGISTRY = IIPAccountRegistry(ipAccountRegistry);
    }

    /// @notice Verifies that the caller has the necessary permission for the given IPAccount.
    /// @dev Modifier that calls _verifyPermission to check if the provided IP account has the required permission.
    /// modules can use this modifier to check if the caller has the necessary permission.
    /// @param ipAccount The address of the IP account to verify.
    modifier verifyPermission(address ipAccount) {
        _verifyPermission(ipAccount);
        _;
    }

    /// @notice Ensures that the caller is a registered IP account.
    /// @dev Modifier that checks if the msg.sender is a registered IP account.
    /// modules can use this modifier to check if the caller is a registered IP account.
    /// so that enforce only registered IP Account can call the functions.
    modifier onlyIpAccount() {
        if (!IP_ACCOUNT_REGISTRY.isIpAccount(msg.sender)) {
            revert Errors.AccessControlled__CallerIsNotIpAccount(msg.sender);
        }
        _;
    }

    /// @dev Internal function to verify if the caller (msg.sender) has the required permission to execute
    /// the function on provided ipAccount.
    /// @param ipAccount The address of the IP account to verify.
    function _verifyPermission(address ipAccount) internal view {
        if (!IP_ACCOUNT_REGISTRY.isIpAccount(ipAccount)) {
            revert Errors.AccessControlled__NotIpAccount(ipAccount);
        }

        if (msg.sender != ipAccount) {
            // revert if the msg.sender does not have permission
            ACCESS_CONTROLLER.checkPermission(ipAccount, msg.sender, address(this), msg.sig);
        }
    }

    /// @dev Internal function to check if the caller (msg.sender) has the required permission to execute
    /// the function on provided ipAccount, returning a boolean.
    /// @param ipAccount The address of the IP account to check.
    /// @return bool Returns true if the caller has permission, false otherwise.
    function _hasPermission(address ipAccount) internal view returns (bool) {
        if (!IP_ACCOUNT_REGISTRY.isIpAccount(ipAccount)) {
            return false;
        }

        if (msg.sender == ipAccount) {
            return true;
        }

        try ACCESS_CONTROLLER.checkPermission(ipAccount, msg.sender, address(this), msg.sig) {
            return true;
        } catch {
            return false;
        }
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

/// @title Key Value Resolver Interface
interface IKeyValueResolver {
    /// @notice Emits when a new key-value pair is set for the resolver.
    event KeyValueSet(address indexed ipId, string indexed key, string value);

    /// @notice Sets the string value for a specified key of an IP ID.
    /// @dev Enforced to be only callable by users with valid permission to call on behalf of the ipId.
    /// @param ipId The canonical identifier of the IP asset.
    /// @param key The string parameter key to update.
    /// @param val The value to set for the specified key.
    function setValue(address ipId, string calldata key, string calldata val) external;

    /// @notice Retrieves the string value associated with a key for an IP asset.
    /// @param key The string parameter key to query.
    /// @return value The value associated with the specified key.
    function value(address ipId, string calldata key) external view returns (string memory);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165Checker.sol)

pragma solidity ^0.8.20;

import {IERC165} from "./IERC165.sol";

/**
 * @dev Library used to query support of an interface declared via {IERC165}.
 *
 * Note that these functions return the actual result of the query: they do not
 * `revert` if an interface is not supported. It is up to the caller to decide
 * what to do in these cases.
 */
library ERC165Checker {
    // As per the EIP-165 spec, no interface should ever match 0xffffffff
    bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff;

    /**
     * @dev Returns true if `account` supports the {IERC165} interface.
     */
    function supportsERC165(address account) internal view returns (bool) {
        // Any contract that implements ERC165 must explicitly indicate support of
        // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
        return
            supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&
            !supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID);
    }

    /**
     * @dev Returns true if `account` supports the interface defined by
     * `interfaceId`. Support for {IERC165} itself is queried automatically.
     *
     * See {IERC165-supportsInterface}.
     */
    function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
        // query support of both ERC165 as per the spec and support of _interfaceId
        return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);
    }

    /**
     * @dev Returns a boolean array where each value corresponds to the
     * interfaces passed in and whether they're supported or not. This allows
     * you to batch check interfaces for a contract where your expectation
     * is that some interfaces may not be supported.
     *
     * See {IERC165-supportsInterface}.
     */
    function getSupportedInterfaces(
        address account,
        bytes4[] memory interfaceIds
    ) internal view returns (bool[] memory) {
        // an array of booleans corresponding to interfaceIds and whether they're supported or not
        bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);

        // query support of ERC165 itself
        if (supportsERC165(account)) {
            // query support of each interface in interfaceIds
            for (uint256 i = 0; i < interfaceIds.length; i++) {
                interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);
            }
        }

        return interfaceIdsSupported;
    }

    /**
     * @dev Returns true if `account` supports all the interfaces defined in
     * `interfaceIds`. Support for {IERC165} itself is queried automatically.
     *
     * Batch-querying can lead to gas savings by skipping repeated checks for
     * {IERC165} support.
     *
     * See {IERC165-supportsInterface}.
     */
    function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
        // query support of ERC165 itself
        if (!supportsERC165(account)) {
            return false;
        }

        // query support of each interface in interfaceIds
        for (uint256 i = 0; i < interfaceIds.length; i++) {
            if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
                return false;
            }
        }

        // all interfaces supported
        return true;
    }

    /**
     * @notice Query if a contract implements an interface, does not check ERC165 support
     * @param account The address of the contract to query for support of an interface
     * @param interfaceId The interface identifier, as specified in ERC-165
     * @return true if the contract at account indicates support of the interface with
     * identifier interfaceId, false otherwise
     * @dev Assumes that account contains a contract that supports ERC165, otherwise
     * the behavior of this method is undefined. This precondition can be checked
     * with {supportsERC165}.
     *
     * Some precompiled contracts will falsely indicate support for a given interface, so caution
     * should be exercised when using this function.
     *
     * Interface identification is specified in ERC-165.
     */
    function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
        // prepare call
        bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId));

        // perform static call
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly {
            success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0x00)
        }

        return success && returnSize >= 0x20 && returnValue > 0;
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";

import { Errors } from "../lib/Errors.sol";
import { IGovernance } from "../interfaces/governance/IGovernance.sol";
import { IGovernable } from "../interfaces/governance/IGovernable.sol";
import { GovernanceLib } from "../lib/GovernanceLib.sol";

/// @title Governable
/// @dev All contracts managed by governance should inherit from this contract.
abstract contract Governable is IGovernable {
    /// @notice The address of the governance.
    address public governance;

    /// @dev Ensures that the function is called by the protocol admin.
    modifier onlyProtocolAdmin() {
        if (!IGovernance(governance).hasRole(GovernanceLib.PROTOCOL_ADMIN, msg.sender)) {
            revert Errors.Governance__OnlyProtocolAdmin();
        }
        _;
    }

    modifier whenNotPaused() {
        if (IGovernance(governance).getState() == GovernanceLib.ProtocolState.Paused) {
            revert Errors.Governance__ProtocolPaused();
        }
        _;
    }

    /// @notice Constructs a new Governable contract.
    /// @param governance_ The address of the governance.
    constructor(address governance_) {
        if (governance_ == address(0)) revert Errors.Governance__ZeroAddress();
        governance = governance_;
        emit GovernanceUpdated(governance);
    }

    /// @notice Sets a new governance address.
    /// @param newGovernance The address of the new governance.
    function setGovernance(address newGovernance) external onlyProtocolAdmin {
        if (newGovernance == address(0)) revert Errors.Governance__ZeroAddress();
        if (!ERC165Checker.supportsInterface(newGovernance, type(IGovernance).interfaceId))
            revert Errors.Governance__UnsupportedInterface("IGovernance");
        if (IGovernance(newGovernance).getState() != IGovernance(governance).getState())
            revert Errors.Governance__InconsistentState();
        governance = newGovernance;
        emit GovernanceUpdated(newGovernance);
    }

    /// @notice Returns the current governance address.
    /// @return governance The address of the current governance.
    function getGovernance() external view returns (address) {
        return governance;
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { IModule } from "../../modules/base/IModule.sol";

/// @title RoyaltyModule interface
interface IRoyaltyModule is IModule {
    /// @notice Event emitted when a royalty policy is whitelisted
    /// @param royaltyPolicy The address of the royalty policy
    /// @param allowed Indicates if the royalty policy is whitelisted or not
    event RoyaltyPolicyWhitelistUpdated(address royaltyPolicy, bool allowed);

    /// @notice Event emitted when a royalty token is whitelisted
    /// @param token The address of the royalty token
    /// @param allowed Indicates if the royalty token is whitelisted or not
    event RoyaltyTokenWhitelistUpdated(address token, bool allowed);

    /// @notice Event emitted when royalties are paid
    /// @param receiverIpId The ID of IP asset that receives the royalties
    /// @param payerIpId The ID of IP asset that pays the royalties
    /// @param sender The address that pays the royalties on behalf of the payer ID of IP asset
    /// @param token The token that is used to pay the royalties
    /// @param amount The amount that is paid
    event RoyaltyPaid(address receiverIpId, address payerIpId, address sender, address token, uint256 amount);

    /// @notice Event emitted when the license minting fee is paid
    /// @param receiverIpId The ipId that receives the royalties
    /// @param payerAddress The address that pays the royalties
    /// @param token The token that is used to pay the royalties
    /// @param amount The amount paid
    event LicenseMintingFeePaid(address receiverIpId, address payerAddress, address token, uint256 amount);

    /// @notice Returns the licensing module address
    function LICENSING_MODULE() external view returns (address);

    /// @notice Indicates if a royalty policy is whitelisted
    /// @param royaltyPolicy The address of the royalty policy
    /// @return isWhitelisted True if the royalty policy is whitelisted
    function isWhitelistedRoyaltyPolicy(address royaltyPolicy) external view returns (bool);

    /// @notice Indicates if a royalty token is whitelisted
    /// @param token The address of the royalty token
    /// @return isWhitelisted True if the royalty token is whitelisted
    function isWhitelistedRoyaltyToken(address token) external view returns (bool);

    /// @notice Indicates the royalty policy for a given IP asset
    /// @param ipId The ID of IP asset
    /// @return royaltyPolicy The address of the royalty policy
    function royaltyPolicies(address ipId) external view returns (address);

    /// @notice Whitelist a royalty policy
    /// @dev Enforced to be only callable by the protocol admin
    /// @param royaltyPolicy The address of the royalty policy
    /// @param allowed Indicates if the royalty policy is whitelisted or not
    function whitelistRoyaltyPolicy(address royaltyPolicy, bool allowed) external;

    /// @notice Whitelist a royalty token
    /// @dev Enforced to be only callable by the protocol admin
    /// @param token The token address
    /// @param allowed Indicates if the token is whitelisted or not
    function whitelistRoyaltyToken(address token, bool allowed) external;

    /// @notice Executes royalty related logic on license minting
    /// @dev Enforced to be only callable by LicensingModule
    /// @param ipId The ipId whose license is being minted (licensor)
    /// @param royaltyPolicy The royalty policy address of the license being minted
    /// @param licenseData The license data custom to each the royalty policy
    /// @param externalData The external data custom to each the royalty policy
    function onLicenseMinting(
        address ipId,
        address royaltyPolicy,
        bytes calldata licenseData,
        bytes calldata externalData
    ) external;

    /// @notice Executes royalty related logic on linking to parents
    /// @dev Enforced to be only callable by LicensingModule
    /// @param ipId The children ipId that is being linked to parents
    /// @param royaltyPolicy The common royalty policy address of all the licenses being burned
    /// @param parentIpIds The parent ipIds that the children ipId is being linked to
    /// @param licenseData The license data custom to each the royalty policy
    /// @param externalData The external data custom to each the royalty policy
    function onLinkToParents(
        address ipId,
        address royaltyPolicy,
        address[] calldata parentIpIds,
        bytes[] memory licenseData,
        bytes calldata externalData
    ) external;

    /// @notice Allows the function caller to pay royalties to the receiver IP asset on behalf of the payer IP asset.
    /// @param receiverIpId The ID of the IP asset that receives the royalties
    /// @param payerIpId The ID of the IP asset that pays the royalties
    /// @param token The token to use to pay the royalties
    /// @param amount The amount to pay
    function payRoyaltyOnBehalf(address receiverIpId, address payerIpId, address token, uint256 amount) external;

    /// @notice Allows to pay the minting fee for a license
    /// @param receiverIpId The ipId that receives the royalties
    /// @param payerAddress The address that pays the royalties
    /// @param licenseRoyaltyPolicy The royalty policy of the license being minted
    /// @param token The token to use to pay the royalties
    /// @param amount The amount to pay
    function payLicenseMintingFee(
        address receiverIpId,
        address payerAddress,
        address licenseRoyaltyPolicy,
        address token,
        uint256 amount
    ) external;
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

/// @title RoyaltyPolicy interface
interface IRoyaltyPolicy {
    /// @notice Executes royalty related logic on minting a license
    /// @dev Enforced to be only callable by RoyaltyModule
    /// @param ipId The ipId whose license is being minted (licensor)
    /// @param licenseData The license data custom to each the royalty policy
    /// @param externalData The external data custom to each the royalty policy
    function onLicenseMinting(address ipId, bytes calldata licenseData, bytes calldata externalData) external;

    /// @notice Executes royalty related logic on linking to parents
    /// @dev Enforced to be only callable by RoyaltyModule
    /// @param ipId The children ipId that is being linked to parents
    /// @param parentIpIds The parent ipIds that the children ipId is being linked to
    /// @param licenseData The license data custom to each the royalty policy
    /// @param externalData The external data custom to each the royalty policy
    function onLinkToParents(
        address ipId,
        address[] calldata parentIpIds,
        bytes[] memory licenseData,
        bytes calldata externalData
    ) external;

    /// @notice Allows the caller to pay royalties to the given IP asset
    /// @param caller The caller is the address from which funds will transferred from
    /// @param ipId The ipId of the receiver of the royalties
    /// @param token The token to pay
    /// @param amount The amount to pay
    function onRoyaltyPayment(address caller, address ipId, address token, uint256 amount) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the value of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(
        address[] calldata accounts,
        uint256[] calldata ids
    ) external view returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`.
     *
     * WARNING: This function can potentially allow a reentrancy attack when transferring tokens
     * to an untrusted contract, when invoking {onERC1155Received} on the receiver.
     * Ensure to follow the checks-effects-interactions pattern and consider employing
     * reentrancy guards when interacting with untrusted contracts.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `value` amount.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * WARNING: This function can potentially allow a reentrancy attack when transferring tokens
     * to an untrusted contract, when invoking {onERC1155BatchReceived} on the receiver.
     * Ensure to follow the checks-effects-interactions pattern and consider employing
     * reentrancy guards when interacting with untrusted contracts.
     *
     * Emits either a {TransferSingle} or a {TransferBatch} event, depending on the length of the array arguments.
     *
     * Requirements:
     *
     * - `ids` and `values` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external;
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

/// @title Metadata Provider Interface
interface IMetadataProvider {
    /// @notice Emits when canonical metadata was set for a specific IP asset.
    /// @param ipId The address of the IP asset.
    /// @param metadata The encoded metadata associated with the IP asset.
    event MetadataSet(address ipId, bytes metadata);

    /// @notice Gets the metadata associated with an IP asset.
    /// @param ipId The address identifier of the IP asset.
    /// @return metadata The encoded metadata associated with the IP asset.
    function getMetadata(address ipId) external view returns (bytes memory);

    /// @notice Sets the metadata associated with an IP asset.
    /// @param ipId The address identifier of the IP asset.
    /// @param metadata The metadata in bytes to associate with the IP asset.
    function setMetadata(address ipId, bytes memory metadata) external;
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { AccessPermission } from "../lib/AccessPermission.sol";

interface IAccessController {
    /// @notice Emitted when a permission is set.
    /// @param ipAccount The address of the IP account that grants the permission for `signer`
    /// @param signer The address that can call `to` on behalf of the IP account
    /// @param to The address that can be called by the `signer` (currently only modules can be `to`)
    /// @param func The function selector of `to` that can be called by the `signer` on behalf of the `ipAccount`
    /// @param permission The permission level
    event PermissionSet(
        address ipAccountOwner,
        address indexed ipAccount,
        address indexed signer,
        address indexed to,
        bytes4 func,
        uint8 permission
    );

    /// @notice Sets a batch of permissions in a single transaction.
    /// @dev This function allows setting multiple permissions at once. Pausable.
    /// @param permissions An array of `Permission` structs, each representing the permission to be set.
    function setBatchPermissions(AccessPermission.Permission[] memory permissions) external;

    /// @notice Sets the permission for all IPAccounts
    /// @dev Enforced to be only callable by the protocol admin in governance.
    /// @param signer The address that can call `to` on behalf of the IP account
    /// @param to The address that can be called by the `signer` (currently only modules can be `to`)
    /// @param func The function selector of `to` that can be called by the `signer` on behalf of the `ipAccount`
    /// @param permission The new permission level
    function setGlobalPermission(address signer, address to, bytes4 func, uint8 permission) external;

    /// @notice Sets the permission for a specific function call
    /// @dev Each policy is represented as a mapping from an IP account address to a signer address to a recipient
    /// address to a function selector to a permission level. The permission level can be 0 (ABSTAIN), 1 (ALLOW), or
    /// 2 (DENY).
    /// @dev By default, all policies are set to 0 (ABSTAIN), which means that the permission is not set.
    /// The owner of ipAccount by default has all permission.
    /// address(0) => wildcard
    /// bytes4(0) => wildcard
    /// Specific permission overrides wildcard permission.
    /// @param ipAccount The address of the IP account that grants the permission for `signer`
    /// @param signer The address that can call `to` on behalf of the `ipAccount`
    /// @param to The address that can be called by the `signer` (currently only modules can be `to`)
    /// @param func The function selector of `to` that can be called by the `signer` on behalf of the `ipAccount`
    /// @param permission The new permission level
    function setPermission(address ipAccount, address signer, address to, bytes4 func, uint8 permission) external;

    /// @notice Checks the permission level for a specific function call. Reverts if permission is not granted.
    /// Otherwise, the function is a noop.
    /// @dev This function checks the permission level for a specific function call.
    /// If a specific permission is set, it overrides the general (wildcard) permission.
    /// If the current level permission is ABSTAIN, the final permission is determined by the upper level.
    /// @param ipAccount The address of the IP account that grants the permission for `signer`
    /// @param signer The address that can call `to` on behalf of the `ipAccount`
    /// @param to The address that can be called by the `signer` (currently only modules can be `to`)
    /// @param func The function selector of `to` that can be called by the `signer` on behalf of the `ipAccount`
    function checkPermission(address ipAccount, address signer, address to, bytes4 func) external view;

    /// @notice Returns the permission level for a specific function call.
    /// @param ipAccount The address of the IP account that grants the permission for `signer`
    /// @param signer The address that can call `to` on behalf of the `ipAccount`
    /// @param to The address that can be called by the `signer` (currently only modules can be `to`)
    /// @param func The function selector of `to` that can be called by the `signer` on behalf of the `ipAccount`
    /// @return permission The current permission level for the function call on `to` by the `signer` for `ipAccount`
    function getPermission(address ipAccount, address signer, address to, bytes4 func) external view returns (uint8);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import { IERC6551Account } from "erc6551/interfaces/IERC6551Account.sol";

import { IIPAccountRegistry } from "../../interfaces/registries/IIPAccountRegistry.sol";
import { IIPAccount } from "../..//interfaces/IIPAccount.sol";

/// @title IPAccountChecker
/// @dev This library provides utility functions to check the registration and validity of IP Accounts.
/// It uses the ERC165 standard for contract introspection and the IIPAccountRegistry interface
/// for account registration checks.
library IPAccountChecker {
    /// @notice Returns true if the IPAccount is registered.
    /// @param chainId_ The chain ID where the IP Account is located.
    /// @param tokenContract_ The address of the token contract associated with the IP Account.
    /// @param tokenId_ The ID of the token associated with the IP Account.
    /// @return True if the IP Account is registered, false otherwise.
    function isRegistered(
        IIPAccountRegistry ipAccountRegistry_,
        uint256 chainId_,
        address tokenContract_,
        uint256 tokenId_
    ) external view returns (bool) {
        return ipAccountRegistry_.ipAccount(chainId_, tokenContract_, tokenId_).code.length != 0;
    }

    /// @notice Checks if the given address is a valid IP Account.
    /// @param ipAccountRegistry_ The IP Account registry contract.
    /// @param ipAccountAddress_ The address to check.
    /// @return True if the address is a valid IP Account, false otherwise.
    function isIpAccount(
        IIPAccountRegistry ipAccountRegistry_,
        address ipAccountAddress_
    ) external view returns (bool) {
        if (ipAccountAddress_ == address(0)) return false;
        if (ipAccountAddress_.code.length == 0) return false;
        if (!ERC165Checker.supportsERC165(ipAccountAddress_)) return false;
        if (!ERC165Checker.supportsInterface(ipAccountAddress_, type(IERC6551Account).interfaceId)) return false;
        if (!ERC165Checker.supportsInterface(ipAccountAddress_, type(IIPAccount).interfaceId)) return false;
        (uint chainId, address tokenContract, uint tokenId) = IIPAccount(payable(ipAccountAddress_)).token();
        return ipAccountAddress_ == ipAccountRegistry_.ipAccount(chainId, tokenContract, tokenId);
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol";

import { GovernanceLib } from "../../lib/GovernanceLib.sol";

/// @title IGovernance
/// @dev This interface defines the governance functionality for the protocol.
interface IGovernance is IAccessControl {
    /// @notice Emitted when the protocol state is set
    /// @param account The address that triggered the state change
    /// @param prevState The previous state of the protocol
    /// @param newState The new state of the protocol
    /// @param timestamp The time when the state change occurred
    event StateSet(
        address indexed account,
        GovernanceLib.ProtocolState prevState,
        GovernanceLib.ProtocolState newState,
        uint256 timestamp
    );

    /// @notice Sets the state of the protocol
    /// @dev This function can only be called by an account with the appropriate role
    /// @param newState The new state to set for the protocol
    function setState(GovernanceLib.ProtocolState newState) external;

    /// @notice Returns the current state of the protocol
    /// @return state The current state of the protocol
    function getState() external view returns (GovernanceLib.ProtocolState);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

/// @title IGovernable
/// @notice This is the interface for the Lens Protocol main governance functions.
interface IGovernable {
    /// @notice Emitted when the governance is updated
    /// @param newGovernance The address of the new governance
    event GovernanceUpdated(address indexed newGovernance);

    /// @notice Sets the governance address
    /// @param newGovernance The address of the new governance
    function setGovernance(address newGovernance) external;

    /// @notice Returns the current governance address
    /// @return The address of the current governance
    function getGovernance() external view returns (address);
}

File 37 of 43 : GovernanceLib.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

/// @title Governance
/// @dev This library provides types for Story Protocol Governance.
library GovernanceLib {
    bytes32 public constant PROTOCOL_ADMIN = bytes32(0);

    /// @notice An enum containing the different states the protocol can be in.
    /// @param Unpaused The unpaused state.
    /// @param Paused The paused state.
    enum ProtocolState {
        Unpaused,
        Paused
    }
}

File 38 of 43 : AccessPermission.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

/// @title Access Permission Library
/// @notice Library for IPAccount access control permissions.
///         These permissions are used by the AccessController.
library AccessPermission {
    /// @notice ABSTAIN means having not enough information to make decision at current level, deferred decision to up
    /// level permission.
    uint8 public constant ABSTAIN = 0;

    /// @notice ALLOW means the permission is granted to transaction signer to call the function.
    uint8 public constant ALLOW = 1;

    /// @notice DENY means the permission is denied to transaction signer to call the function.
    uint8 public constant DENY = 2;

    /// @notice This struct is used to represent permissions in batch operations within the AccessController.
    /// @param ipAccount The address of the IP account that grants the permission for `signer`
    /// @param signer The address that can call `to` on behalf of the `ipAccount`
    /// @param to The address that can be called by the `signer` (currently only modules can be `to`)
    /// @param func The function selector of `to` that can be called by the `signer` on behalf of the `ipAccount`
    /// @param permission The permission level for the transaction (0 = ABSTAIN, 1 = ALLOW, 2 = DENY).
    struct Permission {
        address ipAccount;
        address signer;
        address to;
        bytes4 func;
        uint8 permission;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @dev the ERC-165 identifier for this interface is `0x6faff5f1`
interface IERC6551Account {
    /**
     * @dev Allows the account to receive Ether.
     *
     * Accounts MUST implement a `receive` function.
     *
     * Accounts MAY perform arbitrary logic to restrict conditions
     * under which Ether can be received.
     */
    receive() external payable;

    /**
     * @dev Returns the identifier of the non-fungible token which owns the account.
     *
     * The return value of this function MUST be constant - it MUST NOT change over time.
     *
     * @return chainId       The EIP-155 ID of the chain the token exists on
     * @return tokenContract The contract address of the token
     * @return tokenId       The ID of the token
     */
    function token()
        external
        view
        returns (uint256 chainId, address tokenContract, uint256 tokenId);

    /**
     * @dev Returns a value that SHOULD be modified each time the account changes state.
     *
     * @return The current account state
     */
    function state() external view returns (uint256);

    /**
     * @dev Returns a magic value indicating whether a given signer is authorized to act on behalf
     * of the account.
     *
     * MUST return the bytes4 magic value 0x523e3260 if the given signer is valid.
     *
     * By default, the holder of the non-fungible token the account is bound to MUST be considered
     * a valid signer.
     *
     * Accounts MAY implement additional authorization logic which invalidates the holder as a
     * signer or grants signing permissions to other non-holder accounts.
     *
     * @param  signer     The address to check signing authorization for
     * @param  context    Additional data used to determine whether the signer is valid
     * @return magicValue Magic value indicating whether the signer is valid
     */
    function isValidSigner(address signer, bytes calldata context)
        external
        view
        returns (bytes4 magicValue);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { IERC721Receiver } from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import { IERC1155Receiver } from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import { IERC6551Account } from "erc6551/interfaces/IERC6551Account.sol";

/// @title IIPAccount
/// @dev IPAccount is a token-bound account that adopts the EIP-6551 standard.
/// These accounts are deployed at deterministic addresses through the official 6551 account registry.
/// As a deployed smart contract, IPAccount can store IP-related information,
/// like ownership of other NFTs such as license NFT or Royalty NFT.
/// IPAccount can interact with modules by making calls as a normal transaction sender.
/// This allows for seamless operations on the state and data of IP.
/// IPAccount is core identity for all actions.
interface IIPAccount is IERC6551Account, IERC721Receiver, IERC1155Receiver {
    /// @notice Emitted when a transaction is executed.
    /// @param to The recipient of the transaction.
    /// @param value The amount of Ether sent.
    /// @param data The data sent along with the transaction.
    /// @param nonce The nonce of the transaction.
    event Executed(address indexed to, uint256 value, bytes data, uint256 nonce);

    /// @notice Emitted when a transaction is executed on behalf of the signer.
    /// @param to The recipient of the transaction.
    /// @param value The amount of Ether sent.
    /// @param data The data sent along with the transaction.
    /// @param nonce The nonce of the transaction.
    /// @param deadline The deadline of the transaction signature.
    /// @param signer The signer of the transaction.
    /// @param signature The signature of the transaction, EIP-712 encoded.
    event ExecutedWithSig(
        address indexed to,
        uint256 value,
        bytes data,
        uint256 nonce,
        uint256 deadline,
        address indexed signer,
        bytes signature
    );

    /// @notice Returns the IPAccount's internal nonce for transaction ordering.
    function state() external view returns (uint256);

    /// @notice Returns the identifier of the non-fungible token which owns the account
    /// @return chainId The EIP-155 ID of the chain the token exists on
    /// @return tokenContract The contract address of the token
    /// @return tokenId The ID of the token
    function token() external view returns (uint256, address, uint256);

    /// @notice Checks if the signer is valid for the given data
    /// @param signer The signer to check
    /// @param data The data to check against
    /// @return The function selector if the signer is valid, 0 otherwise
    function isValidSigner(address signer, bytes calldata data) external view returns (bytes4);

    /// @notice Returns the owner of the IP Account.
    /// @return owner The address of the owner.
    function owner() external view returns (address);

    /// @notice Executes a transaction from the IP Account on behalf of the signer.
    /// @param to The recipient of the transaction.
    /// @param value The amount of Ether to send.
    /// @param data The data to send along with the transaction.
    /// @param signer The signer of the transaction.
    /// @param deadline The deadline of the transaction signature.
    /// @param signature The signature of the transaction, EIP-712 encoded.
    /// @return result The return data from the transaction.
    function executeWithSig(
        address to,
        uint256 value,
        bytes calldata data,
        address signer,
        uint256 deadline,
        bytes calldata signature
    ) external payable returns (bytes memory);

    /// @notice Executes a transaction from the IP Account.
    /// @param to The recipient of the transaction.
    /// @param value The amount of Ether to send.
    /// @param data The data to send along with the transaction.
    /// @return result The return data from the transaction.
    function execute(address to, uint256 value, bytes calldata data) external payable returns (bytes memory);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)

pragma solidity ^0.8.20;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev The `account` is missing a role.
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev The caller of a function is not the expected one.
     *
     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
     */
    error AccessControlBadConfirmation();

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     */
    function renounceRole(bytes32 role, address callerConfirmation) external;
}

File 42 of 43 : IERC721Receiver.sol
// 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);
}

Settings
{
  "remappings": [
    "@ethereum-waffle/=node_modules/@ethereum-waffle/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "forge-std/=node_modules/forge-std/src/",
    "ds-test/=node_modules/ds-test/src/",
    "base64-sol/=node_modules/base64-sol/",
    "eth-gas-reporter/=node_modules/eth-gas-reporter/",
    "hardhat-deploy/=node_modules/hardhat-deploy/",
    "hardhat/=node_modules/hardhat/",
    "erc6551/=node_modules/erc6551/",
    "openzeppelin-contracts/=lib/reference/lib/openzeppelin-contracts/",
    "reference/=lib/reference/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 20000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {
    "contracts/lib/registries/IPAccountChecker.sol": {
      "IPAccountChecker": "0x36e93affeca875ebcef53e922a4b716ad2a508a9"
    }
  }
}

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"assetRegistry","type":"address"},{"internalType":"address","name":"licensingModule","type":"address"},{"internalType":"address","name":"resolverAddr","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"RegistrationModule__InvalidOwner","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"ipId","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"licenseIds","type":"uint256[]"}],"name":"DerivativeIPRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"ipId","type":"address"},{"indexed":true,"internalType":"uint256","name":"policyId","type":"uint256"}],"name":"RootIPRegistered","type":"event"},{"inputs":[],"name":"ipResolver","outputs":[{"internalType":"contract IPResolver","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"licenseIds","type":"uint256[]"},{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"ipName","type":"string"},{"internalType":"bytes32","name":"contentHash","type":"bytes32"},{"internalType":"string","name":"externalURL","type":"string"},{"internalType":"bytes","name":"royaltyContext","type":"bytes"}],"name":"registerDerivativeIp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"policyId","type":"uint256"},{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"ipName","type":"string"},{"internalType":"bytes32","name":"contentHash","type":"bytes32"},{"internalType":"string","name":"externalURL","type":"string"}],"name":"registerRootIp","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b506040516110f43803806110f483398101604081905261002f9161008e565b600080546001600160a01b03199081166001600160a01b0393841617909155600280548216938316939093179092556001805490921692169190911790556100d1565b80516001600160a01b038116811461008957600080fd5b919050565b6000806000606084860312156100a357600080fd5b6100ac84610072565b92506100ba60208501610072565b91506100c860408501610072565b90509250925092565b611014806100e06000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806317f248851161005057806317f24885146100dd5780634f52e7a2146100f2578063ec4efa391461012a57600080fd5b806301ffc9a71461006c57806306fdde0314610094575b600080fd5b61007f61007a3660046109c6565b61014a565b60405190151581526020015b60405180910390f35b6100d06040518060400160405280601381526020017f524547495354524154494f4e5f4d4f44554c450000000000000000000000000081525081565b60405161008b9190610a73565b6100f06100eb366004610c23565b6101e3565b005b610105610100366004610d0b565b6105dd565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161008b565b6000546101059073ffffffffffffffffffffffffffffffffffffffff1681565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f06fdde030000000000000000000000000000000000000000000000000000000014806101dd57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810188905260009073ffffffffffffffffffffffffffffffffffffffff8a1690636352211e90602401602060405180830381865afa158015610251573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102759190610da5565b90503373ffffffffffffffffffffffffffffffffffffffff82161480159061033057506040517fe985e9c500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301523360248301528a169063e985e9c590604401602060405180830381865afa15801561030a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061032e9190610dc2565b155b15610367576040517f7748d9ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006040518060a001604052808981526020018881526020014267ffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff16815260200187878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040516103f49190602001610de4565b60405160208183030381529060405290506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d61f3d468d8d60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff166001886040518763ffffffff1660e01b815260040161048d96959493929190610e82565b6020604051808303816000875af11580156104ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d09190610da5565b9050600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639f69e70d8e8e8489896040518663ffffffff1660e01b8152600401610535959493929190610f26565b600060405180830381600087803b15801561054f57600080fd5b505af1158015610563573d6000803e3d6000fd5b505050508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f0300748d3720c0777d8645f4affde2a3a29c8515e10a7a31345d954bd9aed7b48f8f6040516105c6929190610fa9565b60405180910390a350505050505050505050505050565b6040517f6352211e00000000000000000000000000000000000000000000000000000000815260048101869052600090819073ffffffffffffffffffffffffffffffffffffffff891690636352211e90602401602060405180830381865afa15801561064d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106719190610da5565b90503373ffffffffffffffffffffffffffffffffffffffff82161480159061072c57506040517fe985e9c500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff828116600483015233602483015289169063e985e9c590604401602060405180830381865afa158015610706573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072a9190610dc2565b155b15610763576040517f7748d9ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006040518060a001604052808881526020018781526020014267ffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff16815260200186868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040516107f09190602001610de4565b60405160208183030381529060405290506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d61f3d468c8c60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff166001886040518763ffffffff1660e01b815260040161088996959493929190610e82565b6020604051808303816000875af11580156108a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108cc9190610da5565b90508a15610973576002546040517f7305424f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018e905290911690637305424f906044016020604051808303816000875af115801561094d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109719190610fc5565b505b6040518b9073ffffffffffffffffffffffffffffffffffffffff83169033907fa6e4d1983948888a2be7e084c14834fc01066c7b1173b1d505a1a882ae310a3e90600090a49a9950505050505050505050565b6000602082840312156109d857600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610a0857600080fd5b9392505050565b6000815180845260005b81811015610a3557602081850181015186830182015201610a19565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000610a086020830184610a0f565b60008083601f840112610a9857600080fd5b50813567ffffffffffffffff811115610ab057600080fd5b6020830191508360208260051b8501011115610acb57600080fd5b9250929050565b73ffffffffffffffffffffffffffffffffffffffff81168114610af457600080fd5b50565b8035610b0281610ad2565b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f830112610b4757600080fd5b813567ffffffffffffffff80821115610b6257610b62610b07565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715610ba857610ba8610b07565b81604052838152866020858801011115610bc157600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008083601f840112610bf357600080fd5b50813567ffffffffffffffff811115610c0b57600080fd5b602083019150836020828501011115610acb57600080fd5b60008060008060008060008060008060e08b8d031215610c4257600080fd5b8a3567ffffffffffffffff80821115610c5a57600080fd5b610c668e838f01610a86565b909c509a508a9150610c7a60208e01610af7565b995060408d0135985060608d0135915080821115610c9757600080fd5b610ca38e838f01610b36565b975060808d0135965060a08d0135915080821115610cc057600080fd5b610ccc8e838f01610be1565b909650945060c08d0135915080821115610ce557600080fd5b50610cf28d828e01610be1565b915080935050809150509295989b9194979a5092959850565b600080600080600080600060c0888a031215610d2657600080fd5b873596506020880135610d3881610ad2565b955060408801359450606088013567ffffffffffffffff80821115610d5c57600080fd5b610d688b838c01610b36565b955060808a0135945060a08a0135915080821115610d8557600080fd5b50610d928a828b01610be1565b989b979a50959850939692959293505050565b600060208284031215610db757600080fd5b8151610a0881610ad2565b600060208284031215610dd457600080fd5b81518015158114610a0857600080fd5b602081526000825160a06020840152610e0060c0840182610a0f565b90506020840151604084015267ffffffffffffffff604085015116606084015273ffffffffffffffffffffffffffffffffffffffff606085015116608084015260808401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160a0850152610e798282610a0f565b95945050505050565b868152600073ffffffffffffffffffffffffffffffffffffffff8088166020840152866040840152808616606084015250831515608083015260c060a0830152610ecf60c0830184610a0f565b98975050505050505050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115610f0d57600080fd5b8260051b80836020870137939093016020019392505050565b606081526000610f3a606083018789610edb565b73ffffffffffffffffffffffffffffffffffffffff8616602084015282810360408401528381528385602083013760006020858301015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8601168201019150509695505050505050565b602081526000610fbd602083018486610edb565b949350505050565b600060208284031215610fd757600080fd5b505191905056fea264697066735822122090f494cd6df0a7acd2fa2e1aee0e8ecaa8c301f7c2ecd8c6fdbc58a04f93644864736f6c63430008170033000000000000000000000000292639452a975630802c17c9267169d93bd5a793000000000000000000000000950d766a1a0afdc33c3e653c861a8765cb42dbdc0000000000000000000000003809f4128b0b33afb17576edafd7d4f4e2abe933

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100675760003560e01c806317f248851161005057806317f24885146100dd5780634f52e7a2146100f2578063ec4efa391461012a57600080fd5b806301ffc9a71461006c57806306fdde0314610094575b600080fd5b61007f61007a3660046109c6565b61014a565b60405190151581526020015b60405180910390f35b6100d06040518060400160405280601381526020017f524547495354524154494f4e5f4d4f44554c450000000000000000000000000081525081565b60405161008b9190610a73565b6100f06100eb366004610c23565b6101e3565b005b610105610100366004610d0b565b6105dd565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161008b565b6000546101059073ffffffffffffffffffffffffffffffffffffffff1681565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f06fdde030000000000000000000000000000000000000000000000000000000014806101dd57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810188905260009073ffffffffffffffffffffffffffffffffffffffff8a1690636352211e90602401602060405180830381865afa158015610251573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102759190610da5565b90503373ffffffffffffffffffffffffffffffffffffffff82161480159061033057506040517fe985e9c500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301523360248301528a169063e985e9c590604401602060405180830381865afa15801561030a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061032e9190610dc2565b155b15610367576040517f7748d9ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006040518060a001604052808981526020018881526020014267ffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff16815260200187878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040516103f49190602001610de4565b60405160208183030381529060405290506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d61f3d468d8d60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff166001886040518763ffffffff1660e01b815260040161048d96959493929190610e82565b6020604051808303816000875af11580156104ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d09190610da5565b9050600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639f69e70d8e8e8489896040518663ffffffff1660e01b8152600401610535959493929190610f26565b600060405180830381600087803b15801561054f57600080fd5b505af1158015610563573d6000803e3d6000fd5b505050508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f0300748d3720c0777d8645f4affde2a3a29c8515e10a7a31345d954bd9aed7b48f8f6040516105c6929190610fa9565b60405180910390a350505050505050505050505050565b6040517f6352211e00000000000000000000000000000000000000000000000000000000815260048101869052600090819073ffffffffffffffffffffffffffffffffffffffff891690636352211e90602401602060405180830381865afa15801561064d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106719190610da5565b90503373ffffffffffffffffffffffffffffffffffffffff82161480159061072c57506040517fe985e9c500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff828116600483015233602483015289169063e985e9c590604401602060405180830381865afa158015610706573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072a9190610dc2565b155b15610763576040517f7748d9ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006040518060a001604052808881526020018781526020014267ffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff16815260200186868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040516107f09190602001610de4565b60405160208183030381529060405290506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d61f3d468c8c60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff166001886040518763ffffffff1660e01b815260040161088996959493929190610e82565b6020604051808303816000875af11580156108a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108cc9190610da5565b90508a15610973576002546040517f7305424f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018e905290911690637305424f906044016020604051808303816000875af115801561094d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109719190610fc5565b505b6040518b9073ffffffffffffffffffffffffffffffffffffffff83169033907fa6e4d1983948888a2be7e084c14834fc01066c7b1173b1d505a1a882ae310a3e90600090a49a9950505050505050505050565b6000602082840312156109d857600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610a0857600080fd5b9392505050565b6000815180845260005b81811015610a3557602081850181015186830182015201610a19565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000610a086020830184610a0f565b60008083601f840112610a9857600080fd5b50813567ffffffffffffffff811115610ab057600080fd5b6020830191508360208260051b8501011115610acb57600080fd5b9250929050565b73ffffffffffffffffffffffffffffffffffffffff81168114610af457600080fd5b50565b8035610b0281610ad2565b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f830112610b4757600080fd5b813567ffffffffffffffff80821115610b6257610b62610b07565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715610ba857610ba8610b07565b81604052838152866020858801011115610bc157600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008083601f840112610bf357600080fd5b50813567ffffffffffffffff811115610c0b57600080fd5b602083019150836020828501011115610acb57600080fd5b60008060008060008060008060008060e08b8d031215610c4257600080fd5b8a3567ffffffffffffffff80821115610c5a57600080fd5b610c668e838f01610a86565b909c509a508a9150610c7a60208e01610af7565b995060408d0135985060608d0135915080821115610c9757600080fd5b610ca38e838f01610b36565b975060808d0135965060a08d0135915080821115610cc057600080fd5b610ccc8e838f01610be1565b909650945060c08d0135915080821115610ce557600080fd5b50610cf28d828e01610be1565b915080935050809150509295989b9194979a5092959850565b600080600080600080600060c0888a031215610d2657600080fd5b873596506020880135610d3881610ad2565b955060408801359450606088013567ffffffffffffffff80821115610d5c57600080fd5b610d688b838c01610b36565b955060808a0135945060a08a0135915080821115610d8557600080fd5b50610d928a828b01610be1565b989b979a50959850939692959293505050565b600060208284031215610db757600080fd5b8151610a0881610ad2565b600060208284031215610dd457600080fd5b81518015158114610a0857600080fd5b602081526000825160a06020840152610e0060c0840182610a0f565b90506020840151604084015267ffffffffffffffff604085015116606084015273ffffffffffffffffffffffffffffffffffffffff606085015116608084015260808401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160a0850152610e798282610a0f565b95945050505050565b868152600073ffffffffffffffffffffffffffffffffffffffff8088166020840152866040840152808616606084015250831515608083015260c060a0830152610ecf60c0830184610a0f565b98975050505050505050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115610f0d57600080fd5b8260051b80836020870137939093016020019392505050565b606081526000610f3a606083018789610edb565b73ffffffffffffffffffffffffffffffffffffffff8616602084015282810360408401528381528385602083013760006020858301015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8601168201019150509695505050505050565b602081526000610fbd602083018486610edb565b949350505050565b600060208284031215610fd757600080fd5b505191905056fea264697066735822122090f494cd6df0a7acd2fa2e1aee0e8ecaa8c301f7c2ecd8c6fdbc58a04f93644864736f6c63430008170033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000292639452a975630802c17c9267169d93bd5a793000000000000000000000000950d766a1a0afdc33c3e653c861a8765cb42dbdc0000000000000000000000003809f4128b0b33afb17576edafd7d4f4e2abe933

-----Decoded View---------------
Arg [0] : assetRegistry (address): 0x292639452A975630802C17c9267169D93BD5a793
Arg [1] : licensingModule (address): 0x950d766A1a0afDc33c3e653C861A8765cb42DbdC
Arg [2] : resolverAddr (address): 0x3809f4128B0B33AFb17576edafD7D4F4E2ABE933

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000292639452a975630802c17c9267169d93bd5a793
Arg [1] : 000000000000000000000000950d766a1a0afdc33c3e653c861a8765cb42dbdc
Arg [2] : 0000000000000000000000003809f4128b0b33afb17576edafd7d4f4e2abe933


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
0x613128e88b568768764824f898C8135efED97fA6
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.