Sepolia Testnet

Contract

0xeAABf2b80B7e069EE449B5629590A1cc0F9bC9C2

Overview

ETH Balance

0 ETH

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Register Policy84950952025-06-07 7:21:1232 days ago1749280872IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.000076791.50031262
Register Policy84950672025-06-07 7:15:3632 days ago1749280536IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.000076781.50022834
Register Policy84949692025-06-07 6:56:0032 days ago1749279360IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.000076771.50001021
Register Policy74978102025-01-15 15:43:00175 days ago1736955780IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.0089824413.52949015
Register Policy65947032024-08-29 15:53:36314 days ago1724946816IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.04111921105.93149293
Register Policy63882342024-07-28 0:34:00346 days ago1722126840IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.000816151.01804801
Register Policy63247532024-07-17 2:28:24357 days ago1721183304IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.000017140.03750604
Register Policy63234772024-07-16 21:23:48358 days ago1721165028IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.001332232.91472473
Register Policy63234452024-07-16 21:16:48358 days ago1721164608IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.001894874.14613126
Register Policy63165782024-07-15 18:35:00359 days ago1721068500IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.000266190.58238071
Register Policy63162122024-07-15 17:10:24359 days ago1721063424IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.0398628375.77981126
Register Policy63161872024-07-15 17:04:36359 days ago1721063076IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.0364255393.83671468
Register Policy63160422024-07-15 16:30:48359 days ago1721061048IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.003189998.21732073
Register Policy63159812024-07-15 16:16:36359 days ago1721060196IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.004855410.62203846
Register Policy63052832024-07-13 22:21:24360 days ago1720909284IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.000320430.60921235
Register Policy63042012024-07-13 18:02:00361 days ago1720893720IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.001278511.46842401
Register Policy60522432024-06-06 16:18:24398 days ago1717690704IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.004991925.31296354
Register Policy60151912024-05-31 23:01:00403 days ago1717196460IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.000310630.38740716
Register Policy60151522024-05-31 22:51:12403 days ago1717195872IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.000278090.37947693
Register Policy60150352024-05-31 22:22:48403 days ago1717194168IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.000235830.32187002
Register Policy60149602024-05-31 22:03:36403 days ago1717193016IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.000254050.34670001
Register Policy60149332024-05-31 21:56:48403 days ago1717192608IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.000251450.37874684
Register Policy60149312024-05-31 21:56:12403 days ago1717192572IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.000219940.36968492
Register Policy60148432024-05-31 21:35:00404 days ago1717191300IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.000332650.5011278
Register Policy60146992024-05-31 21:00:12404 days ago1717189212IN
0xeAABf2b8...c0F9bC9C2
0 ETH0.000591271.12422403
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:

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:
PILPolicyFrameworkManager

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 20000 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.23;

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

// contracts
import { IHookModule } from "../../interfaces/modules/base/IHookModule.sol";
import { ILicensingModule } from "../../interfaces/modules/licensing/ILicensingModule.sol";
import { Licensing } from "../../lib/Licensing.sol";
import { Errors } from "../../lib/Errors.sol";
import { PILFrameworkErrors } from "../../lib/PILFrameworkErrors.sol";
// solhint-disable-next-line max-line-length
import { IPILPolicyFrameworkManager, PILPolicy, PILAggregator, RegisterPILPolicyParams } from "../../interfaces/modules/licensing/IPILPolicyFrameworkManager.sol";
import { BasePolicyFrameworkManager } from "../../modules/licensing/BasePolicyFrameworkManager.sol";
import { LicensorApprovalChecker } from "../../modules/licensing/parameter-helpers/LicensorApprovalChecker.sol";

/// @title PILPolicyFrameworkManager
/// @notice PIL Policy Framework Manager implements the PIL Policy Framework logic for encoding and decoding PIL
/// policies into the LicenseRegistry and verifying the licensing parameters for linking, minting, and transferring.
contract PILPolicyFrameworkManager is
    IPILPolicyFrameworkManager,
    BasePolicyFrameworkManager,
    LicensorApprovalChecker,
    ReentrancyGuard
{
    using ERC165Checker for address;
    using Strings for *;

    /// @dev Hash of an empty string array
    bytes32 private constant _EMPTY_STRING_ARRAY_HASH =
        0x569e75fc77c1a856f6daaf9e69d8a9566ca34aa47f9133711ce065a571af0cfd;

    constructor(
        address accessController,
        address ipAccountRegistry,
        address licensing,
        string memory name_,
        string memory licenseUrl_
    )
        BasePolicyFrameworkManager(licensing, name_, licenseUrl_)
        LicensorApprovalChecker(
            accessController,
            ipAccountRegistry,
            address(ILicensingModule(licensing).LICENSE_REGISTRY())
        )
    {}

    /// @notice Registers a new policy to the registry
    /// @dev Internally, this function must generate a Licensing.Policy struct and call registerPolicy.
    /// @param params parameters needed to register a PILPolicy
    /// @return policyId The ID of the newly registered policy
    function registerPolicy(RegisterPILPolicyParams calldata params) external nonReentrant returns (uint256 policyId) {
        /// Minting fee amount & address checked in LicensingModule, no need to check here.
        /// We don't limit charging for minting to commercial use, you could sell a NC license in theory.
        _verifyComercialUse(params.policy, params.royaltyPolicy, params.mintingFee, params.mintingFeeToken);
        _verifyDerivatives(params.policy);
        /// TODO: DO NOT deploy on production networks without hashing string[] values instead of storing them

        Licensing.Policy memory pol = Licensing.Policy({
            isLicenseTransferable: params.transferable,
            policyFramework: address(this),
            frameworkData: abi.encode(params.policy),
            royaltyPolicy: params.royaltyPolicy,
            royaltyData: abi.encode(params.policy.commercialRevShare),
            mintingFee: params.mintingFee,
            mintingFeeToken: params.mintingFeeToken
        });
        // No need to emit here, as the LicensingModule will emit the event
        return LICENSING_MODULE.registerPolicy(pol);
    }

    /// @notice Verify policy parameters for linking a child IP to a parent IP (licensor) by burning a license NFT.
    /// @dev Enforced to be only callable by LicenseRegistry
    /// @param licenseId the license id to burn
    /// @param licensee the address that holds the license and is executing the linking
    /// @param ipId the IP id of the IP being linked
    /// @param parentIpId the IP id of the parent IP
    /// @param policyData the encoded framework policy data to verify
    /// @return verified True if the link is verified
    function verifyLink(
        uint256 licenseId,
        address licensee,
        address ipId,
        address parentIpId,
        bytes calldata policyData
    ) external override nonReentrant onlyLicensingModule returns (bool) {
        PILPolicy memory policy = abi.decode(policyData, (PILPolicy));

        // Trying to burn a license to create a derivative, when the license doesn't allow derivatives.
        if (!policy.derivativesAllowed) {
            return false;
        }

        // If the policy defines the licensor must approve derivatives, check if the
        // derivative is approved by the licensor
        if (policy.derivativesApproval && !isDerivativeApproved(licenseId, ipId)) {
            return false;
        }
        // Check if the commercializerChecker allows the link
        if (policy.commercializerChecker != address(0)) {
            // No need to check if the commercializerChecker supports the IHookModule interface, as it was checked
            // when the policy was registered.
            if (!IHookModule(policy.commercializerChecker).verify(licensee, policy.commercializerCheckerData)) {
                return false;
            }
        }
        return true;
    }

    /// @notice Verify policy parameters for minting a license.
    /// @dev Enforced to be only callable by LicenseRegistry
    /// @param licensee the address that holds the license and is executing the mint
    /// @param mintingFromADerivative true if the license is minting from a derivative IPA
    /// @param licensorIpId the IP id of the licensor
    /// @param receiver the address receiving the license
    /// @param mintAmount the amount of licenses to mint
    /// @param policyData the encoded framework policy data to verify
    /// @return verified True if the link is verified
    function verifyMint(
        address licensee,
        bool mintingFromADerivative,
        address licensorIpId,
        address receiver,
        uint256 mintAmount,
        bytes memory policyData
    ) external nonReentrant onlyLicensingModule returns (bool) {
        PILPolicy memory policy = abi.decode(policyData, (PILPolicy));
        // If the policy defines no reciprocal derivatives are allowed (no derivatives of derivatives),
        // and we are mintingFromADerivative we don't allow minting
        if (!policy.derivativesReciprocal && mintingFromADerivative) {
            return false;
        }

        if (policy.commercializerChecker != address(0)) {
            // No need to check if the commercializerChecker supports the IHookModule interface, as it was checked
            // when the policy was registered.
            if (!IHookModule(policy.commercializerChecker).verify(licensee, policy.commercializerCheckerData)) {
                return false;
            }
        }

        return true;
    }

    /// @notice Returns the aggregation data for inherited policies of an IP asset.
    /// @param ipId The ID of the IP asset to get the aggregator for
    /// @return rights The PILAggregator struct
    function getAggregator(address ipId) external view returns (PILAggregator memory rights) {
        bytes memory policyAggregatorData = LICENSING_MODULE.policyAggregatorData(address(this), ipId);
        if (policyAggregatorData.length == 0) {
            revert PILFrameworkErrors.PILPolicyFrameworkManager__RightsNotFound();
        }
        rights = abi.decode(policyAggregatorData, (PILAggregator));
    }

    /// @notice gets the PILPolicy for a given policy ID decoded from Licensing.Policy.frameworkData
    /// @dev Do not call this function from a smart contract, it is only for off-chain
    /// @param policyId The ID of the policy to get
    /// @return policy The PILPolicy struct
    function getPILPolicy(uint256 policyId) external view returns (PILPolicy memory policy) {
        Licensing.Policy memory pol = LICENSING_MODULE.policy(policyId);
        return abi.decode(pol.frameworkData, (PILPolicy));
    }

    /// @notice Verify compatibility of one or more policies when inheriting them from one or more parent IPs.
    /// @dev Enforced to be only callable by LicenseRegistry
    /// @dev The assumption in this method is that we can add parents later on, hence the need
    /// for an aggregator, if not we will do this when linking to parents directly with an
    /// array of policies.
    /// @param aggregator common state of the policies for the IP
    /// @param policyId the ID of the policy being inherited
    /// @param policy the policy to inherit
    /// @return changedAgg  true if the aggregator was changed
    /// @return newAggregator the new aggregator
    // solhint-disable-next-line code-complexity
    function processInheritedPolicies(
        bytes memory aggregator,
        uint256 policyId,
        bytes memory policy
    ) external view onlyLicensingModule returns (bool changedAgg, bytes memory newAggregator) {
        PILAggregator memory agg;
        PILPolicy memory newPolicy = abi.decode(policy, (PILPolicy));
        if (aggregator.length == 0) {
            // Initialize the aggregator
            agg = PILAggregator({
                commercial: newPolicy.commercialUse,
                derivativesReciprocal: newPolicy.derivativesReciprocal,
                lastPolicyId: policyId,
                territoriesAcc: keccak256(abi.encode(newPolicy.territories)),
                distributionChannelsAcc: keccak256(abi.encode(newPolicy.distributionChannels)),
                contentRestrictionsAcc: keccak256(abi.encode(newPolicy.contentRestrictions))
            });
            return (true, abi.encode(agg));
        } else {
            agg = abi.decode(aggregator, (PILAggregator));

            // Either all are reciprocal or none are
            if (agg.derivativesReciprocal != newPolicy.derivativesReciprocal) {
                revert PILFrameworkErrors.PILPolicyFrameworkManager__ReciprocalValueMismatch();
            } else if (agg.derivativesReciprocal && newPolicy.derivativesReciprocal) {
                // Ids are uniqued because we hash them to compare on creation in LicenseRegistry,
                // so we can compare the ids safely.
                if (agg.lastPolicyId != policyId) {
                    revert PILFrameworkErrors.PILPolicyFrameworkManager__ReciprocalButDifferentPolicyIds();
                }
            } else {
                // Both non reciprocal
                if (agg.commercial != newPolicy.commercialUse) {
                    revert PILFrameworkErrors.PILPolicyFrameworkManager__CommercialValueMismatch();
                }

                bytes32 newHash = _verifHashedParams(
                    agg.territoriesAcc,
                    keccak256(abi.encode(newPolicy.territories)),
                    _EMPTY_STRING_ARRAY_HASH
                );
                if (newHash != agg.territoriesAcc) {
                    agg.territoriesAcc = newHash;
                    changedAgg = true;
                }
                newHash = _verifHashedParams(
                    agg.distributionChannelsAcc,
                    keccak256(abi.encode(newPolicy.distributionChannels)),
                    _EMPTY_STRING_ARRAY_HASH
                );
                if (newHash != agg.distributionChannelsAcc) {
                    agg.distributionChannelsAcc = newHash;
                    changedAgg = true;
                }
                newHash = _verifHashedParams(
                    agg.contentRestrictionsAcc,
                    keccak256(abi.encode(newPolicy.contentRestrictions)),
                    _EMPTY_STRING_ARRAY_HASH
                );
                if (newHash != agg.contentRestrictionsAcc) {
                    agg.contentRestrictionsAcc = newHash;
                    changedAgg = true;
                }
            }
        }
        return (changedAgg, abi.encode(agg));
    }

    /// @notice Returns the stringified JSON policy data for the LicenseRegistry.uri(uint256) method.
    /// @dev Must return ERC1155 OpenSea standard compliant metadata.
    /// @param policyData The encoded licensing policy data to be decoded by the PFM
    /// @return jsonString The OpenSea-compliant metadata URI of the policy
    function policyToJson(bytes memory policyData) public pure returns (string memory) {
        PILPolicy memory policy = abi.decode(policyData, (PILPolicy));

        /* solhint-disable */
        // Follows the OpenSea standard for JSON metadata.
        // **Attributions**
        string memory json = string(
            abi.encodePacked(
                '{"trait_type": "Attribution", "value": "',
                policy.attribution ? "true" : "false",
                '"},',
                // Skip transferable, it's already added in the common attributes by the LicenseRegistry.
                // Should be managed by the LicenseRegistry, not the PFM.
                _policyCommercialTraitsToJson(policy),
                _policyDerivativeTraitsToJson(policy)
            )
        );

        json = string(abi.encodePacked(json, '{"trait_type": "Territories", "value": ['));
        uint256 count = policy.territories.length;
        for (uint256 i = 0; i < count; ++i) {
            json = string(abi.encodePacked(json, '"', policy.territories[i], '"'));
            if (i != count - 1) {
                // skip comma for last element in the array
                json = string(abi.encodePacked(json, ","));
            }
        }
        json = string(abi.encodePacked(json, "]},")); // close the trait_type: "Territories" array

        json = string(abi.encodePacked(json, '{"trait_type": "Distribution Channels", "value": ['));
        count = policy.distributionChannels.length;
        for (uint256 i = 0; i < count; ++i) {
            json = string(abi.encodePacked(json, '"', policy.distributionChannels[i], '"'));
            if (i != count - 1) {
                // skip comma for last element in the array
                json = string(abi.encodePacked(json, ","));
            }
        }
        json = string(abi.encodePacked(json, "]},")); // close the trait_type: "Distribution Channels" array

        // NOTE: (above) last trait added by PFM should have a comma at the end.

        /* solhint-enable */

        return json;
    }

    /// @dev Encodes the commercial traits of PIL policy into a JSON string for OpenSea
    /// @param policy The policy to encode
    function _policyCommercialTraitsToJson(PILPolicy memory policy) internal pure returns (string memory) {
        /* solhint-disable */
        // NOTE: TOTAL_RNFT_SUPPLY = 1000 in trait with max_value. For numbers, don't add any display_type, so that
        // they will show up in the "Ranking" section of the OpenSea UI.
        return
            string(
                abi.encodePacked(
                    '{"trait_type": "Commercial Use", "value": "',
                    policy.commercialUse ? "true" : "false",
                    '"},',
                    '{"trait_type": "Commercial Attribution", "value": "',
                    policy.commercialAttribution ? "true" : "false",
                    '"},',
                    '{"trait_type": "Commercial Revenue Share", "max_value": 1000, "value": ',
                    policy.commercialRevShare.toString(),
                    "},",
                    '{"trait_type": "Commercializer Check", "value": "',
                    policy.commercializerChecker.toHexString(),
                    // Skip on commercializerCheckerData as it's bytes as irrelevant for the user metadata
                    '"},'
                )
            );
        /* solhint-enable */
    }

    /// @dev Encodes the derivative traits of PIL policy into a JSON string for OpenSea
    /// @param policy The policy to encode
    function _policyDerivativeTraitsToJson(PILPolicy memory policy) internal pure returns (string memory) {
        /* solhint-disable */
        // NOTE: TOTAL_RNFT_SUPPLY = 1000 in trait with max_value. For numbers, don't add any display_type, so that
        // they will show up in the "Ranking" section of the OpenSea UI.
        return
            string(
                abi.encodePacked(
                    '{"trait_type": "Derivatives Allowed", "value": "',
                    policy.derivativesAllowed ? "true" : "false",
                    '"},',
                    '{"trait_type": "Derivatives Attribution", "value": "',
                    policy.derivativesAttribution ? "true" : "false",
                    '"},',
                    '{"trait_type": "Derivatives Approval", "value": "',
                    policy.derivativesApproval ? "true" : "false",
                    '"},',
                    '{"trait_type": "Derivatives Reciprocal", "value": "',
                    policy.derivativesReciprocal ? "true" : "false",
                    '"},'
                )
            );
        /* solhint-enable */
    }

    /// @dev Checks the configuration of commercial use and throws if the policy is not compliant
    /// @param policy The policy to verify
    /// @param royaltyPolicy The address of the royalty policy
    // solhint-disable-next-line code-complexity
    function _verifyComercialUse(
        PILPolicy calldata policy,
        address royaltyPolicy,
        uint256 mintingFee,
        address mintingFeeToken
    ) internal view {
        if (!policy.commercialUse) {
            if (policy.commercialAttribution) {
                revert PILFrameworkErrors.PILPolicyFrameworkManager__CommercialDisabled_CantAddAttribution();
            }
            if (policy.commercializerChecker != address(0)) {
                revert PILFrameworkErrors.PILPolicyFrameworkManager__CommercialDisabled_CantAddCommercializers();
            }
            if (policy.commercialRevShare > 0) {
                revert PILFrameworkErrors.PILPolicyFrameworkManager__CommercialDisabled_CantAddRevShare();
            }
            if (royaltyPolicy != address(0)) {
                revert PILFrameworkErrors.PILPolicyFrameworkManager__CommercialDisabled_CantAddRoyaltyPolicy();
            }
            if (mintingFee > 0) {
                revert PILFrameworkErrors.PILPolicyFrameworkManager__CommercialDisabled_CantAddMintingFee();
            }
            if (mintingFeeToken != address(0)) {
                revert PILFrameworkErrors.PILPolicyFrameworkManager__CommercialDisabled_CantAddMintingFeeToken();
            }
        } else {
            if (royaltyPolicy == address(0)) {
                revert PILFrameworkErrors.PILPolicyFrameworkManager__CommercialEnabled_RoyaltyPolicyRequired();
            }
            if (policy.commercializerChecker != address(0)) {
                if (!policy.commercializerChecker.supportsInterface(type(IHookModule).interfaceId)) {
                    revert Errors.PolicyFrameworkManager__CommercializerCheckerDoesNotSupportHook(
                        policy.commercializerChecker
                    );
                }
                IHookModule(policy.commercializerChecker).validateConfig(policy.commercializerCheckerData);
            }
        }
    }

    /// @notice Checks the configuration of derivative parameters and throws if the policy is not compliant
    /// @param policy The policy to verify
    function _verifyDerivatives(PILPolicy calldata policy) internal pure {
        if (!policy.derivativesAllowed) {
            if (policy.derivativesAttribution) {
                revert PILFrameworkErrors.PILPolicyFrameworkManager__DerivativesDisabled_CantAddAttribution();
            }
            if (policy.derivativesApproval) {
                revert PILFrameworkErrors.PILPolicyFrameworkManager__DerivativesDisabled_CantAddApproval();
            }
            if (policy.derivativesReciprocal) {
                revert PILFrameworkErrors.PILPolicyFrameworkManager__DerivativesDisabled_CantAddReciprocal();
            }
        }
    }

    /// @dev Verifies compatibility for params where the valid options are either permissive value, or equal params
    /// @param oldHash hash of the old param
    /// @param newHash hash of the new param
    /// @param permissive hash of the most permissive param
    /// @return result the hash that's different from the permissive hash
    function _verifHashedParams(
        bytes32 oldHash,
        bytes32 newHash,
        bytes32 permissive
    ) internal pure returns (bytes32 result) {
        if (oldHash == newHash) {
            return newHash;
        }
        if (oldHash != permissive && newHash != permissive) {
            revert PILFrameworkErrors.PILPolicyFrameworkManager__StringArrayMismatch();
        }
        if (oldHash != permissive) {
            return oldHash;
        }
        if (newHash != permissive) {
            return newHash;
        }
    }
}

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

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant HEX_DIGITS = "0123456789abcdef";
    uint8 private constant ADDRESS_LENGTH = 20;

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toStringSigned(int256 value) internal pure returns (string memory) {
        return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        uint256 localValue = value;
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = HEX_DIGITS[localValue & 0xf];
            localValue >>= 4;
        }
        if (localValue != 0) {
            revert StringsInsufficientHexLength(value, length);
        }
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
     * representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

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

pragma solidity ^0.8.20;

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

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

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

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

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

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

        return interfaceIdsSupported;
    }

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

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

        // all interfaces supported
        return true;
    }

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/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: BUSL-1.1
pragma solidity 0.8.23;

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

/// @notice Hook Module Interface
interface IHookModule is IModule {
    /// @notice Verify if the caller can pass the hook
    /// @param caller The address of the caller
    /// @param data The arbitrary data to be verified
    /// @return bool Whether or not the caller has passed the hook's verification
    function verify(address caller, bytes calldata data) external returns (bool);

    /// @notice Validates the configuration for the hook.
    /// @param configData The configuration data for the hook.
    function validateConfig(bytes calldata configData) external view;
}

// 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);
}

File 7 of 42 : 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
    }
}

File 8 of 42 : 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 9 of 42 : PILFrameworkErrors.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

/// @title PILFrameworkErrors Errors Library
/// @notice Library for all PILFramework related contract errors.
library PILFrameworkErrors {
    ////////////////////////////////////////////////////////////////////////////
    //                         PILPolicyFrameworkManager                      //
    ////////////////////////////////////////////////////////////////////////////

    error PILPolicyFrameworkManager__CommercialDisabled_CantAddAttribution();
    error PILPolicyFrameworkManager__CommercialDisabled_CantAddCommercializers();
    error PILPolicyFrameworkManager__CommercialDisabled_CantAddRevShare();
    error PILPolicyFrameworkManager__DerivativesDisabled_CantAddAttribution();
    error PILPolicyFrameworkManager__DerivativesDisabled_CantAddApproval();
    error PILPolicyFrameworkManager__DerivativesDisabled_CantAddReciprocal();
    error PILPolicyFrameworkManager__RightsNotFound();
    error PILPolicyFrameworkManager__CommercialDisabled_CantAddRoyaltyPolicy();
    error PILPolicyFrameworkManager__CommercialEnabled_RoyaltyPolicyRequired();
    error PILPolicyFrameworkManager__ReciprocalButDifferentPolicyIds();
    error PILPolicyFrameworkManager__ReciprocalValueMismatch();
    error PILPolicyFrameworkManager__CommercialValueMismatch();
    error PILPolicyFrameworkManager__StringArrayMismatch();
    error PILPolicyFrameworkManager__CommercialDisabled_CantAddMintingFee();
    error PILPolicyFrameworkManager__CommercialDisabled_CantAddMintingFeeToken();
}

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

import { IPolicyFrameworkManager } from "../../../interfaces/modules/licensing/IPolicyFrameworkManager.sol";

/// @notice Licensing parameters for the Programmable IP License v1 (PIL) standard
/// @param transferable Whether or not the license is transferable
/// @param attribution Whether or not attribution is required when reproducing the work
/// @param commercialUse Whether or not the work can be used commercially
/// @param commercialAttribution Whether or not attribution is required when reproducing the work commercially
/// @param commercializerChecker commercializers that are allowed to commercially exploit the work. If zero address,
/// then no restrictions is enforced.
/// @param commercialRevShare Percentage of revenue that must be shared with the licensor
/// @param derivativesAllowed Whether or not the licensee can create derivatives of his work
/// @param derivativesAttribution Whether or not attribution is required for derivatives of the work
/// @param derivativesApproval Whether or not the licensor must approve derivatives of the work before they can be
/// linked to the licensor IP ID
/// @param derivativesReciprocal Whether or not the licensee must license derivatives of the work under the same terms.
/// @param territories List of territories where the license is valid. If empty, global.
/// @param distributionChannels List of distribution channels where the license is valid. Empty if no restrictions.
/// @param contentRestrictions List of content restrictions. Empty if no restrictions.
/// TODO: DO NOT deploy on production networks without hashing string[] instead of storing them
struct PILPolicy {
    bool attribution;
    bool commercialUse;
    bool commercialAttribution;
    address commercializerChecker;
    bytes commercializerCheckerData;
    uint32 commercialRevShare;
    bool derivativesAllowed;
    bool derivativesAttribution;
    bool derivativesApproval;
    bool derivativesReciprocal;
    string[] territories;
    string[] distributionChannels;
    string[] contentRestrictions;
}

/// @param transferable Whether or not the license is transferable
/// @param royaltyPolicy Address of a royalty policy contract (e.g. RoyaltyPolicyLS) that will handle royalty payments
/// @param mintingFee Fee to be paid when minting a license
/// @param mintingFeeToken Token to be used to pay the minting fee
/// @param policy PILPolicy compliant licensing term values
struct RegisterPILPolicyParams {
    bool transferable;
    address royaltyPolicy;
    uint256 mintingFee;
    address mintingFeeToken;
    PILPolicy policy;
}

/// @notice Struct that accumulates values of inherited policies so we can verify compatibility when inheriting
/// new policies.
/// @dev The assumption is that new policies may be added later, not only when linking an IP to its parent.
/// @param commercial Whether or not there is a policy that allows commercial use
/// @param derivativesReciprocal Whether or not there is a policy that requires derivatives to be licensed under the
/// same terms
/// @param lastPolicyId The last policy ID that was added to the IP
/// @param territoriesAcc The last hash of the territories array
/// @param distributionChannelsAcc The last hash of the distributionChannels array
/// @param contentRestrictionsAcc The last hash of the contentRestrictions array
struct PILAggregator {
    bool commercial;
    bool derivativesReciprocal;
    uint256 lastPolicyId;
    bytes32 territoriesAcc;
    bytes32 distributionChannelsAcc;
    bytes32 contentRestrictionsAcc;
}

/// @title IPILPolicyFrameworkManager
/// @notice Defines the interface for a Policy Framework Manager compliant with the PIL standard
interface IPILPolicyFrameworkManager is IPolicyFrameworkManager {
    /// @notice Registers a new policy to the registry
    /// @dev Internally, this function must generate a Licensing.Policy struct and call registerPolicy.
    /// @param params parameters needed to register a PILPolicy
    /// @return policyId The ID of the newly registered policy
    function registerPolicy(RegisterPILPolicyParams calldata params) external returns (uint256 policyId);

    /// @notice Returns the aggregation data for inherited policies of an IP asset.
    /// @param ipId The ID of the IP asset to get the aggregator for
    /// @return rights The PILAggregator struct
    function getAggregator(address ipId) external view returns (PILAggregator memory rights);

    /// @notice gets the PILPolicy for a given policy ID decoded from Licensing.Policy.frameworkData
    /// @dev Do not call this function from a smart contract, it is only for off-chain
    /// @param policyId The ID of the policy to get
    /// @return policy The PILPolicy struct
    function getPILPolicy(uint256 policyId) external view returns (PILPolicy memory policy);
}

File 11 of 42 : BasePolicyFrameworkManager.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

// external
import { ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
// contracts
import { IPolicyFrameworkManager } from "../../interfaces/modules/licensing/IPolicyFrameworkManager.sol";
import { LicensingModuleAware } from "../../modules/licensing/LicensingModuleAware.sol";

/// @title BasePolicyFrameworkManager
/// @notice Base contract for policy framework managers.
abstract contract BasePolicyFrameworkManager is IPolicyFrameworkManager, ERC165, LicensingModuleAware {
    /// @notice Returns the name to be show in license NFT (LNFT) metadata
    string public override name;

    /// @notice Returns the URL to the off chain legal agreement template text
    string public override licenseTextUrl;

    constructor(address licensing, string memory name_, string memory licenseTextUrl_) LicensingModuleAware(licensing) {
        name = name_;
        licenseTextUrl = licenseTextUrl_;
    }

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

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

import { AccessControlled } from "../../../access/AccessControlled.sol";
import { ILicenseRegistry } from "../../../interfaces/registries/ILicenseRegistry.sol";

/// @title LicensorApprovalChecker
/// @notice Manages the approval of derivative IP accounts by the licensor. Used to verify
/// licensing terms like "Derivatives With Approval" in PIL.
abstract contract LicensorApprovalChecker is AccessControlled {
    /// @notice Emits when a derivative IP account is approved by the licensor.
    /// @param licenseId The ID of the license waiting for approval
    /// @param ipId The ID of the derivative IP to be approved
    /// @param caller The executor of the approval
    /// @param approved Result of the approval
    event DerivativeApproved(uint256 indexed licenseId, address indexed ipId, address indexed caller, bool approved);

    /// @notice Returns the license registry address
    ILicenseRegistry public immutable LICENSE_REGISTRY;

    /// @notice Approvals for derivative IP.
    /// @dev License Id => licensor => childIpId => approved
    mapping(uint256 => mapping(address => mapping(address => bool))) private _approvals;

    constructor(
        address accessController,
        address ipAccountRegistry,
        address licenseRegistry
    ) AccessControlled(accessController, ipAccountRegistry) {
        LICENSE_REGISTRY = ILicenseRegistry(licenseRegistry);
    }

    /// @notice Approves or disapproves a derivative IP account.
    /// @param licenseId The ID of the license waiting for approval
    /// @param childIpId The ID of the derivative IP to be approved
    /// @param approved Result of the approval
    function setApproval(uint256 licenseId, address childIpId, bool approved) external {
        address licensorIpId = LICENSE_REGISTRY.licensorIpId(licenseId);
        _setApproval(licensorIpId, licenseId, childIpId, approved);
    }

    /// @notice Checks if a derivative IP account is approved by the licensor.
    /// @param licenseId The ID of the license NFT issued from a policy of the licensor
    /// @param childIpId The ID of the derivative IP to be approved
    /// @return approved True if the derivative IP account using the license is approved
    function isDerivativeApproved(uint256 licenseId, address childIpId) public view returns (bool) {
        address licensorIpId = LICENSE_REGISTRY.licensorIpId(licenseId);
        return _approvals[licenseId][licensorIpId][childIpId];
    }

    /// @notice Sets the approval for a derivative IP account.
    /// @dev This function is only callable by the licensor IP account.
    /// @param licensorIpId The ID of the licensor IP account
    /// @param licenseId The ID of the license waiting for approval
    /// @param childIpId The ID of the derivative IP to be approved
    /// @param approved Result of the approval
    function _setApproval(
        address licensorIpId,
        uint256 licenseId,
        address childIpId,
        bool approved
    ) internal verifyPermission(licensorIpId) {
        _approvals[licenseId][licensorIpId][childIpId] = approved;
        emit DerivativeApproved(licenseId, licensorIpId, msg.sender, approved);
    }
}

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

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

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

pragma solidity ^0.8.20;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

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

pragma solidity ^0.8.20;

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

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

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

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

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

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;

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

/// @title IPolicyFrameworkManager
/// @notice Interface to define a policy framework contract, that will register itself into the LicenseRegistry to
/// format policy into the LicenseRegistry
interface IPolicyFrameworkManager is IERC165 {
    /// @notice Name to be show in LNFT metadata
    function name() external view returns (string memory);

    /// @notice Returns the URL to the off chain legal agreement template text
    function licenseTextUrl() external view returns (string memory);

    /// @notice Returns the stringified JSON policy data for the LicenseRegistry.uri(uint256) method.
    /// @dev Must return ERC1155 OpenSea standard compliant metadata.
    /// @param policyData The encoded licensing policy data to be decoded by the PFM
    /// @return jsonString The OpenSea-compliant metadata URI of the policy
    function policyToJson(bytes memory policyData) external view returns (string memory);

    /// @notice Verify compatibility of one or more policies when inheriting them from one or more parent IPs.
    /// @dev Enforced to be only callable by LicenseRegistry
    /// @dev The assumption in this method is that we can add parents later on, hence the need
    /// for an aggregator, if not we will do this when linking to parents directly with an
    /// array of policies.
    /// @param aggregator common state of the policies for the IP
    /// @param policyId the ID of the policy being inherited
    /// @param policy the policy to inherit
    /// @return changedAgg  true if the aggregator was changed
    /// @return newAggregator the new aggregator
    function processInheritedPolicies(
        bytes memory aggregator,
        uint256 policyId,
        bytes memory policy
    ) external view returns (bool changedAgg, bytes memory newAggregator);

    /// @notice Verify policy parameters for minting a license.
    /// @dev Enforced to be only callable by LicenseRegistry
    /// @param licensee the address that holds the license and is executing the mint
    /// @param mintingFromADerivative true if we verify minting a license from a derivative IP ID
    /// @param receiver the address receiving the license
    /// @param licensorIpId the IP id of the licensor
    /// @param mintAmount the amount of licenses to mint
    /// @param policyData the encoded framework policy data to verify
    /// @return verified True if the link is verified
    function verifyMint(
        address licensee,
        bool mintingFromADerivative,
        address licensorIpId,
        address receiver,
        uint256 mintAmount,
        bytes memory policyData
    ) external returns (bool);

    /// @notice Verify policy parameters for linking a child IP to a parent IP (licensor) by burning a license NFT.
    /// @dev Enforced to be only callable by LicenseRegistry
    /// @param licenseId the license id to burn
    /// @param licensee the address that holds the license and is executing the link
    /// @param ipId the IP id of the IP being linked
    /// @param parentIpId the IP id of the parent IP
    /// @param policyData the encoded framework policy data to verify
    /// @return verified True if the link is verified
    function verifyLink(
        uint256 licenseId,
        address licensee,
        address ipId,
        address parentIpId,
        bytes calldata policyData
    ) external returns (bool);
}

// 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;
    }
}

File 22 of 42 : LicensingModuleAware.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

// contracts
import { ILicensingModule } from "../../interfaces/modules/licensing/ILicensingModule.sol";
import { Errors } from "../../lib/Errors.sol";

/// @title LicensingModuleAware
/// @notice Base contract to be inherited by modules that need to access the licensing module.
abstract contract LicensingModuleAware {
    /// @notice Returns the protocol-wide licensing module.
    ILicensingModule public immutable LICENSING_MODULE;

    constructor(address licensingModule) {
        LICENSING_MODULE = ILicensingModule(licensingModule);
    }

    /// @notice Modifier for authorizing the calling entity to only the LicensingModule.
    modifier onlyLicensingModule() {
        if (msg.sender != address(LICENSING_MODULE)) {
            revert Errors.LicensingModuleAware__CallerNotLicensingModule();
        }
        _;
    }
}

// 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;
        }
    }
}

File 24 of 42 : 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 { 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;
}

File 28 of 42 : 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";

// 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;
}

File 30 of 42 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity ^0.8.20;

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

// 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;

/// @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;

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 36 of 42 : 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 37 of 42 : 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 41 of 42 : 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":"accessController","type":"address"},{"internalType":"address","name":"ipAccountRegistry","type":"address"},{"internalType":"address","name":"licensing","type":"address"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"licenseUrl_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"ipAccount","type":"address"}],"name":"AccessControlled__NotIpAccount","type":"error"},{"inputs":[],"name":"AccessControlled__ZeroAddress","type":"error"},{"inputs":[],"name":"LicensingModuleAware__CallerNotLicensingModule","type":"error"},{"inputs":[],"name":"PILPolicyFrameworkManager__CommercialDisabled_CantAddAttribution","type":"error"},{"inputs":[],"name":"PILPolicyFrameworkManager__CommercialDisabled_CantAddCommercializers","type":"error"},{"inputs":[],"name":"PILPolicyFrameworkManager__CommercialDisabled_CantAddMintingFee","type":"error"},{"inputs":[],"name":"PILPolicyFrameworkManager__CommercialDisabled_CantAddMintingFeeToken","type":"error"},{"inputs":[],"name":"PILPolicyFrameworkManager__CommercialDisabled_CantAddRevShare","type":"error"},{"inputs":[],"name":"PILPolicyFrameworkManager__CommercialDisabled_CantAddRoyaltyPolicy","type":"error"},{"inputs":[],"name":"PILPolicyFrameworkManager__CommercialEnabled_RoyaltyPolicyRequired","type":"error"},{"inputs":[],"name":"PILPolicyFrameworkManager__CommercialValueMismatch","type":"error"},{"inputs":[],"name":"PILPolicyFrameworkManager__DerivativesDisabled_CantAddApproval","type":"error"},{"inputs":[],"name":"PILPolicyFrameworkManager__DerivativesDisabled_CantAddAttribution","type":"error"},{"inputs":[],"name":"PILPolicyFrameworkManager__DerivativesDisabled_CantAddReciprocal","type":"error"},{"inputs":[],"name":"PILPolicyFrameworkManager__ReciprocalButDifferentPolicyIds","type":"error"},{"inputs":[],"name":"PILPolicyFrameworkManager__ReciprocalValueMismatch","type":"error"},{"inputs":[],"name":"PILPolicyFrameworkManager__RightsNotFound","type":"error"},{"inputs":[],"name":"PILPolicyFrameworkManager__StringArrayMismatch","type":"error"},{"inputs":[{"internalType":"address","name":"commercializer","type":"address"}],"name":"PolicyFrameworkManager__CommercializerCheckerDoesNotSupportHook","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"length","type":"uint256"}],"name":"StringsInsufficientHexLength","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"licenseId","type":"uint256"},{"indexed":true,"internalType":"address","name":"ipId","type":"address"},{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"DerivativeApproved","type":"event"},{"inputs":[],"name":"ACCESS_CONTROLLER","outputs":[{"internalType":"contract IAccessController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"IP_ACCOUNT_REGISTRY","outputs":[{"internalType":"contract IIPAccountRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LICENSE_REGISTRY","outputs":[{"internalType":"contract ILicenseRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LICENSING_MODULE","outputs":[{"internalType":"contract ILicensingModule","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"ipId","type":"address"}],"name":"getAggregator","outputs":[{"components":[{"internalType":"bool","name":"commercial","type":"bool"},{"internalType":"bool","name":"derivativesReciprocal","type":"bool"},{"internalType":"uint256","name":"lastPolicyId","type":"uint256"},{"internalType":"bytes32","name":"territoriesAcc","type":"bytes32"},{"internalType":"bytes32","name":"distributionChannelsAcc","type":"bytes32"},{"internalType":"bytes32","name":"contentRestrictionsAcc","type":"bytes32"}],"internalType":"struct PILAggregator","name":"rights","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"policyId","type":"uint256"}],"name":"getPILPolicy","outputs":[{"components":[{"internalType":"bool","name":"attribution","type":"bool"},{"internalType":"bool","name":"commercialUse","type":"bool"},{"internalType":"bool","name":"commercialAttribution","type":"bool"},{"internalType":"address","name":"commercializerChecker","type":"address"},{"internalType":"bytes","name":"commercializerCheckerData","type":"bytes"},{"internalType":"uint32","name":"commercialRevShare","type":"uint32"},{"internalType":"bool","name":"derivativesAllowed","type":"bool"},{"internalType":"bool","name":"derivativesAttribution","type":"bool"},{"internalType":"bool","name":"derivativesApproval","type":"bool"},{"internalType":"bool","name":"derivativesReciprocal","type":"bool"},{"internalType":"string[]","name":"territories","type":"string[]"},{"internalType":"string[]","name":"distributionChannels","type":"string[]"},{"internalType":"string[]","name":"contentRestrictions","type":"string[]"}],"internalType":"struct PILPolicy","name":"policy","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"licenseId","type":"uint256"},{"internalType":"address","name":"childIpId","type":"address"}],"name":"isDerivativeApproved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"licenseTextUrl","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"policyData","type":"bytes"}],"name":"policyToJson","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"aggregator","type":"bytes"},{"internalType":"uint256","name":"policyId","type":"uint256"},{"internalType":"bytes","name":"policy","type":"bytes"}],"name":"processInheritedPolicies","outputs":[{"internalType":"bool","name":"changedAgg","type":"bool"},{"internalType":"bytes","name":"newAggregator","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"transferable","type":"bool"},{"internalType":"address","name":"royaltyPolicy","type":"address"},{"internalType":"uint256","name":"mintingFee","type":"uint256"},{"internalType":"address","name":"mintingFeeToken","type":"address"},{"components":[{"internalType":"bool","name":"attribution","type":"bool"},{"internalType":"bool","name":"commercialUse","type":"bool"},{"internalType":"bool","name":"commercialAttribution","type":"bool"},{"internalType":"address","name":"commercializerChecker","type":"address"},{"internalType":"bytes","name":"commercializerCheckerData","type":"bytes"},{"internalType":"uint32","name":"commercialRevShare","type":"uint32"},{"internalType":"bool","name":"derivativesAllowed","type":"bool"},{"internalType":"bool","name":"derivativesAttribution","type":"bool"},{"internalType":"bool","name":"derivativesApproval","type":"bool"},{"internalType":"bool","name":"derivativesReciprocal","type":"bool"},{"internalType":"string[]","name":"territories","type":"string[]"},{"internalType":"string[]","name":"distributionChannels","type":"string[]"},{"internalType":"string[]","name":"contentRestrictions","type":"string[]"}],"internalType":"struct PILPolicy","name":"policy","type":"tuple"}],"internalType":"struct RegisterPILPolicyParams","name":"params","type":"tuple"}],"name":"registerPolicy","outputs":[{"internalType":"uint256","name":"policyId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"licenseId","type":"uint256"},{"internalType":"address","name":"childIpId","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"licenseId","type":"uint256"},{"internalType":"address","name":"licensee","type":"address"},{"internalType":"address","name":"ipId","type":"address"},{"internalType":"address","name":"parentIpId","type":"address"},{"internalType":"bytes","name":"policyData","type":"bytes"}],"name":"verifyLink","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"licensee","type":"address"},{"internalType":"bool","name":"mintingFromADerivative","type":"bool"},{"internalType":"address","name":"licensorIpId","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"mintAmount","type":"uint256"},{"internalType":"bytes","name":"policyData","type":"bytes"}],"name":"verifyMint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]

6101006040523480156200001257600080fd5b506040516200434f3803806200434f83398101604081905262000035916200022b565b8484846001600160a01b031663f0ebdc836040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000076573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009c9190620002d6565b6001600160a01b03861660805282828787876000620000bc83826200038e565b506001620000cb82826200038e565b5050506001600160a01b0383169050620000f8576040516320a816ad60e01b815260040160405180910390fd5b6001600160a01b03811662000120576040516320a816ad60e01b815260040160405180910390fd5b6001600160a01b0391821660a052811660c0521660e05250506001600355506200045a9350505050565b6001600160a01b03811681146200016057600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200018b57600080fd5b81516001600160401b0380821115620001a857620001a862000163565b604051601f8301601f19908116603f01168101908282118183101715620001d357620001d362000163565b8160405283815260209250866020858801011115620001f157600080fd5b600091505b83821015620002155785820183015181830184015290820190620001f6565b6000602085830101528094505050505092915050565b600080600080600060a086880312156200024457600080fd5b855162000251816200014a565b602087015190955062000264816200014a565b604087015190945062000277816200014a565b60608701519093506001600160401b03808211156200029557600080fd5b620002a389838a0162000179565b93506080880151915080821115620002ba57600080fd5b50620002c98882890162000179565b9150509295509295909350565b600060208284031215620002e957600080fd5b8151620002f6816200014a565b9392505050565b600181811c908216806200031257607f821691505b6020821081036200033357634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000389576000816000526020600020601f850160051c81016020861015620003645750805b601f850160051c820191505b81811015620003855782815560010162000370565b5050505b505050565b81516001600160401b03811115620003aa57620003aa62000163565b620003c281620003bb8454620002fd565b8462000339565b602080601f831160018114620003fa5760008415620003e15750858301515b600019600386901b1c1916600185901b17855562000385565b600085815260208120601f198616915b828110156200042b578886015182559484019460019091019084016200040a565b50858210156200044a5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e051613e75620004da6000396000818161030f01528181610ede0152610fbb01526000818161025f0152611dbd0152600081816101680152611f3001526000818161023801528181610474015281816109fa01528181610b2401528181610c9801528181610d5001526113110152613e756000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c8063af0b2eaf11610097578063e1ecbde311610066578063e1ecbde3146102d1578063eb6b3315146102e4578063f02a3111146102f7578063f0ebdc831461030a57600080fd5b8063af0b2eaf14610281578063c75e9a59146102a1578063cd6f464d146102a9578063dc96e2aa146102bc57600080fd5b80632421d9a4116100d35780632421d9a4146101af57806329a42d56146101d057806365165aa514610233578063702acd851461025a57600080fd5b806301ffc9a71461010557806306fdde031461012d5780631b00c800146101425780631b8b107314610163575b600080fd5b6101186101133660046124ab565b610331565b60405190151581526020015b60405180910390f35b6101356103ca565b604051610124919061253d565b610155610150366004612683565b610458565b6040516101249291906126f0565b61018a7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610124565b6101c26101bd36600461270b565b61089f565b604051908152602001610124565b6101e36101de366004612773565b610aa6565b6040516101249190600060c08201905082511515825260208301511515602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b61018a7f000000000000000000000000000000000000000000000000000000000000000081565b61018a7f000000000000000000000000000000000000000000000000000000000000000081565b61029461028f366004612790565b610beb565b6040516101249190612803565b610135610d21565b6101186102b7366004612953565b610d2e565b6102cf6102ca3660046129e3565b610eac565b005b6101186102df366004612a25565b610f72565b6101356102f2366004612a55565b61106b565b610118610305366004612a8a565b6112ef565b61018a7f000000000000000000000000000000000000000000000000000000000000000081565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f0c8dc8130000000000000000000000000000000000000000000000000000000014806103c457507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b600080546103d790612b3d565b80601f016020809104026020016040519081016040528092919081815260200182805461040390612b3d565b80156104505780601f1061042557610100808354040283529160200191610450565b820191906000526020600020905b81548152906001019060200180831161043357829003601f168201915b505050505081565b600060603373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146104cb576040517f4343348300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091526000848060200190518101906105139190612cd7565b9050865160000361064b576040518060c001604052808260200151151581526020018261012001511515815260200187815260200182610140015160405160200161055e9190612e54565b60405160208183030381529060405280519060200120815260200182610160015160405160200161058f9190612e54565b6040516020818303038152906040528051906020012081526020018261018001516040516020016105c09190612e54565b6040516020818303038152906040528051906020012081525091506001826040516020016106319190600060c08201905082511515825260208301511515602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b604051602081830303815290604052935093505050610897565b8680602001905181019061065f9190612e67565b9150806101200151151582602001511515146106a7576040517f3b53932500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816020015180156106ba57508061012001515b1561070157858260400151146106fc576040517f5ba8230300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61082c565b60208101518251151590151514610744576040517f0b63cb3100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006107a383606001518361014001516040516020016107649190612e54565b604051602081830303815290604052805190602001207f569e75fc77c1a856f6daaf9e69d8a9566ca34aa47f9133711ce065a571af0cfd60001b611416565b9050826060015181146107bc5760608301819052600194505b6107da83608001518361016001516040516020016107649190612e54565b9050826080015181146107f35760808301819052600194505b6108118360a001518361018001516040516020016107649190612e54565b90508260a00151811461082a5760a08301819052600194505b505b83826040516020016108819190600060c08201905082511515825260208301511515602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b6040516020818303038152906040529350935050505b935093915050565b60006108a961148a565b6108e36108b96080840184612ef3565b6108c96040850160208601612773565b60408501356108de6080870160608801612773565b6114cd565b6108f86108f36080840184612ef3565b611869565b6040805160e08101909152600090806109146020860186612f31565b1515815230602082015260400161092e6080860186612ef3565b60405160200161093e91906130aa565b60405160208183030381529060405281526020018460200160208101906109659190612773565b73ffffffffffffffffffffffffffffffffffffffff16815260200161098d6080860186612ef3565b61099e9060c081019060a001613246565b6040805163ffffffff90921660208301520160408051601f19818403018152918152908252858101356020830152016109dd6080860160608701612773565b73ffffffffffffffffffffffffffffffffffffffff1681525090507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663032e1860826040518263ffffffff1660e01b8152600401610a519190613263565b6020604051808303816000875af1158015610a70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a94919061330e565b915050610aa16001600355565b919050565b6040805160c081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905291517f30d9113600000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff84811660248301529192917f000000000000000000000000000000000000000000000000000000000000000016906330d9113690604401600060405180830381865afa158015610b6b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b939190810190613327565b90508051600003610bd0576040517fc64675f600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80806020019051810190610be49190612e67565b9392505050565b604080516101a08101825260008082526020820181905281830181905260608083018290526080830181905260a0830182905260c0830182905260e08301829052610100830182905261012083018290526101408301819052610160830181905261018083015291517f3cea51200000000000000000000000000000000000000000000000000000000081526004810184905290919073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690633cea512090602401600060405180830381865afa158015610cdf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d07919081019061335c565b90508060400151806020019051810190610be49190612cd7565b600180546103d790612b3d565b6000610d3861148a565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610da7576040517f4343348300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082806020019051810190610dbd9190612cd7565b9050806101200151158015610dcf5750865b15610dde576000915050610e98565b606081015173ffffffffffffffffffffffffffffffffffffffff1615610e9257806060015173ffffffffffffffffffffffffffffffffffffffff16634a41d1ac8983608001516040518363ffffffff1660e01b8152600401610e4192919061343b565b6020604051808303816000875af1158015610e60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e84919061346a565b610e92576000915050610e98565b60019150505b610ea26001600355565b9695505050505050565b6040517f34d70eea000000000000000000000000000000000000000000000000000000008152600481018490526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906334d70eea90602401602060405180830381865afa158015610f3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5e9190613487565b9050610f6c8185858561195a565b50505050565b6040517f34d70eea00000000000000000000000000000000000000000000000000000000815260048101839052600090819073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906334d70eea90602401602060405180830381865afa158015611002573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110269190613487565b600094855260026020908152604080872073ffffffffffffffffffffffffffffffffffffffff9384168852825280872095909216865293909352505090205460ff1690565b60606000828060200190518101906110839190612cd7565b9050600081600001516110cb576040518060400160405280600581526020017f66616c7365000000000000000000000000000000000000000000000000000000815250611102565b6040518060400160405280600481526020017f74727565000000000000000000000000000000000000000000000000000000008152505b61110b83611a0a565b61111484611b61565b604051602001611126939291906134c0565b604051602081830303815290604052905080604051602001611148919061357e565b60408051601f198184030181529190526101408301515190915060005b818110156111ec57828461014001518281518110611185576111856135e5565b602002602001015160405160200161119e929190613614565b60408051601f1981840301815291905292506111bb6001836136a4565b81146111e457826040516020016111d291906136b7565b60405160208183030381529060405292505b600101611165565b50816040516020016111fe91906136f8565b6040516020818303038152906040529150816040516020016112209190613739565b604051602081830303815290604052915082610160015151905060005b818110156112c45782846101600151828151811061125d5761125d6135e5565b6020026020010151604051602001611276929190613614565b60408051601f1981840301815291905292506112936001836136a4565b81146112bc57826040516020016112aa91906136b7565b60405160208183030381529060405292505b60010161123d565b50816040516020016112d691906136f8565b60408051601f1981840301815291905295945050505050565b60006112f961148a565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611368576040517f4343348300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061137683850185613835565b90508060c0015161138b576000915050610e98565b80610100015180156113a457506113a28887610f72565b155b156113b3576000915050610e98565b606081015173ffffffffffffffffffffffffffffffffffffffff1615610e9257806060015173ffffffffffffffffffffffffffffffffffffffff16634a41d1ac8883608001516040518363ffffffff1660e01b8152600401610e4192919061343b565b6000828403611426575081610be4565b8184141580156114365750818314155b1561146d576040517fe12ebaba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81841461147b575082610be4565b818314610be457509092915050565b6002600354036114c6576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600355565b6114dd6040850160208601612f31565b6116b0576114f16060850160408601612f31565b15611528576040517f7397bbaa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061153a6080860160608701612773565b73ffffffffffffffffffffffffffffffffffffffff1614611587576040517fc1f0a67d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061159960c0860160a08701613246565b63ffffffff1611156115d7576040517f529c886000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff831615611625576040517f3f63513800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b811561165d576040517f0cb7b17500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116156116ab576040517f88fb4f2f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f6c565b73ffffffffffffffffffffffffffffffffffffffff83166116fd576040517f7660ada600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061170f6080860160608701612773565b73ffffffffffffffffffffffffffffffffffffffff1614610f6c5761177a7fe352692d0000000000000000000000000000000000000000000000000000000061175e6080870160608801612773565b73ffffffffffffffffffffffffffffffffffffffff1690611d64565b6117de5761178e6080850160608601612773565b6040517f5f72721800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024015b60405180910390fd5b6117ee6080850160608601612773565b73ffffffffffffffffffffffffffffffffffffffff1663a913b88161181660808701876139a1565b6040518363ffffffff1660e01b8152600401611833929190613a06565b60006040518083038186803b15801561184b57600080fd5b505afa15801561185f573d6000803e3d6000fd5b5050505050505050565b61187960e0820160c08301612f31565b6119575761188e610100820160e08301612f31565b156118c5576040517f550c495200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6118d761012082016101008301612f31565b1561190e576040517f0891883b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61192061014082016101208301612f31565b15611957576040517f209f573300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b8361196481611d80565b600084815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff898116808652918452828520908816855283529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016861515908117909155905190815233929187917f436fd071b1745141646f97213ec7dd4b24e735af0c49bd6d047186c995cc10cc910160405180910390a45050505050565b60608160200151611a50576040518060400160405280600581526020017f66616c7365000000000000000000000000000000000000000000000000000000815250611a87565b6040518060400160405280600481526020017f74727565000000000000000000000000000000000000000000000000000000008152505b8260400151611acb576040518060400160405280600581526020017f66616c7365000000000000000000000000000000000000000000000000000000815250611b02565b6040518060400160405280600481526020017f74727565000000000000000000000000000000000000000000000000000000008152505b611b158460a0015163ffffffff16611f8d565b611b38856060015173ffffffffffffffffffffffffffffffffffffffff1661204c565b604051602001611b4b9493929190613a1a565b6040516020818303038152906040529050919050565b60608160c00151611ba7576040518060400160405280600581526020017f66616c7365000000000000000000000000000000000000000000000000000000815250611bde565b6040518060400160405280600481526020017f74727565000000000000000000000000000000000000000000000000000000008152505b8260e00151611c22576040518060400160405280600581526020017f66616c7365000000000000000000000000000000000000000000000000000000815250611c59565b6040518060400160405280600481526020017f74727565000000000000000000000000000000000000000000000000000000008152505b836101000151611c9e576040518060400160405280600581526020017f66616c7365000000000000000000000000000000000000000000000000000000815250611cd5565b6040518060400160405280600481526020017f74727565000000000000000000000000000000000000000000000000000000008152505b846101200151611d1a576040518060400160405280600581526020017f66616c7365000000000000000000000000000000000000000000000000000000815250611d51565b6040518060400160405280600481526020017f74727565000000000000000000000000000000000000000000000000000000008152505b604051602001611b4b9493929190613c3d565b6000611d6f8361206f565b8015610be45750610be483836120d3565b6040517f5a1c2dd700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081166004830152821660248201527336e93affeca875ebcef53e922a4b716ad2a508a990635a1c2dd790604401602060405180830381865af4158015611e26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e4a919061346a565b611e98576040517fd64edf9000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016117d5565b3373ffffffffffffffffffffffffffffffffffffffff821614611957576040517f7dfd0ddb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301523360248301523060448301526000357fffffffff000000000000000000000000000000000000000000000000000000001660648301527f00000000000000000000000000000000000000000000000000000000000000001690637dfd0ddb9060840160006040518083038186803b158015611f7257600080fd5b505afa158015611f86573d6000803e3d6000fd5b5050505050565b60606000611f9a836121a3565b600101905060008167ffffffffffffffff811115611fba57611fba612550565b6040519080825280601f01601f191660200182016040528015611fe4576020820181803683370190505b5090508181016020015b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8504945084611fee575b509392505050565b60606103c473ffffffffffffffffffffffffffffffffffffffff83166014612285565b600061209b827f01ffc9a7000000000000000000000000000000000000000000000000000000006120d3565b80156103c457506120cc827fffffffff000000000000000000000000000000000000000000000000000000006120d3565b1592915050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000082166024820152600090819060440160408051601f19818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825192935060009283928392909183918a617530fa92503d9150600051905082801561218c575060208210155b80156121985750600081115b979650505050505050565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000083106121ec577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef81000000008310612218576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061223657662386f26fc10000830492506010015b6305f5e100831061224e576305f5e100830492506008015b612710831061226257612710830492506004015b60648310612274576064830492506002015b600a83106103c45760010192915050565b6060826000612295846002613de0565b6122a0906002613df7565b67ffffffffffffffff8111156122b8576122b8612550565b6040519080825280601f01601f1916602001820160405280156122e2576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110612319576123196135e5565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061237c5761237c6135e5565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006123b8856002613de0565b6123c3906001613df7565b90505b6001811115612460577f303132333435363738396162636465660000000000000000000000000000000083600f1660108110612404576124046135e5565b1a60f81b82828151811061241a5761241a6135e5565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049290921c9161245981613e0a565b90506123c6565b5081156124a3576040517fe22e27eb00000000000000000000000000000000000000000000000000000000815260048101869052602481018590526044016117d5565b949350505050565b6000602082840312156124bd57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610be457600080fd5b60005b838110156125085781810151838201526020016124f0565b50506000910152565b600081518084526125298160208601602086016124ed565b601f01601f19169290920160200192915050565b602081526000610be46020830184612511565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101a0810167ffffffffffffffff811182821017156125a3576125a3612550565b60405290565b60405160e0810167ffffffffffffffff811182821017156125a3576125a3612550565b604051601f8201601f1916810167ffffffffffffffff811182821017156125f5576125f5612550565b604052919050565b600067ffffffffffffffff82111561261757612617612550565b50601f01601f191660200190565b6000612638612633846125fd565b6125cc565b905082815283838301111561264c57600080fd5b828260208301376000602084830101529392505050565b600082601f83011261267457600080fd5b610be483833560208501612625565b60008060006060848603121561269857600080fd5b833567ffffffffffffffff808211156126b057600080fd5b6126bc87838801612663565b94506020860135935060408601359150808211156126d957600080fd5b506126e686828701612663565b9150509250925092565b82151581526040602082015260006124a36040830184612511565b60006020828403121561271d57600080fd5b813567ffffffffffffffff81111561273457600080fd5b820160a08185031215610be457600080fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461195757600080fd5b8035610aa181612746565b60006020828403121561278557600080fd5b8135610be481612746565b6000602082840312156127a257600080fd5b5035919050565b60008282518085526020808601955060208260051b8401016020860160005b848110156127f657601f198684030189526127e4838351612511565b988401989250908301906001016127c8565b5090979650505050505050565b6020815261281660208201835115159052565b6000602083015161282b604084018215159052565b506040830151801515606084015250606083015173ffffffffffffffffffffffffffffffffffffffff811660808401525060808301516101a08060a08501526128786101c0850183612511565b915060a085015161289160c086018263ffffffff169052565b5060c085015180151560e08601525060e08501516101006128b58187018315159052565b86015190506101206128ca8682018315159052565b86015190506101406128df8682018315159052565b80870151915050601f196101608187860301818801526128ff85846127a9565b94508088015192505061018081878603018188015261291e85846127a9565b908801518782039092018488015293509050610ea283826127a9565b801515811461195757600080fd5b8035610aa18161293a565b60008060008060008060c0878903121561296c57600080fd5b863561297781612746565b955060208701356129878161293a565b9450604087013561299781612746565b935060608701356129a781612746565b92506080870135915060a087013567ffffffffffffffff8111156129ca57600080fd5b6129d689828a01612663565b9150509295509295509295565b6000806000606084860312156129f857600080fd5b833592506020840135612a0a81612746565b91506040840135612a1a8161293a565b809150509250925092565b60008060408385031215612a3857600080fd5b823591506020830135612a4a81612746565b809150509250929050565b600060208284031215612a6757600080fd5b813567ffffffffffffffff811115612a7e57600080fd5b6124a384828501612663565b60008060008060008060a08789031215612aa357600080fd5b863595506020870135612ab581612746565b94506040870135612ac581612746565b93506060870135612ad581612746565b9250608087013567ffffffffffffffff80821115612af257600080fd5b818901915089601f830112612b0657600080fd5b813581811115612b1557600080fd5b8a6020828501011115612b2757600080fd5b6020830194508093505050509295509295509295565b600181811c90821680612b5157607f821691505b602082108103612b8a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b8051610aa18161293a565b8051610aa181612746565b6000612bb4612633846125fd565b9050828152838383011115612bc857600080fd5b610be48360208301846124ed565b600082601f830112612be757600080fd5b610be483835160208501612ba6565b63ffffffff8116811461195757600080fd5b8051610aa181612bf6565b600067ffffffffffffffff821115612c2d57612c2d612550565b5060051b60200190565b600082601f830112612c4857600080fd5b81516020612c5861263383612c13565b82815260059290921b84018101918181019086841115612c7757600080fd5b8286015b84811015612ccc57805167ffffffffffffffff811115612c9b5760008081fd5b8701603f81018913612cad5760008081fd5b612cbe898683015160408401612ba6565b845250918301918301612c7b565b509695505050505050565b600060208284031215612ce957600080fd5b815167ffffffffffffffff80821115612d0157600080fd5b908301906101a08286031215612d1657600080fd5b612d1e61257f565b612d2783612b90565b8152612d3560208401612b90565b6020820152612d4660408401612b90565b6040820152612d5760608401612b9b565b6060820152608083015182811115612d6e57600080fd5b612d7a87828601612bd6565b608083015250612d8c60a08401612c08565b60a0820152612d9d60c08401612b90565b60c0820152612dae60e08401612b90565b60e0820152610100612dc1818501612b90565b90820152610120612dd3848201612b90565b908201526101408381015183811115612deb57600080fd5b612df788828701612c37565b8284015250506101608084015183811115612e1157600080fd5b612e1d88828701612c37565b8284015250506101808084015183811115612e3757600080fd5b612e4388828701612c37565b918301919091525095945050505050565b602081526000610be460208301846127a9565b600060c08284031215612e7957600080fd5b60405160c0810181811067ffffffffffffffff82111715612e9c57612e9c612550565b6040528251612eaa8161293a565b81526020830151612eba8161293a565b8060208301525060408301516040820152606083015160608201526080830151608082015260a083015160a08201528091505092915050565b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe61833603018112612f2757600080fd5b9190910192915050565b600060208284031215612f4357600080fd5b8135610be48161293a565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612f8357600080fd5b830160208101925035905067ffffffffffffffff811115612fa357600080fd5b803603821315612fb257600080fd5b9250929050565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b8035610aa181612bf6565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261302457600080fd5b830160208101925035905067ffffffffffffffff81111561304457600080fd5b8060051b3603821315612fb257600080fd5b6000838385526020808601955060208560051b8301018460005b878110156127f657601f1985840301895261308b8288612f4e565b613096858284612fb9565b9a86019a9450505090830190600101613070565b602081526130c4602082016130be84612948565b15159052565b60006130d260208401612948565b8015156040840152506130e760408401612948565b8015156060840152506130fc60608401612768565b73ffffffffffffffffffffffffffffffffffffffff81166080840152506131266080840184612f4e565b6101a08060a086015261313e6101c086018385612fb9565b925061314c60a08701612fe4565b63ffffffff811660c0870152915061316660c08701612948565b80151560e0870152915061317c60e08701612948565b915061010061318e8187018415159052565b613199818801612948565b9250506101206131ac8187018415159052565b6131b7818801612948565b9250506101406131ca8187018415159052565b6131d681880188612fef565b93509050601f196101608188870301818901526131f4868685613056565b9550613202818a018a612fef565b955092505061018081888703018189015261321e868685613056565b955061322c818a018a612fef565b955092505080878603018388015250612198848483613056565b60006020828403121561325857600080fd5b8135610be481612bf6565b602081528151151560208201526000602083015173ffffffffffffffffffffffffffffffffffffffff80821660408501526040850151915060e060608501526132b0610100850183612511565b9150806060860151166080850152506080840151601f198483030160a08501526132da8282612511565b91505060a084015160c084015260c084015161204460e085018273ffffffffffffffffffffffffffffffffffffffff169052565b60006020828403121561332057600080fd5b5051919050565b60006020828403121561333957600080fd5b815167ffffffffffffffff81111561335057600080fd5b6124a384828501612bd6565b60006020828403121561336e57600080fd5b815167ffffffffffffffff8082111561338657600080fd5b9083019060e0828603121561339a57600080fd5b6133a26125a9565b6133ab83612b90565b81526133b960208401612b9b565b60208201526040830151828111156133d057600080fd5b6133dc87828601612bd6565b6040830152506133ee60608401612b9b565b606082015260808301518281111561340557600080fd5b61341187828601612bd6565b60808301525060a083015160a082015261342d60c08401612b9b565b60c082015295945050505050565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006124a36040830184612511565b60006020828403121561347c57600080fd5b8151610be48161293a565b60006020828403121561349957600080fd5b8151610be481612746565b600081516134b68185602086016124ed565b9290920192915050565b7f7b2274726169745f74797065223a20224174747269627574696f6e222c20227681527f616c7565223a202200000000000000000000000000000000000000000000000060208201526000845161351e8160288501602089016124ed565b7f227d2c0000000000000000000000000000000000000000000000000000000000602891840191820152845161355b81602b8401602089016124ed565b845191019061357181602b8401602088016124ed565b01602b0195945050505050565b600082516135908184602087016124ed565b7f7b2274726169745f74797065223a20225465727269746f72696573222c2022769201918252507f616c7565223a205b0000000000000000000000000000000000000000000000006020820152602801919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600083516136268184602088016124ed565b80830190507f220000000000000000000000000000000000000000000000000000000000000080825284516136628160018501602089016124ed565b6001920191820152600201949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156103c4576103c4613675565b600082516136c98184602087016124ed565b7f2c00000000000000000000000000000000000000000000000000000000000000920191825250600101919050565b6000825161370a8184602087016124ed565b7f5d7d2c0000000000000000000000000000000000000000000000000000000000920191825250600301919050565b6000825161374b8184602087016124ed565b7f7b2274726169745f74797065223a2022446973747269627574696f6e204368619201918252507f6e6e656c73222c202276616c7565223a205b00000000000000000000000000006020820152603201919050565b600082601f8301126137b157600080fd5b813560206137c161263383612c13565b82815260059290921b840181019181810190868411156137e057600080fd5b8286015b84811015612ccc57803567ffffffffffffffff8111156138045760008081fd5b8701603f810189136138165760008081fd5b613827898683013560408401612625565b8452509183019183016137e4565b60006020828403121561384757600080fd5b813567ffffffffffffffff8082111561385f57600080fd5b908301906101a0828603121561387457600080fd5b61387c61257f565b61388583612948565b815261389360208401612948565b60208201526138a460408401612948565b60408201526138b560608401612768565b60608201526080830135828111156138cc57600080fd5b6138d887828601612663565b6080830152506138ea60a08401612fe4565b60a08201526138fb60c08401612948565b60c082015261390c60e08401612948565b60e082015261010061391f818501612948565b90820152610120613931848201612948565b90820152610140838101358381111561394957600080fd5b613955888287016137a0565b828401525050610160808401358381111561396f57600080fd5b61397b888287016137a0565b828401525050610180808401358381111561399557600080fd5b612e43888287016137a0565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126139d657600080fd5b83018035915067ffffffffffffffff8211156139f157600080fd5b602001915036819003821315612fb257600080fd5b6020815260006124a3602083018486612fb9565b7f7b2274726169745f74797065223a2022436f6d6d65726369616c20557365222c81527f202276616c7565223a2022000000000000000000000000000000000000000000602082015260008551613a7881602b850160208a016124ed565b80830190507f227d2c000000000000000000000000000000000000000000000000000000000080602b8301527f7b2274726169745f74797065223a2022436f6d6d65726369616c204174747269602e8301527f627574696f6e222c202276616c7565223a202200000000000000000000000000604e8301528651613b03816061850160208b016124ed565b60619201918201527f7b2274726169745f74797065223a2022436f6d6d65726369616c20526576656e60648201527f7565205368617265222c20226d61785f76616c7565223a20313030302c20227660848201527f616c7565223a200000000000000000000000000000000000000000000000000060a4820152612198613c14613c0e613bbf613b9660ab86018a6134a4565b7f7d2c000000000000000000000000000000000000000000000000000000000000815260020190565b7f7b2274726169745f74797065223a2022436f6d6d65726369616c697a6572204381527f6865636b222c202276616c7565223a2022000000000000000000000000000000602082015260310190565b866134a4565b7f227d2c0000000000000000000000000000000000000000000000000000000000815260030190565b7f7b2274726169745f74797065223a2022446572697661746976657320416c6c6f81527f776564222c202276616c7565223a202200000000000000000000000000000000602082015260008551613c9b816030850160208a016124ed565b80830190507f227d2c00000000000000000000000000000000000000000000000000000000008060308301527f7b2274726169745f74797065223a20224465726976617469766573204174747260338301527f69627574696f6e222c202276616c7565223a202200000000000000000000000060538301528651613d26816067850160208b016124ed565b60679201918201527f7b2274726169745f74797065223a202244657269766174697665732041707072606a8201527f6f76616c222c202276616c7565223a2022000000000000000000000000000000608a820152612198613c14613c0e613d9182609b86018a6134a4565b7f7b2274726169745f74797065223a20224465726976617469766573205265636981527f70726f63616c222c202276616c7565223a202200000000000000000000000000602082015260330190565b80820281158282048414176103c4576103c4613675565b808201808211156103c4576103c4613675565b600081613e1957613e19613675565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea2646970667358221220fc90f9839b5bffd45375fae8376b11c830bd4c45c43935ea1a1e6e88633b9d8964736f6c63430008170033000000000000000000000000ad64a4b2e18ff7d2f97af083e7b193d7dd141735000000000000000000000000bd2780f291588c8bddf7f5874988fa9d3179d560000000000000000000000000950d766a1a0afdc33c3e653c861a8765cb42dbdc00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000370696c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004d68747470733a2f2f6769746875622e636f6d2f73746f727970726f746f636f6c2f70726f746f636f6c2d636f72652f626c6f622f6d61696e2f50494c2d426574612d323032342d30322e70646600000000000000000000000000000000000000

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101005760003560e01c8063af0b2eaf11610097578063e1ecbde311610066578063e1ecbde3146102d1578063eb6b3315146102e4578063f02a3111146102f7578063f0ebdc831461030a57600080fd5b8063af0b2eaf14610281578063c75e9a59146102a1578063cd6f464d146102a9578063dc96e2aa146102bc57600080fd5b80632421d9a4116100d35780632421d9a4146101af57806329a42d56146101d057806365165aa514610233578063702acd851461025a57600080fd5b806301ffc9a71461010557806306fdde031461012d5780631b00c800146101425780631b8b107314610163575b600080fd5b6101186101133660046124ab565b610331565b60405190151581526020015b60405180910390f35b6101356103ca565b604051610124919061253d565b610155610150366004612683565b610458565b6040516101249291906126f0565b61018a7f000000000000000000000000ad64a4b2e18ff7d2f97af083e7b193d7dd14173581565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610124565b6101c26101bd36600461270b565b61089f565b604051908152602001610124565b6101e36101de366004612773565b610aa6565b6040516101249190600060c08201905082511515825260208301511515602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b61018a7f000000000000000000000000950d766a1a0afdc33c3e653c861a8765cb42dbdc81565b61018a7f000000000000000000000000bd2780f291588c8bddf7f5874988fa9d3179d56081565b61029461028f366004612790565b610beb565b6040516101249190612803565b610135610d21565b6101186102b7366004612953565b610d2e565b6102cf6102ca3660046129e3565b610eac565b005b6101186102df366004612a25565b610f72565b6101356102f2366004612a55565b61106b565b610118610305366004612a8a565b6112ef565b61018a7f000000000000000000000000c2bc7a2d5784768bded98436f2522a4931e2fbb481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f0c8dc8130000000000000000000000000000000000000000000000000000000014806103c457507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b600080546103d790612b3d565b80601f016020809104026020016040519081016040528092919081815260200182805461040390612b3d565b80156104505780601f1061042557610100808354040283529160200191610450565b820191906000526020600020905b81548152906001019060200180831161043357829003601f168201915b505050505081565b600060603373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000950d766a1a0afdc33c3e653c861a8765cb42dbdc16146104cb576040517f4343348300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091526000848060200190518101906105139190612cd7565b9050865160000361064b576040518060c001604052808260200151151581526020018261012001511515815260200187815260200182610140015160405160200161055e9190612e54565b60405160208183030381529060405280519060200120815260200182610160015160405160200161058f9190612e54565b6040516020818303038152906040528051906020012081526020018261018001516040516020016105c09190612e54565b6040516020818303038152906040528051906020012081525091506001826040516020016106319190600060c08201905082511515825260208301511515602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b604051602081830303815290604052935093505050610897565b8680602001905181019061065f9190612e67565b9150806101200151151582602001511515146106a7576040517f3b53932500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816020015180156106ba57508061012001515b1561070157858260400151146106fc576040517f5ba8230300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61082c565b60208101518251151590151514610744576040517f0b63cb3100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006107a383606001518361014001516040516020016107649190612e54565b604051602081830303815290604052805190602001207f569e75fc77c1a856f6daaf9e69d8a9566ca34aa47f9133711ce065a571af0cfd60001b611416565b9050826060015181146107bc5760608301819052600194505b6107da83608001518361016001516040516020016107649190612e54565b9050826080015181146107f35760808301819052600194505b6108118360a001518361018001516040516020016107649190612e54565b90508260a00151811461082a5760a08301819052600194505b505b83826040516020016108819190600060c08201905082511515825260208301511515602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b6040516020818303038152906040529350935050505b935093915050565b60006108a961148a565b6108e36108b96080840184612ef3565b6108c96040850160208601612773565b60408501356108de6080870160608801612773565b6114cd565b6108f86108f36080840184612ef3565b611869565b6040805160e08101909152600090806109146020860186612f31565b1515815230602082015260400161092e6080860186612ef3565b60405160200161093e91906130aa565b60405160208183030381529060405281526020018460200160208101906109659190612773565b73ffffffffffffffffffffffffffffffffffffffff16815260200161098d6080860186612ef3565b61099e9060c081019060a001613246565b6040805163ffffffff90921660208301520160408051601f19818403018152918152908252858101356020830152016109dd6080860160608701612773565b73ffffffffffffffffffffffffffffffffffffffff1681525090507f000000000000000000000000950d766a1a0afdc33c3e653c861a8765cb42dbdc73ffffffffffffffffffffffffffffffffffffffff1663032e1860826040518263ffffffff1660e01b8152600401610a519190613263565b6020604051808303816000875af1158015610a70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a94919061330e565b915050610aa16001600355565b919050565b6040805160c081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905291517f30d9113600000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff84811660248301529192917f000000000000000000000000950d766a1a0afdc33c3e653c861a8765cb42dbdc16906330d9113690604401600060405180830381865afa158015610b6b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b939190810190613327565b90508051600003610bd0576040517fc64675f600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80806020019051810190610be49190612e67565b9392505050565b604080516101a08101825260008082526020820181905281830181905260608083018290526080830181905260a0830182905260c0830182905260e08301829052610100830182905261012083018290526101408301819052610160830181905261018083015291517f3cea51200000000000000000000000000000000000000000000000000000000081526004810184905290919073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000950d766a1a0afdc33c3e653c861a8765cb42dbdc1690633cea512090602401600060405180830381865afa158015610cdf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d07919081019061335c565b90508060400151806020019051810190610be49190612cd7565b600180546103d790612b3d565b6000610d3861148a565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000950d766a1a0afdc33c3e653c861a8765cb42dbdc1614610da7576040517f4343348300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082806020019051810190610dbd9190612cd7565b9050806101200151158015610dcf5750865b15610dde576000915050610e98565b606081015173ffffffffffffffffffffffffffffffffffffffff1615610e9257806060015173ffffffffffffffffffffffffffffffffffffffff16634a41d1ac8983608001516040518363ffffffff1660e01b8152600401610e4192919061343b565b6020604051808303816000875af1158015610e60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e84919061346a565b610e92576000915050610e98565b60019150505b610ea26001600355565b9695505050505050565b6040517f34d70eea000000000000000000000000000000000000000000000000000000008152600481018490526000907f000000000000000000000000c2bc7a2d5784768bded98436f2522a4931e2fbb473ffffffffffffffffffffffffffffffffffffffff16906334d70eea90602401602060405180830381865afa158015610f3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5e9190613487565b9050610f6c8185858561195a565b50505050565b6040517f34d70eea00000000000000000000000000000000000000000000000000000000815260048101839052600090819073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c2bc7a2d5784768bded98436f2522a4931e2fbb416906334d70eea90602401602060405180830381865afa158015611002573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110269190613487565b600094855260026020908152604080872073ffffffffffffffffffffffffffffffffffffffff9384168852825280872095909216865293909352505090205460ff1690565b60606000828060200190518101906110839190612cd7565b9050600081600001516110cb576040518060400160405280600581526020017f66616c7365000000000000000000000000000000000000000000000000000000815250611102565b6040518060400160405280600481526020017f74727565000000000000000000000000000000000000000000000000000000008152505b61110b83611a0a565b61111484611b61565b604051602001611126939291906134c0565b604051602081830303815290604052905080604051602001611148919061357e565b60408051601f198184030181529190526101408301515190915060005b818110156111ec57828461014001518281518110611185576111856135e5565b602002602001015160405160200161119e929190613614565b60408051601f1981840301815291905292506111bb6001836136a4565b81146111e457826040516020016111d291906136b7565b60405160208183030381529060405292505b600101611165565b50816040516020016111fe91906136f8565b6040516020818303038152906040529150816040516020016112209190613739565b604051602081830303815290604052915082610160015151905060005b818110156112c45782846101600151828151811061125d5761125d6135e5565b6020026020010151604051602001611276929190613614565b60408051601f1981840301815291905292506112936001836136a4565b81146112bc57826040516020016112aa91906136b7565b60405160208183030381529060405292505b60010161123d565b50816040516020016112d691906136f8565b60408051601f1981840301815291905295945050505050565b60006112f961148a565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000950d766a1a0afdc33c3e653c861a8765cb42dbdc1614611368576040517f4343348300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061137683850185613835565b90508060c0015161138b576000915050610e98565b80610100015180156113a457506113a28887610f72565b155b156113b3576000915050610e98565b606081015173ffffffffffffffffffffffffffffffffffffffff1615610e9257806060015173ffffffffffffffffffffffffffffffffffffffff16634a41d1ac8883608001516040518363ffffffff1660e01b8152600401610e4192919061343b565b6000828403611426575081610be4565b8184141580156114365750818314155b1561146d576040517fe12ebaba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81841461147b575082610be4565b818314610be457509092915050565b6002600354036114c6576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600355565b6114dd6040850160208601612f31565b6116b0576114f16060850160408601612f31565b15611528576040517f7397bbaa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061153a6080860160608701612773565b73ffffffffffffffffffffffffffffffffffffffff1614611587576040517fc1f0a67d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061159960c0860160a08701613246565b63ffffffff1611156115d7576040517f529c886000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff831615611625576040517f3f63513800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b811561165d576040517f0cb7b17500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116156116ab576040517f88fb4f2f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f6c565b73ffffffffffffffffffffffffffffffffffffffff83166116fd576040517f7660ada600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061170f6080860160608701612773565b73ffffffffffffffffffffffffffffffffffffffff1614610f6c5761177a7fe352692d0000000000000000000000000000000000000000000000000000000061175e6080870160608801612773565b73ffffffffffffffffffffffffffffffffffffffff1690611d64565b6117de5761178e6080850160608601612773565b6040517f5f72721800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024015b60405180910390fd5b6117ee6080850160608601612773565b73ffffffffffffffffffffffffffffffffffffffff1663a913b88161181660808701876139a1565b6040518363ffffffff1660e01b8152600401611833929190613a06565b60006040518083038186803b15801561184b57600080fd5b505afa15801561185f573d6000803e3d6000fd5b5050505050505050565b61187960e0820160c08301612f31565b6119575761188e610100820160e08301612f31565b156118c5576040517f550c495200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6118d761012082016101008301612f31565b1561190e576040517f0891883b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61192061014082016101208301612f31565b15611957576040517f209f573300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b8361196481611d80565b600084815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff898116808652918452828520908816855283529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016861515908117909155905190815233929187917f436fd071b1745141646f97213ec7dd4b24e735af0c49bd6d047186c995cc10cc910160405180910390a45050505050565b60608160200151611a50576040518060400160405280600581526020017f66616c7365000000000000000000000000000000000000000000000000000000815250611a87565b6040518060400160405280600481526020017f74727565000000000000000000000000000000000000000000000000000000008152505b8260400151611acb576040518060400160405280600581526020017f66616c7365000000000000000000000000000000000000000000000000000000815250611b02565b6040518060400160405280600481526020017f74727565000000000000000000000000000000000000000000000000000000008152505b611b158460a0015163ffffffff16611f8d565b611b38856060015173ffffffffffffffffffffffffffffffffffffffff1661204c565b604051602001611b4b9493929190613a1a565b6040516020818303038152906040529050919050565b60608160c00151611ba7576040518060400160405280600581526020017f66616c7365000000000000000000000000000000000000000000000000000000815250611bde565b6040518060400160405280600481526020017f74727565000000000000000000000000000000000000000000000000000000008152505b8260e00151611c22576040518060400160405280600581526020017f66616c7365000000000000000000000000000000000000000000000000000000815250611c59565b6040518060400160405280600481526020017f74727565000000000000000000000000000000000000000000000000000000008152505b836101000151611c9e576040518060400160405280600581526020017f66616c7365000000000000000000000000000000000000000000000000000000815250611cd5565b6040518060400160405280600481526020017f74727565000000000000000000000000000000000000000000000000000000008152505b846101200151611d1a576040518060400160405280600581526020017f66616c7365000000000000000000000000000000000000000000000000000000815250611d51565b6040518060400160405280600481526020017f74727565000000000000000000000000000000000000000000000000000000008152505b604051602001611b4b9493929190613c3d565b6000611d6f8361206f565b8015610be45750610be483836120d3565b6040517f5a1c2dd700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000bd2780f291588c8bddf7f5874988fa9d3179d56081166004830152821660248201527336e93affeca875ebcef53e922a4b716ad2a508a990635a1c2dd790604401602060405180830381865af4158015611e26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e4a919061346a565b611e98576040517fd64edf9000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016117d5565b3373ffffffffffffffffffffffffffffffffffffffff821614611957576040517f7dfd0ddb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301523360248301523060448301526000357fffffffff000000000000000000000000000000000000000000000000000000001660648301527f000000000000000000000000ad64a4b2e18ff7d2f97af083e7b193d7dd1417351690637dfd0ddb9060840160006040518083038186803b158015611f7257600080fd5b505afa158015611f86573d6000803e3d6000fd5b5050505050565b60606000611f9a836121a3565b600101905060008167ffffffffffffffff811115611fba57611fba612550565b6040519080825280601f01601f191660200182016040528015611fe4576020820181803683370190505b5090508181016020015b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8504945084611fee575b509392505050565b60606103c473ffffffffffffffffffffffffffffffffffffffff83166014612285565b600061209b827f01ffc9a7000000000000000000000000000000000000000000000000000000006120d3565b80156103c457506120cc827fffffffff000000000000000000000000000000000000000000000000000000006120d3565b1592915050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000082166024820152600090819060440160408051601f19818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825192935060009283928392909183918a617530fa92503d9150600051905082801561218c575060208210155b80156121985750600081115b979650505050505050565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000083106121ec577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef81000000008310612218576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061223657662386f26fc10000830492506010015b6305f5e100831061224e576305f5e100830492506008015b612710831061226257612710830492506004015b60648310612274576064830492506002015b600a83106103c45760010192915050565b6060826000612295846002613de0565b6122a0906002613df7565b67ffffffffffffffff8111156122b8576122b8612550565b6040519080825280601f01601f1916602001820160405280156122e2576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110612319576123196135e5565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061237c5761237c6135e5565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006123b8856002613de0565b6123c3906001613df7565b90505b6001811115612460577f303132333435363738396162636465660000000000000000000000000000000083600f1660108110612404576124046135e5565b1a60f81b82828151811061241a5761241a6135e5565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049290921c9161245981613e0a565b90506123c6565b5081156124a3576040517fe22e27eb00000000000000000000000000000000000000000000000000000000815260048101869052602481018590526044016117d5565b949350505050565b6000602082840312156124bd57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610be457600080fd5b60005b838110156125085781810151838201526020016124f0565b50506000910152565b600081518084526125298160208601602086016124ed565b601f01601f19169290920160200192915050565b602081526000610be46020830184612511565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101a0810167ffffffffffffffff811182821017156125a3576125a3612550565b60405290565b60405160e0810167ffffffffffffffff811182821017156125a3576125a3612550565b604051601f8201601f1916810167ffffffffffffffff811182821017156125f5576125f5612550565b604052919050565b600067ffffffffffffffff82111561261757612617612550565b50601f01601f191660200190565b6000612638612633846125fd565b6125cc565b905082815283838301111561264c57600080fd5b828260208301376000602084830101529392505050565b600082601f83011261267457600080fd5b610be483833560208501612625565b60008060006060848603121561269857600080fd5b833567ffffffffffffffff808211156126b057600080fd5b6126bc87838801612663565b94506020860135935060408601359150808211156126d957600080fd5b506126e686828701612663565b9150509250925092565b82151581526040602082015260006124a36040830184612511565b60006020828403121561271d57600080fd5b813567ffffffffffffffff81111561273457600080fd5b820160a08185031215610be457600080fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461195757600080fd5b8035610aa181612746565b60006020828403121561278557600080fd5b8135610be481612746565b6000602082840312156127a257600080fd5b5035919050565b60008282518085526020808601955060208260051b8401016020860160005b848110156127f657601f198684030189526127e4838351612511565b988401989250908301906001016127c8565b5090979650505050505050565b6020815261281660208201835115159052565b6000602083015161282b604084018215159052565b506040830151801515606084015250606083015173ffffffffffffffffffffffffffffffffffffffff811660808401525060808301516101a08060a08501526128786101c0850183612511565b915060a085015161289160c086018263ffffffff169052565b5060c085015180151560e08601525060e08501516101006128b58187018315159052565b86015190506101206128ca8682018315159052565b86015190506101406128df8682018315159052565b80870151915050601f196101608187860301818801526128ff85846127a9565b94508088015192505061018081878603018188015261291e85846127a9565b908801518782039092018488015293509050610ea283826127a9565b801515811461195757600080fd5b8035610aa18161293a565b60008060008060008060c0878903121561296c57600080fd5b863561297781612746565b955060208701356129878161293a565b9450604087013561299781612746565b935060608701356129a781612746565b92506080870135915060a087013567ffffffffffffffff8111156129ca57600080fd5b6129d689828a01612663565b9150509295509295509295565b6000806000606084860312156129f857600080fd5b833592506020840135612a0a81612746565b91506040840135612a1a8161293a565b809150509250925092565b60008060408385031215612a3857600080fd5b823591506020830135612a4a81612746565b809150509250929050565b600060208284031215612a6757600080fd5b813567ffffffffffffffff811115612a7e57600080fd5b6124a384828501612663565b60008060008060008060a08789031215612aa357600080fd5b863595506020870135612ab581612746565b94506040870135612ac581612746565b93506060870135612ad581612746565b9250608087013567ffffffffffffffff80821115612af257600080fd5b818901915089601f830112612b0657600080fd5b813581811115612b1557600080fd5b8a6020828501011115612b2757600080fd5b6020830194508093505050509295509295509295565b600181811c90821680612b5157607f821691505b602082108103612b8a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b8051610aa18161293a565b8051610aa181612746565b6000612bb4612633846125fd565b9050828152838383011115612bc857600080fd5b610be48360208301846124ed565b600082601f830112612be757600080fd5b610be483835160208501612ba6565b63ffffffff8116811461195757600080fd5b8051610aa181612bf6565b600067ffffffffffffffff821115612c2d57612c2d612550565b5060051b60200190565b600082601f830112612c4857600080fd5b81516020612c5861263383612c13565b82815260059290921b84018101918181019086841115612c7757600080fd5b8286015b84811015612ccc57805167ffffffffffffffff811115612c9b5760008081fd5b8701603f81018913612cad5760008081fd5b612cbe898683015160408401612ba6565b845250918301918301612c7b565b509695505050505050565b600060208284031215612ce957600080fd5b815167ffffffffffffffff80821115612d0157600080fd5b908301906101a08286031215612d1657600080fd5b612d1e61257f565b612d2783612b90565b8152612d3560208401612b90565b6020820152612d4660408401612b90565b6040820152612d5760608401612b9b565b6060820152608083015182811115612d6e57600080fd5b612d7a87828601612bd6565b608083015250612d8c60a08401612c08565b60a0820152612d9d60c08401612b90565b60c0820152612dae60e08401612b90565b60e0820152610100612dc1818501612b90565b90820152610120612dd3848201612b90565b908201526101408381015183811115612deb57600080fd5b612df788828701612c37565b8284015250506101608084015183811115612e1157600080fd5b612e1d88828701612c37565b8284015250506101808084015183811115612e3757600080fd5b612e4388828701612c37565b918301919091525095945050505050565b602081526000610be460208301846127a9565b600060c08284031215612e7957600080fd5b60405160c0810181811067ffffffffffffffff82111715612e9c57612e9c612550565b6040528251612eaa8161293a565b81526020830151612eba8161293a565b8060208301525060408301516040820152606083015160608201526080830151608082015260a083015160a08201528091505092915050565b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe61833603018112612f2757600080fd5b9190910192915050565b600060208284031215612f4357600080fd5b8135610be48161293a565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612f8357600080fd5b830160208101925035905067ffffffffffffffff811115612fa357600080fd5b803603821315612fb257600080fd5b9250929050565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b8035610aa181612bf6565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261302457600080fd5b830160208101925035905067ffffffffffffffff81111561304457600080fd5b8060051b3603821315612fb257600080fd5b6000838385526020808601955060208560051b8301018460005b878110156127f657601f1985840301895261308b8288612f4e565b613096858284612fb9565b9a86019a9450505090830190600101613070565b602081526130c4602082016130be84612948565b15159052565b60006130d260208401612948565b8015156040840152506130e760408401612948565b8015156060840152506130fc60608401612768565b73ffffffffffffffffffffffffffffffffffffffff81166080840152506131266080840184612f4e565b6101a08060a086015261313e6101c086018385612fb9565b925061314c60a08701612fe4565b63ffffffff811660c0870152915061316660c08701612948565b80151560e0870152915061317c60e08701612948565b915061010061318e8187018415159052565b613199818801612948565b9250506101206131ac8187018415159052565b6131b7818801612948565b9250506101406131ca8187018415159052565b6131d681880188612fef565b93509050601f196101608188870301818901526131f4868685613056565b9550613202818a018a612fef565b955092505061018081888703018189015261321e868685613056565b955061322c818a018a612fef565b955092505080878603018388015250612198848483613056565b60006020828403121561325857600080fd5b8135610be481612bf6565b602081528151151560208201526000602083015173ffffffffffffffffffffffffffffffffffffffff80821660408501526040850151915060e060608501526132b0610100850183612511565b9150806060860151166080850152506080840151601f198483030160a08501526132da8282612511565b91505060a084015160c084015260c084015161204460e085018273ffffffffffffffffffffffffffffffffffffffff169052565b60006020828403121561332057600080fd5b5051919050565b60006020828403121561333957600080fd5b815167ffffffffffffffff81111561335057600080fd5b6124a384828501612bd6565b60006020828403121561336e57600080fd5b815167ffffffffffffffff8082111561338657600080fd5b9083019060e0828603121561339a57600080fd5b6133a26125a9565b6133ab83612b90565b81526133b960208401612b9b565b60208201526040830151828111156133d057600080fd5b6133dc87828601612bd6565b6040830152506133ee60608401612b9b565b606082015260808301518281111561340557600080fd5b61341187828601612bd6565b60808301525060a083015160a082015261342d60c08401612b9b565b60c082015295945050505050565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006124a36040830184612511565b60006020828403121561347c57600080fd5b8151610be48161293a565b60006020828403121561349957600080fd5b8151610be481612746565b600081516134b68185602086016124ed565b9290920192915050565b7f7b2274726169745f74797065223a20224174747269627574696f6e222c20227681527f616c7565223a202200000000000000000000000000000000000000000000000060208201526000845161351e8160288501602089016124ed565b7f227d2c0000000000000000000000000000000000000000000000000000000000602891840191820152845161355b81602b8401602089016124ed565b845191019061357181602b8401602088016124ed565b01602b0195945050505050565b600082516135908184602087016124ed565b7f7b2274726169745f74797065223a20225465727269746f72696573222c2022769201918252507f616c7565223a205b0000000000000000000000000000000000000000000000006020820152602801919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600083516136268184602088016124ed565b80830190507f220000000000000000000000000000000000000000000000000000000000000080825284516136628160018501602089016124ed565b6001920191820152600201949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156103c4576103c4613675565b600082516136c98184602087016124ed565b7f2c00000000000000000000000000000000000000000000000000000000000000920191825250600101919050565b6000825161370a8184602087016124ed565b7f5d7d2c0000000000000000000000000000000000000000000000000000000000920191825250600301919050565b6000825161374b8184602087016124ed565b7f7b2274726169745f74797065223a2022446973747269627574696f6e204368619201918252507f6e6e656c73222c202276616c7565223a205b00000000000000000000000000006020820152603201919050565b600082601f8301126137b157600080fd5b813560206137c161263383612c13565b82815260059290921b840181019181810190868411156137e057600080fd5b8286015b84811015612ccc57803567ffffffffffffffff8111156138045760008081fd5b8701603f810189136138165760008081fd5b613827898683013560408401612625565b8452509183019183016137e4565b60006020828403121561384757600080fd5b813567ffffffffffffffff8082111561385f57600080fd5b908301906101a0828603121561387457600080fd5b61387c61257f565b61388583612948565b815261389360208401612948565b60208201526138a460408401612948565b60408201526138b560608401612768565b60608201526080830135828111156138cc57600080fd5b6138d887828601612663565b6080830152506138ea60a08401612fe4565b60a08201526138fb60c08401612948565b60c082015261390c60e08401612948565b60e082015261010061391f818501612948565b90820152610120613931848201612948565b90820152610140838101358381111561394957600080fd5b613955888287016137a0565b828401525050610160808401358381111561396f57600080fd5b61397b888287016137a0565b828401525050610180808401358381111561399557600080fd5b612e43888287016137a0565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126139d657600080fd5b83018035915067ffffffffffffffff8211156139f157600080fd5b602001915036819003821315612fb257600080fd5b6020815260006124a3602083018486612fb9565b7f7b2274726169745f74797065223a2022436f6d6d65726369616c20557365222c81527f202276616c7565223a2022000000000000000000000000000000000000000000602082015260008551613a7881602b850160208a016124ed565b80830190507f227d2c000000000000000000000000000000000000000000000000000000000080602b8301527f7b2274726169745f74797065223a2022436f6d6d65726369616c204174747269602e8301527f627574696f6e222c202276616c7565223a202200000000000000000000000000604e8301528651613b03816061850160208b016124ed565b60619201918201527f7b2274726169745f74797065223a2022436f6d6d65726369616c20526576656e60648201527f7565205368617265222c20226d61785f76616c7565223a20313030302c20227660848201527f616c7565223a200000000000000000000000000000000000000000000000000060a4820152612198613c14613c0e613bbf613b9660ab86018a6134a4565b7f7d2c000000000000000000000000000000000000000000000000000000000000815260020190565b7f7b2274726169745f74797065223a2022436f6d6d65726369616c697a6572204381527f6865636b222c202276616c7565223a2022000000000000000000000000000000602082015260310190565b866134a4565b7f227d2c0000000000000000000000000000000000000000000000000000000000815260030190565b7f7b2274726169745f74797065223a2022446572697661746976657320416c6c6f81527f776564222c202276616c7565223a202200000000000000000000000000000000602082015260008551613c9b816030850160208a016124ed565b80830190507f227d2c00000000000000000000000000000000000000000000000000000000008060308301527f7b2274726169745f74797065223a20224465726976617469766573204174747260338301527f69627574696f6e222c202276616c7565223a202200000000000000000000000060538301528651613d26816067850160208b016124ed565b60679201918201527f7b2274726169745f74797065223a202244657269766174697665732041707072606a8201527f6f76616c222c202276616c7565223a2022000000000000000000000000000000608a820152612198613c14613c0e613d9182609b86018a6134a4565b7f7b2274726169745f74797065223a20224465726976617469766573205265636981527f70726f63616c222c202276616c7565223a202200000000000000000000000000602082015260330190565b80820281158282048414176103c4576103c4613675565b808201808211156103c4576103c4613675565b600081613e1957613e19613675565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea2646970667358221220fc90f9839b5bffd45375fae8376b11c830bd4c45c43935ea1a1e6e88633b9d8964736f6c63430008170033

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

000000000000000000000000ad64a4b2e18ff7d2f97af083e7b193d7dd141735000000000000000000000000bd2780f291588c8bddf7f5874988fa9d3179d560000000000000000000000000950d766a1a0afdc33c3e653c861a8765cb42dbdc00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000370696c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004d68747470733a2f2f6769746875622e636f6d2f73746f727970726f746f636f6c2f70726f746f636f6c2d636f72652f626c6f622f6d61696e2f50494c2d426574612d323032342d30322e70646600000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : accessController (address): 0xad64a4b2e18FF7D2f97aF083E7b193d7Dd141735
Arg [1] : ipAccountRegistry (address): 0xBD2780F291588C8bDDf7F5874988fA9d3179d560
Arg [2] : licensing (address): 0x950d766A1a0afDc33c3e653C861A8765cb42DbdC
Arg [3] : name_ (string): pil
Arg [4] : licenseUrl_ (string): https://github.com/storyprotocol/protocol-core/blob/main/PIL-Beta-2024-02.pdf

-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 000000000000000000000000ad64a4b2e18ff7d2f97af083e7b193d7dd141735
Arg [1] : 000000000000000000000000bd2780f291588c8bddf7f5874988fa9d3179d560
Arg [2] : 000000000000000000000000950d766a1a0afdc33c3e653c861a8765cb42dbdc
Arg [3] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [4] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [6] : 70696c0000000000000000000000000000000000000000000000000000000000
Arg [7] : 000000000000000000000000000000000000000000000000000000000000004d
Arg [8] : 68747470733a2f2f6769746875622e636f6d2f73746f727970726f746f636f6c
Arg [9] : 2f70726f746f636f6c2d636f72652f626c6f622f6d61696e2f50494c2d426574
Arg [10] : 612d323032342d30322e70646600000000000000000000000000000000000000


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.