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

Add Licensing-Royalty integration and new LAP royalty policy #99

Merged
merged 22 commits into from
Feb 17, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .solhint.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"not-rely-on-time": "off",
"reason-string": ["warn", { "maxLength": 64 }],
"no-unused-import": "error",
"no-unused-vars": "error",
"no-unused-vars": "off",
"no-inline-assembly": "off",
"avoid-low-level-calls": "off",
"no-global-import": "error",
Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/modules/IRegistrationModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ interface IRegistrationModule {
string memory ipName,
bytes32 hash,
string calldata externalURL,
uint32 minRoyalty
bytes calldata data
) external;
}
1 change: 0 additions & 1 deletion contracts/interfaces/modules/dispute/IDisputeModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -159,5 +159,4 @@ interface IDisputeModule {
/// @notice returns true if the ipId is tagged with any tag (meaning at least one dispute went through)
/// @param _ipId The ipId
function isIpTagged(address _ipId) external view returns (bool);

}
51 changes: 34 additions & 17 deletions contracts/interfaces/modules/licensing/ILicensingModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,18 @@ interface ILicensingModule is IModule {
event PolicyFrameworkRegistered(address indexed framework, string name, string licenseTextUrl);

/// @notice Emitted when a policy is added to the contract
/// @param policyFrameworkManager The address that created the policy
/// @param policyId The id of the policy
/// @param policy The encoded policy data
event PolicyRegistered(address indexed policyFrameworkManager, uint256 indexed policyId, bytes 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
event PolicyRegistered(
uint256 indexed policyId,
address indexed policyFrameworkManager,
bytes frameworkData,
address royaltyPolicy,
bytes royaltyData
);

/// @notice Emitted when a policy is added to an IP
/// @param caller The address that called the function
Expand All @@ -47,6 +55,7 @@ interface ILicensingModule is IModule {

/// @notice Returns the address of the LicenseRegistry
function licenseRegistry() external view returns (address);

/// @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
Expand All @@ -56,15 +65,18 @@ interface ILicensingModule is IModule {
/// framework or it will revert. The policy data and its integrity must be
/// verified by the policy framework manager.
/// @param isLicenseTransferable True if the license is transferable
/// @param data The policy data
function registerPolicy(bool isLicenseTransferable, bytes memory data) external returns (uint256 policyId);
/// @param royaltyPolicy The address of the royalty policy
/// @param royaltyData The royalty policy specific encoded data
/// @param frameworkData The policy framework specific encoded data
function registerPolicy(
bool isLicenseTransferable,
address royaltyPolicy,
bytes memory royaltyData,
bytes memory frameworkData
) external returns (uint256 policyId);

/// @notice returns the policy id for the given data, or 0 if not found
function getPolicyId(
address framework,
bool isLicenseTransferable,
bytes memory data
) external view returns (uint256 policyId);
function getPolicyId(Licensing.Policy calldata pol) external view returns (uint256 policyId);

/// @notice Adds a policy to an IP policy list
/// @param ipId The id of the IP
Expand All @@ -74,23 +86,25 @@ interface ILicensingModule is IModule {

/// @notice Mints a license to create derivative IP
/// @param policyId The id of the policy with the licensing parameters
/// @param licensorIpId The id of the licensor IP
/// @param licensorIp 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 of the NFT(s)
function mintLicense(
uint256 policyId,
address licensorIpId,
uint256 amount,
address receiver
address licensorIp,
LeoHChen marked this conversation as resolved.
Show resolved Hide resolved
LeoHChen marked this conversation as resolved.
Show resolved Hide resolved
uint256 amount, // mint amount
address receiver,
bytes calldata royaltyContext
) external returns (uint256 licenseId);

/// @notice Links an IP to the licensors (parent IP IDs) listed in the License NFTs, if their policies allow it,
/// burning the NFTs in the proccess. The caller must be the owner of the NFTs and the IP owner.
/// @param licenseIds The id of the licenses to burn
/// @param childIpId The id of the child IP to be linked
/// @param minRoyalty The minimum derivative rev share that the child wants from its descendants. The value is
/// overriden by the `derivativesRevShare` value of the linking licenses.
function linkIpToParents(uint256[] calldata licenseIds, address childIpId, uint32 minRoyalty) external;
/// @param royaltyContext The context for the royalty module to process
function linkIpToParents(uint256[] calldata licenseIds, address childIpId, bytes calldata royaltyContext) external;

///
/// Getters
Expand All @@ -117,6 +131,9 @@ interface ILicensingModule is IModule {
/// @notice True if policy is part of an IP's policy list
function isPolicyIdSetForIp(bool isInherited, address ipId, uint256 policyId) external view returns (bool);

/// @notice True if policy is inherited from an IP
function isPolicyInherited(address ipId, uint256 policyId) external view returns (bool);

/// @notice Gets the policy ID for an IP by index on the IP's policy list
function policyIdForIpAtIndex(
bool isInherited,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,6 @@ import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol";
/// @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 {
struct VerifyLinkResponse {
bool isLinkingAllowed;
bool isRoyaltyRequired;
address royaltyPolicy;
uint32 royaltyDerivativeRevShare;
}

/// @notice Name to be show in LNFT metadata
function name() external view returns (string memory);
/// @notice URL to the off chain legal agreement template text
Expand All @@ -25,15 +18,6 @@ interface IPolicyFrameworkManager is IERC165 {
/// Must return ERC1155 OpenSea standard compliant metadata
function policyToJson(bytes memory policyData) external view returns (string memory);

/// @notice Returns the royalty policy address of a policy ID belonging to the PFM
function getRoyaltyPolicy(uint256 policyId) external view returns (address royaltyPolicy);

/// @notice Returns the commercial revenue share of a policy ID belonging to the PFM
function getCommercialRevenueShare(uint256 policyId) external view returns (uint32 commercialRevenueShare);

/// @notice Returns whether the policy ID belonging to the PFM is commercial or non-commercial
function isPolicyCommercial(uint256 policyId) external view returns (bool);

function processInheritedPolicies(
bytes memory aggregator,
uint256 policyId,
Expand All @@ -55,5 +39,5 @@ interface IPolicyFrameworkManager is IERC165 {
address ipId,
address parentIpId,
bytes calldata policyData
) external returns (VerifyLinkResponse memory);
) external returns (bool);
LeoHChen marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@ import { IPolicyFrameworkManager } from "../../../interfaces/modules/licensing/I
/// @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 derivativesRevShare Percentage of revenue that must be shared with the licensor for derivatives of the work
/// @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 royaltyPolicy Address of a royalty policy contract (e.g. RoyaltyPolicyLS) that will handle royalty payments
/// TODO: DO NOT deploy on production networks without hashing string[] instead of storing them
struct UMLPolicy {
bool transferable;
bool attribution;
bool commercialUse;
bool commercialAttribution;
Expand All @@ -32,15 +31,24 @@ struct UMLPolicy {
bool derivativesAttribution;
bool derivativesApproval;
bool derivativesReciprocal;
uint32 derivativesRevShare;
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 umlPolicy UMLPolicy compliant licensing term values
struct RegisterUMLPolicyParams {
bool transferable;
address royaltyPolicy;
UMLPolicy policy;
}

/// @notice Struct that accumulates values of inherited policies
/// so we can verify compatibility when inheriting new policies
/// so we can verify compatibility when inheriting new policies.
/// 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 derivatives Whether or not there is a policy that allows derivatives
/// @param derivativesReciprocal Whether or not there is a policy that requires derivatives
Expand All @@ -63,17 +71,15 @@ struct UMLAggregator {
/// @notice Defines the interface for a Policy Framework Manager compliant with the UML standard
interface IUMLPolicyFrameworkManager is IPolicyFrameworkManager {
/// @notice Registers a new policy to the registry
/// @dev Must encode the policy into bytes to be stored in the LicenseRegistry
/// @param umlPolicy UMLPolicy compliant licensing term values
function registerPolicy(UMLPolicy calldata umlPolicy) external returns (uint256 policyId);
/// @notice Fetchs a policy from the registry, decoding the raw bytes into a UMLPolicy struct
/// @param policyId The ID of the policy to fetch
/// @return policy The UMLPolicy struct
function getPolicy(uint256 policyId) external view returns (UMLPolicy memory policy);

/// @notice gets the policy ID for the given policy data, or 0 if not found
function getPolicyId(UMLPolicy calldata umlPolicy) external view returns (uint256 policyId);
/// @dev must generate a Licensing.Policy struct and call registerPolicy
/// @param params parameters needed to register a UMLPolicy
/// @return policyId The ID of the newly registered policy
function registerPolicy(RegisterUMLPolicyParams calldata params) external returns (uint256 policyId);

/// @notice gets the aggregation data for inherited policies.
function getAggregator(address ipId) external view returns (UMLAggregator memory rights);

/// @notice gets the UMLPolicy 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
function getUMLPolicy(uint256 policyId) external view returns (UMLPolicy memory policy);
}
36 changes: 21 additions & 15 deletions contracts/interfaces/modules/royalty/IRoyaltyModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,6 @@ interface IRoyaltyModule is IModule {
/// @param ipId The ipId
function royaltyPolicies(address ipId) external view returns (address);

/// @notice Indicates if a royalty policy is immutable
/// @param ipId The ipId
function isRoyaltyPolicyImmutable(address ipId) external view returns (bool);

/// @notice Sets the licensing module
/// @param licensingModule The address of the licensing module
function setLicensingModule(address licensingModule) external;

/// @notice Whitelist a royalty policy
/// @param royaltyPolicy The address of the royalty policy
/// @param allowed Indicates if the royalty policy is whitelisted or not
Expand All @@ -59,16 +51,30 @@ interface IRoyaltyModule is IModule {
/// @param allowed Indicates if the token is whitelisted or not
function whitelistRoyaltyToken(address token, bool allowed) external;

/// @notice Sets the royalty policy for an ipId
/// @param ipId The ipId
/// @param royaltyPolicy The address of the royalty policy
/// @param parentIpIds The parent ipIds
/// @param data The data to initialize the policy
function setRoyaltyPolicy(
/// @notice Executes royalty related logic on license minting
/// @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
/// @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 calldata data
bytes[] memory licenseData,
LeoHChen marked this conversation as resolved.
Show resolved Hide resolved
bytes calldata externalData
) external;

/// @notice Allows a sender to to pay royalties on behalf of an ipId
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.23;

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

/// @title Liquid absolute percentage policy ancestor vault interface
interface IAncestorsVaultLAP {
/// @notice Event emitted when a claim is made
/// @param ipId The ipId address
/// @param claimerIpId The claimer ipId address
/// @param withdrawETH Indicates if the claimer wants to withdraw ETH
/// @param tokens The ERC20 tokens to withdraw
event Claimed(address ipId, address claimerIpId, bool withdrawETH, ERC20[] tokens);

/// @notice Allows an ipId to claim their rnfts and accrued royalties
/// @param ipId The ipId of the IP
/// @param claimerIpId The ipId of the claimer
/// @param ancestors The ancestors of the IP
/// @param ancestorsRoyalties The royalties of the ancestors
/// @param withdrawETH Indicates if the claimer wants to withdraw ETH
/// @param tokens The ERC20 tokens to withdraw
function claim(
address ipId,
address claimerIpId,
address[] calldata ancestors,
uint32[] calldata ancestorsRoyalties,
bool withdrawETH,
ERC20[] calldata tokens
) external;
}
26 changes: 17 additions & 9 deletions contracts/interfaces/modules/royalty/policies/IRoyaltyPolicy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,28 @@ pragma solidity ^0.8.23;

/// @title RoyaltyPolicy interface
interface IRoyaltyPolicy {
/// @notice Initializes the royalty policy
/// @param ipId The ipId
/// @param parentsIpIds The parent ipIds
/// @param data The data to initialize the policy
function initPolicy(address ipId, address[] calldata parentsIpIds, bytes calldata data) external;
/// @notice Executes royalty related logic on minting a license
/// @param _ipId The children ipId that is being linked to parents
/// @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
/// @param _ipId The children ipId that is being linked to parents
/// @param _parentIpIds The selected parent ipIds
/// @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,
LeoHChen marked this conversation as resolved.
Show resolved Hide resolved
address[] calldata _parentIpIds,
bytes[] memory _licenseData,
bytes calldata _externalData
) external;

/// @notice Allows to pay a royalty
/// @param caller The caller
/// @param ipId The ipId
/// @param token The token to pay
/// @param amount The amount to pay
function onRoyaltyPayment(address caller, address ipId, address token, uint256 amount) external;

/// @notice Returns the minimum royalty the IPAccount expects from descendants
/// @param ipId The ipId
function minRoyaltyFromDescendants(address ipId) external view returns (uint32);
}
Loading
Loading