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(deriv): use batch permissions for derivative registration #155

Merged
merged 1 commit into from
Dec 21, 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
14 changes: 6 additions & 8 deletions contracts/interfaces/workflows/IDerivativeWorkflows.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,15 @@ interface IDerivativeWorkflows {
/// @param tokenId The ID of the NFT.
/// @param derivData The derivative data to be used for registerDerivative.
/// @param ipMetadata OPTIONAL. The desired metadata for the newly registered IP.
/// @param sigMetadata OPTIONAL. Signature data for setAll (metadata) for the IP via the Core Metadata Module.
/// @param sigRegister Signature data for registerDerivative for the IP via the Licensing Module.
/// @param sigMetadataAndRegister OPTIONAL. Signature data for setAll (metadata) for the IP via the Core Metadata Module
/// and registerDerivative for the IP via the Licensing Module.
/// @return ipId The ID of the newly registered IP.
function registerIpAndMakeDerivative(
address nftContract,
uint256 tokenId,
WorkflowStructs.MakeDerivative calldata derivData,
WorkflowStructs.IPMetadata calldata ipMetadata,
WorkflowStructs.SignatureData calldata sigMetadata,
WorkflowStructs.SignatureData calldata sigRegister
WorkflowStructs.SignatureData calldata sigMetadataAndRegister
) external returns (address ipId);

/// @notice Mint an NFT from a SPGNFT collection and register it as a derivative IP using license tokens.
Expand Down Expand Up @@ -70,8 +69,8 @@ interface IDerivativeWorkflows {
/// @param royaltyContext The context for royalty module, should be empty for Royalty Policy LAP.
/// @param maxRts The maximum number of royalty tokens that can be distributed to the external royalty policies.
/// @param ipMetadata OPTIONAL. The desired metadata for the newly registered IP.
/// @param sigMetadata OPTIONAL. Signature data for setAll (metadata) for the IP via the Core Metadata Module.
/// @param sigRegister Signature data for registerDerivativeWithLicenseTokens for the IP via the Licensing Module.
/// @param sigMetadataAndRegister Signature data for setAll (metadata) for the IP via the Core Metadata Module
/// and registerDerivativeWithLicenseTokens for the IP via the Licensing Module.
/// @return ipId The ID of the newly registered IP.
function registerIpAndMakeDerivativeWithLicenseTokens(
address nftContract,
Expand All @@ -80,8 +79,7 @@ interface IDerivativeWorkflows {
bytes calldata royaltyContext,
uint32 maxRts,
WorkflowStructs.IPMetadata calldata ipMetadata,
WorkflowStructs.SignatureData calldata sigMetadata,
WorkflowStructs.SignatureData calldata sigRegister
WorkflowStructs.SignatureData calldata sigMetadataAndRegister
) external returns (address ipId);

////////////////////////////////////////////////////////////////////////////
Expand Down
Original file line number Diff line number Diff line change
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);

}
74 changes: 37 additions & 37 deletions contracts/workflows/DerivativeWorkflows.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { MulticallUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/MulticallUpgradeable.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

import { ICoreMetadataModule } from "@storyprotocol/core/interfaces/modules/metadata/ICoreMetadataModule.sol";
import { ILicenseToken } from "@storyprotocol/core/interfaces/ILicenseToken.sol";
import { ILicensingModule } from "@storyprotocol/core/interfaces/modules/licensing/ILicensingModule.sol";
import { IRoyaltyModule } from "@storyprotocol/core/interfaces/modules/royalty/IRoyaltyModule.sol";
Expand Down Expand Up @@ -151,33 +152,33 @@ contract DerivativeWorkflows is
/// @param tokenId The ID of the NFT.
/// @param derivData The derivative data to be used for registerDerivative.
/// @param ipMetadata OPTIONAL. The desired metadata for the newly registered IP.
/// @param sigMetadata OPTIONAL. Signature data for setAll (metadata) for the IP via the Core Metadata Module.
/// @param sigRegister Signature data for registerDerivative for the IP via the Licensing Module.
/// @param sigMetadataAndRegister OPTIONAL. Signature data for setAll (metadata) for the IP via the Core Metadata
/// Module and registerDerivative for the IP via the Licensing Module.
/// @return ipId The ID of the newly registered IP.
function registerIpAndMakeDerivative(
address nftContract,
uint256 tokenId,
WorkflowStructs.MakeDerivative calldata derivData,
WorkflowStructs.IPMetadata calldata ipMetadata,
WorkflowStructs.SignatureData calldata sigMetadata,
WorkflowStructs.SignatureData calldata sigRegister
WorkflowStructs.SignatureData calldata sigMetadataAndRegister
) external returns (address ipId) {
ipId = IP_ASSET_REGISTRY.register(block.chainid, nftContract, tokenId);
MetadataHelper.setMetadataWithSig(
ipId,
address(CORE_METADATA_MODULE),
address(ACCESS_CONTROLLER),
ipMetadata,
sigMetadata
);

PermissionHelper.setPermissionForModule(
ipId,
address(LICENSING_MODULE),
address(ACCESS_CONTROLLER),
ILicensingModule.registerDerivative.selector,
sigRegister
);
address[] memory modules = new address[](2);
bytes4[] memory selectors = new bytes4[](2);
modules[0] = address(CORE_METADATA_MODULE);
modules[1] = address(LICENSING_MODULE);
selectors[0] = ICoreMetadataModule.setAll.selector;
selectors[1] = ILicensingModule.registerDerivative.selector;
PermissionHelper.setBatchPermissionForModules({
ipId: ipId,
accessController: address(ACCESS_CONTROLLER),
modules: modules,
selectors: selectors,
sigData: sigMetadataAndRegister
});

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

LicensingHelper.collectMintFeesAndMakeDerivative(
ipId,
Expand Down Expand Up @@ -233,8 +234,8 @@ contract DerivativeWorkflows is
/// @param royaltyContext The context for royalty module, should be empty for Royalty Policy LAP.
/// @param maxRts The maximum number of royalty tokens that can be distributed to the external royalty policies.
/// @param ipMetadata OPTIONAL. The desired metadata for the newly registered IP.
/// @param sigMetadata OPTIONAL. Signature data for setAll (metadata) for the IP via the Core Metadata Module.
/// @param sigRegister Signature data for registerDerivativeWithLicenseTokens for the IP via the Licensing Module.
/// @param sigMetadataAndRegister Signature data for setAll (metadata) for the IP via the Core Metadata Module
/// and registerDerivativeWithLicenseTokens for the IP via the Licensing Module.
/// @return ipId The ID of the newly registered IP.
function registerIpAndMakeDerivativeWithLicenseTokens(
address nftContract,
Expand All @@ -243,27 +244,26 @@ contract DerivativeWorkflows is
bytes calldata royaltyContext,
uint32 maxRts,
WorkflowStructs.IPMetadata calldata ipMetadata,
WorkflowStructs.SignatureData calldata sigMetadata,
WorkflowStructs.SignatureData calldata sigRegister
WorkflowStructs.SignatureData calldata sigMetadataAndRegister
) external returns (address ipId) {
_collectLicenseTokens(licenseTokenIds, address(LICENSE_TOKEN));

ipId = IP_ASSET_REGISTRY.register(block.chainid, nftContract, tokenId);
MetadataHelper.setMetadataWithSig(
ipId,
address(CORE_METADATA_MODULE),
address(ACCESS_CONTROLLER),
ipMetadata,
sigMetadata
);

PermissionHelper.setPermissionForModule(
ipId,
address(LICENSING_MODULE),
address(ACCESS_CONTROLLER),
ILicensingModule.registerDerivativeWithLicenseTokens.selector,
sigRegister
);
address[] memory modules = new address[](2);
bytes4[] memory selectors = new bytes4[](2);
modules[0] = address(CORE_METADATA_MODULE);
modules[1] = address(LICENSING_MODULE);
selectors[0] = ICoreMetadataModule.setAll.selector;
selectors[1] = ILicensingModule.registerDerivativeWithLicenseTokens.selector;
PermissionHelper.setBatchPermissionForModules({
ipId: ipId,
accessController: address(ACCESS_CONTROLLER),
modules: modules,
selectors: selectors,
sigData: sigMetadataAndRegister
});

MetadataHelper.setMetadata(ipId, address(CORE_METADATA_MODULE), ipMetadata);
LICENSING_MODULE.registerDerivativeWithLicenseTokens(ipId, licenseTokenIds, royaltyContext, maxRts);
}

Expand Down
31 changes: 31 additions & 0 deletions test/integration/BaseIntegration.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,37 @@ contract BaseIntegration is Test, Script, StoryProtocolCoreAddressManager, Story
/*//////////////////////////////////////////////////////////////////////////
HELPERS
//////////////////////////////////////////////////////////////////////////*/
/// @dev Get the permission list for setting metadata and registering a derivative for the IP.
/// @param ipId The ID of the IP that the permissions are for.
/// @param to The address of the periphery contract to receive the permission.
/// @return permissionList The list of permissions for setting metadata and registering a derivative.
function _getMetadataAndDerivativeRegistrationPermissionList(
address ipId,
address to,
bool withLicenseToken
) internal view returns (AccessPermission.Permission[] memory permissionList) {
address[] memory modules = new address[](2);
bytes4[] memory selectors = new bytes4[](2);
permissionList = new AccessPermission.Permission[](2);
modules[0] = coreMetadataModuleAddr;
modules[1] = licensingModuleAddr;
selectors[0] = ICoreMetadataModule.setAll.selector;
if (withLicenseToken) {
selectors[1] = ILicensingModule.registerDerivativeWithLicenseTokens.selector;
} else {
selectors[1] = ILicensingModule.registerDerivative.selector;
}
for (uint256 i = 0; i < 2; i++) {
permissionList[i] = AccessPermission.Permission({
ipAccount: ipId,
signer: to,
to: modules[i],
func: selectors[i],
permission: AccessPermission.ALLOW
});
}
}

/// @dev Get the permission list for attaching license terms and setting licensing config for the IP.
/// @param ipId The ID of the IP that the permissions are for.
/// @param to The address of the periphery contract to receive the permission.
Expand Down
79 changes: 24 additions & 55 deletions test/integration/workflows/DerivativeIntegration.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -100,26 +100,18 @@ contract DerivativeIntegration is BaseIntegration {

uint256 deadline = block.timestamp + 1000;

(bytes memory sigMetadata, bytes32 sigRegisterState, ) = _getSetPermissionSigForPeriphery({
(bytes memory signatureMetadataAndRegister, bytes32 expectedState, ) = _getSetBatchPermissionSigForPeriphery({
ipId: childIpId,
to: derivativeWorkflowsAddr,
module: coreMetadataModuleAddr,
selector: ICoreMetadataModule.setAll.selector,
permissionList: _getMetadataAndDerivativeRegistrationPermissionList(
childIpId,
address(derivativeWorkflows),
false
),
deadline: deadline,
state: bytes32(0),
signerSk: testSenderSk
});

(bytes memory sigRegister, bytes32 expectedState, ) = _getSetPermissionSigForPeriphery({
ipId: childIpId,
to: derivativeWorkflowsAddr,
module: licensingModuleAddr,
selector: ILicensingModule.registerDerivative.selector,
deadline: deadline,
state: sigRegisterState,
signerSk: testSenderSk
});

StoryUSD.mint(testSender, testMintFee);
StoryUSD.approve(derivativeWorkflowsAddr, testMintFee); // for derivative minting fee
derivativeWorkflows.registerIpAndMakeDerivative({
Expand All @@ -135,15 +127,10 @@ contract DerivativeIntegration is BaseIntegration {
maxRevenueShare: 0
}),
ipMetadata: testIpMetadata,
sigMetadata: WorkflowStructs.SignatureData({
signer: testSender,
deadline: deadline,
signature: sigMetadata
}),
sigRegister: WorkflowStructs.SignatureData({
sigMetadataAndRegister: WorkflowStructs.SignatureData({
signer: testSender,
deadline: deadline,
signature: sigRegister
signature: signatureMetadataAndRegister
})
});

Expand Down Expand Up @@ -255,38 +242,17 @@ contract DerivativeIntegration is BaseIntegration {
licenseTokenIds[0] = startLicenseTokenId;
licenseToken.approve(derivativeWorkflowsAddr, startLicenseTokenId);

WorkflowStructs.SignatureData memory sigMetadata;
WorkflowStructs.SignatureData memory sigRegister;
{
(bytes memory signatureMetadata, bytes32 sigRegisterState, ) = _getSetPermissionSigForPeriphery({
ipId: childIpId,
to: derivativeWorkflowsAddr,
module: coreMetadataModuleAddr,
selector: ICoreMetadataModule.setAll.selector,
deadline: deadline,
state: bytes32(0),
signerSk: testSenderSk
});
(bytes memory signatureRegister, bytes32 expectedState, ) = _getSetPermissionSigForPeriphery({
ipId: childIpId,
to: derivativeWorkflowsAddr,
module: licensingModuleAddr,
selector: ILicensingModule.registerDerivativeWithLicenseTokens.selector,
deadline: deadline,
state: sigRegisterState,
signerSk: testSenderSk
});
sigMetadata = WorkflowStructs.SignatureData({
signer: testSender,
deadline: deadline,
signature: signatureMetadata
});
sigRegister = WorkflowStructs.SignatureData({
signer: testSender,
deadline: deadline,
signature: signatureRegister
});
}
(bytes memory signatureMetadataAndRegister, bytes32 expectedState, ) = _getSetBatchPermissionSigForPeriphery({
ipId: childIpId,
permissionList: _getMetadataAndDerivativeRegistrationPermissionList(
childIpId,
address(derivativeWorkflows),
true
),
deadline: deadline,
state: bytes32(0),
signerSk: testSenderSk
});

derivativeWorkflows.registerIpAndMakeDerivativeWithLicenseTokens({
nftContract: address(spgNftContract),
Expand All @@ -295,8 +261,11 @@ contract DerivativeIntegration is BaseIntegration {
royaltyContext: "",
maxRts: revShare,
ipMetadata: testIpMetadata,
sigMetadata: sigMetadata,
sigRegister: sigRegister
sigMetadataAndRegister: WorkflowStructs.SignatureData({
signer: testSender,
deadline: deadline,
signature: signatureMetadataAndRegister
})
});

assertTrue(ipAssetRegistry.isRegistered(childIpId));
Expand Down
Loading
Loading