Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support for multi-license attachment in RT distribution flow #154

Merged
merged 1 commit into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ interface IRoyaltyTokenDistributionWorkflows {
/// @param allowDuplicates Set to true to allow minting an NFT with a duplicate metadata hash.
/// @return ipId The ID of the registered IP.
/// @return tokenId The ID of the minted NFT.
/// @return licenseTermsId The ID of the attached PIL terms.
/// @return licenseTermsIds The IDs of the attached PIL terms.
function mintAndRegisterIpAndAttachPILTermsAndDistributeRoyaltyTokens(
address spgNftContract,
address recipient,
WorkflowStructs.IPMetadata calldata ipMetadata,
WorkflowStructs.LicenseTermsData calldata licenseTermsData,
WorkflowStructs.LicenseTermsData[] calldata licenseTermsData,
WorkflowStructs.RoyaltyShare[] calldata royaltyShares,
bool allowDuplicates
) external returns (address ipId, uint256 tokenId, uint256 licenseTermsId);
) external returns (address ipId, uint256 tokenId, uint256[] memory licenseTermsIds);

/// @notice Mint an NFT and register the IP, make a derivative, and distribute royalty tokens.
/// @param spgNftContract The address of the SPG NFT contract.
Expand Down Expand Up @@ -53,15 +53,15 @@ interface IRoyaltyTokenDistributionWorkflows {
/// @param sigMetadataAndAttachAndConfig Signature data for setAll (metadata), attachLicenseTerms, and
/// setLicensingConfig to the IP via the Core Metadata Module and Licensing Module.
/// @return ipId The ID of the registered IP.
/// @return licenseTermsId The ID of the attached PIL terms.
/// @return licenseTermsIds The IDs of the attached PIL terms.
/// @return ipRoyaltyVault The address of the deployed royalty vault.
function registerIpAndAttachPILTermsAndDeployRoyaltyVault(
address nftContract,
uint256 tokenId,
WorkflowStructs.IPMetadata calldata ipMetadata,
WorkflowStructs.LicenseTermsData calldata licenseTermsData,
WorkflowStructs.LicenseTermsData[] calldata licenseTermsData,
WorkflowStructs.SignatureData calldata sigMetadataAndAttachAndConfig
) external returns (address ipId, uint256 licenseTermsId, address ipRoyaltyVault);
) external returns (address ipId, uint256[] memory licenseTermsIds, address ipRoyaltyVault);

/// @notice Register an IP, make a derivative, and deploy a royalty vault.
/// @param nftContract The address of the NFT contract.
Expand Down Expand Up @@ -114,5 +114,4 @@ interface IRoyaltyTokenDistributionWorkflows {
WorkflowStructs.SignatureData calldata sigMetadata,
WorkflowStructs.SignatureData calldata sigAttach
) external returns (address ipId, uint256[] memory licenseTermsIds, address ipRoyaltyVault);

}
9 changes: 3 additions & 6 deletions contracts/lib/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ library Errors {
/// @notice Royalty vault not deployed.
error RoyaltyTokenDistributionWorkflows__RoyaltyVaultNotDeployed();

/// @notice License terms data list is empty.
error RoyaltyTokenDistributionWorkflows__NoLicenseTermsData();

////////////////////////////////////////////////////////////////////////////
// SPGNFT //
////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -141,10 +144,4 @@ library Errors {
/// @param ipId The address of the already tokenized IP
/// @param token The address of the fractionalized token for the IP
error TokenizerModule__IpAlreadyTokenized(address ipId, address token);

////////////////////////////////////////////////////////////////////////////
// DEPRECATED, WILL BE REMOVED IN V1.4 //
////////////////////////////////////////////////////////////////////////////

error RoyaltyTokenDistributionWorkflows__TotalPercentagesExceeds100Percent();
}
21 changes: 21 additions & 0 deletions contracts/lib/LicensingHelper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,27 @@ import { WorkflowStructs } from "./WorkflowStructs.sol";
library LicensingHelper {
using SafeERC20 for IERC20;

/// @notice Registers multiple PIL terms and attaches them to the given IP and sets their licensing configurations.
/// @param ipId The ID of the IP.
/// @param licenseTermsData The PIL terms and licensing configuration data to be attached to the IP.
/// @return licenseTermsIds The IDs of the newly registered PIL terms.
function registerMultiplePILTermsAndAttachAndSetConfigs(
address ipId,
address pilTemplate,
address licensingModule,
WorkflowStructs.LicenseTermsData[] calldata licenseTermsData
) internal returns (uint256[] memory licenseTermsIds) {
licenseTermsIds = new uint256[](licenseTermsData.length);
for (uint256 i; i < licenseTermsData.length; i++) {
licenseTermsIds[i] = LicensingHelper.registerPILTermsAndAttachAndSetConfigs(
ipId,
pilTemplate,
licensingModule,
licenseTermsData[i]
);
}
}

/// @dev Registers PIL License Terms and attaches them to the given IP.
/// @param ipId The ID of the IP.
/// @param pilTemplate The address of the PIL License Template.
Expand Down
40 changes: 18 additions & 22 deletions contracts/workflows/LicenseAttachmentWorkflows.sol
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,12 @@ contract LicenseAttachmentWorkflows is
sigData: sigAttachAndConfig
});

licenseTermsIds = _registerMultiplePILTermsAndAttachAndSetConfigs(ipId, licenseTermsData);
licenseTermsIds = LicensingHelper.registerMultiplePILTermsAndAttachAndSetConfigs({
ipId: ipId,
pilTemplate: address(PIL_TEMPLATE),
licensingModule: address(LICENSING_MODULE),
licenseTermsData: licenseTermsData
});
}

/// @notice Mint an NFT from a SPGNFT collection, register it with metadata as an IP,
Expand Down Expand Up @@ -154,7 +159,12 @@ contract LicenseAttachmentWorkflows is
ipId = IP_ASSET_REGISTRY.register(block.chainid, spgNftContract, tokenId);
MetadataHelper.setMetadata(ipId, address(CORE_METADATA_MODULE), ipMetadata);

licenseTermsIds = _registerMultiplePILTermsAndAttachAndSetConfigs(ipId, licenseTermsData);
licenseTermsIds = LicensingHelper.registerMultiplePILTermsAndAttachAndSetConfigs({
ipId: ipId,
pilTemplate: address(PIL_TEMPLATE),
licensingModule: address(LICENSING_MODULE),
licenseTermsData: licenseTermsData
});

ISPGNFT(spgNftContract).safeTransferFrom(address(this), recipient, tokenId, "");
}
Expand Down Expand Up @@ -199,26 +209,12 @@ contract LicenseAttachmentWorkflows is

MetadataHelper.setMetadata(ipId, address(CORE_METADATA_MODULE), ipMetadata);

licenseTermsIds = _registerMultiplePILTermsAndAttachAndSetConfigs(ipId, licenseTermsData);
}

/// @notice Registers multiple PIL terms and attaches them to the given IP and sets their licensing configurations.
/// @param ipId The ID of the IP.
/// @param licenseTermsData The PIL terms and licensing configuration data to be attached to the IP.
/// @return licenseTermsIds The IDs of the newly registered PIL terms.
function _registerMultiplePILTermsAndAttachAndSetConfigs(
address ipId,
WorkflowStructs.LicenseTermsData[] calldata licenseTermsData
) private returns (uint256[] memory licenseTermsIds) {
licenseTermsIds = new uint256[](licenseTermsData.length);
for (uint256 i; i < licenseTermsData.length; i++) {
licenseTermsIds[i] = LicensingHelper.registerPILTermsAndAttachAndSetConfigs(
ipId,
address(PIL_TEMPLATE),
address(LICENSING_MODULE),
licenseTermsData[i]
);
}
licenseTermsIds = LicensingHelper.registerMultiplePILTermsAndAttachAndSetConfigs({
ipId: ipId,
pilTemplate: address(PIL_TEMPLATE),
licensingModule: address(LICENSING_MODULE),
licenseTermsData: licenseTermsData
});
}

//
Expand Down
24 changes: 16 additions & 8 deletions contracts/workflows/RoyaltyTokenDistributionWorkflows.sol
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,21 @@ contract RoyaltyTokenDistributionWorkflows is
/// @param allowDuplicates Set to true to allow minting an NFT with a duplicate metadata hash.
/// @return ipId The ID of the registered IP.
/// @return tokenId The ID of the minted NFT.
/// @return licenseTermsId The ID of the attached PIL terms.
/// @return licenseTermsIds The IDs of the attached PIL terms.
function mintAndRegisterIpAndAttachPILTermsAndDistributeRoyaltyTokens(
address spgNftContract,
address recipient,
WorkflowStructs.IPMetadata calldata ipMetadata,
WorkflowStructs.LicenseTermsData calldata licenseTermsData,
WorkflowStructs.LicenseTermsData[] calldata licenseTermsData,
WorkflowStructs.RoyaltyShare[] calldata royaltyShares,
bool allowDuplicates
) external onlyMintAuthorized(spgNftContract) returns (address ipId, uint256 tokenId, uint256 licenseTermsId) {
)
external
onlyMintAuthorized(spgNftContract)
returns (address ipId, uint256 tokenId, uint256[] memory licenseTermsIds)
{
if (licenseTermsData.length == 0) revert Errors.RoyaltyTokenDistributionWorkflows__NoLicenseTermsData();

tokenId = ISPGNFT(spgNftContract).mintByPeriphery({
to: address(this),
payer: msg.sender,
Expand All @@ -146,7 +152,7 @@ contract RoyaltyTokenDistributionWorkflows is
ipId = IP_ASSET_REGISTRY.register(block.chainid, spgNftContract, tokenId);
MetadataHelper.setMetadata(ipId, address(CORE_METADATA_MODULE), ipMetadata);

licenseTermsId = LicensingHelper.registerPILTermsAndAttachAndSetConfigs({
licenseTermsIds = LicensingHelper.registerMultiplePILTermsAndAttachAndSetConfigs({
ipId: ipId,
pilTemplate: address(PIL_TEMPLATE),
licensingModule: address(LICENSING_MODULE),
Expand Down Expand Up @@ -217,15 +223,17 @@ contract RoyaltyTokenDistributionWorkflows is
/// @param sigMetadataAndAttachAndConfig Signature data for setAll (metadata), attachLicenseTerms, and
/// setLicensingConfig to the IP via the Core Metadata Module and Licensing Module.
/// @return ipId The ID of the registered IP.
/// @return licenseTermsId The ID of the attached PIL terms.
/// @return licenseTermsIds The IDs of the attached PIL terms.
/// @return ipRoyaltyVault The address of the deployed royalty vault.
function registerIpAndAttachPILTermsAndDeployRoyaltyVault(
address nftContract,
uint256 tokenId,
WorkflowStructs.IPMetadata calldata ipMetadata,
WorkflowStructs.LicenseTermsData calldata licenseTermsData,
WorkflowStructs.LicenseTermsData[] calldata licenseTermsData,
WorkflowStructs.SignatureData calldata sigMetadataAndAttachAndConfig
) external returns (address ipId, uint256 licenseTermsId, address ipRoyaltyVault) {
) external returns (address ipId, uint256[] memory licenseTermsIds, address ipRoyaltyVault) {
if (licenseTermsData.length == 0) revert Errors.RoyaltyTokenDistributionWorkflows__NoLicenseTermsData();

ipId = IP_ASSET_REGISTRY.register(block.chainid, nftContract, tokenId);

address[] memory modules = new address[](3);
Expand All @@ -246,7 +254,7 @@ contract RoyaltyTokenDistributionWorkflows is

MetadataHelper.setMetadata(ipId, address(CORE_METADATA_MODULE), ipMetadata);

licenseTermsId = LicensingHelper.registerPILTermsAndAttachAndSetConfigs({
licenseTermsIds = LicensingHelper.registerMultiplePILTermsAndAttachAndSetConfigs({
ipId: ipId,
pilTemplate: address(PIL_TEMPLATE),
licensingModule: address(LICENSING_MODULE),
Expand Down
Loading
Loading