diff --git a/contracts/interfaces/workflows/ILicenseAttachmentWorkflows.sol b/contracts/interfaces/workflows/ILicenseAttachmentWorkflows.sol index 2e33cd3..007ed51 100644 --- a/contracts/interfaces/workflows/ILicenseAttachmentWorkflows.sol +++ b/contracts/interfaces/workflows/ILicenseAttachmentWorkflows.sol @@ -11,8 +11,13 @@ interface ILicenseAttachmentWorkflows { /// @notice Register Programmable IP License Terms (if unregistered) and attach it to IP. /// @param ipId The ID of the IP. /// @param terms The PIL terms to be registered. + /// @param sigAttach Signature data for attachLicenseTerms to the IP via the Licensing Module. /// @return licenseTermsId The ID of the newly registered PIL terms. - function registerPILTermsAndAttach(address ipId, PILTerms calldata terms) external returns (uint256 licenseTermsId); + function registerPILTermsAndAttach( + address ipId, + PILTerms calldata terms, + WorkflowStructs.SignatureData calldata sigAttach + ) external returns (uint256 licenseTermsId); /// @notice Mint an NFT from a SPGNFT collection, register it with metadata as an IP, /// register Programmable IPLicense diff --git a/contracts/workflows/LicenseAttachmentWorkflows.sol b/contracts/workflows/LicenseAttachmentWorkflows.sol index 407126f..63b9f3b 100644 --- a/contracts/workflows/LicenseAttachmentWorkflows.sol +++ b/contracts/workflows/LicenseAttachmentWorkflows.sol @@ -92,11 +92,21 @@ contract LicenseAttachmentWorkflows is /// @notice Register Programmable IP License Terms (if unregistered) and attach it to IP. /// @param ipId The ID of the IP. /// @param terms The PIL terms to be registered. + /// @param sigAttach Signature data for attachLicenseTerms to the IP via the Licensing Module. /// @return licenseTermsId The ID of the newly registered PIL terms. function registerPILTermsAndAttach( address ipId, - PILTerms calldata terms + PILTerms calldata terms, + WorkflowStructs.SignatureData calldata sigAttach ) external returns (uint256 licenseTermsId) { + PermissionHelper.setPermissionForModule( + ipId, + address(LICENSING_MODULE), + address(ACCESS_CONTROLLER), + ILicensingModule.attachLicenseTerms.selector, + sigAttach + ); + licenseTermsId = LicensingHelper.registerPILTermsAndAttach( ipId, address(PIL_TEMPLATE), diff --git a/test/integration/workflows/LicenseAttachmentIntegration.t.sol b/test/integration/workflows/LicenseAttachmentIntegration.t.sol index 88aec7e..9ba093f 100644 --- a/test/integration/workflows/LicenseAttachmentIntegration.t.sol +++ b/test/integration/workflows/LicenseAttachmentIntegration.t.sol @@ -49,7 +49,7 @@ contract LicenseAttachmentIntegration is BaseIntegration { }); uint256 deadline = block.timestamp + 1000; - (bytes memory signature, , bytes memory data) = _getSetPermissionSigForPeriphery({ + (bytes memory signature, , ) = _getSetPermissionSigForPeriphery({ ipId: ipId, to: licenseAttachmentWorkflowsAddr, module: licensingModuleAddr, @@ -59,18 +59,10 @@ contract LicenseAttachmentIntegration is BaseIntegration { signerSk: testSenderSk }); - IIPAccount(payable(ipId)).executeWithSig({ - to: accessControllerAddr, - value: 0, - data: data, - signer: testSender, - deadline: deadline, - signature: signature - }); - uint256 licenseTermsId = licenseAttachmentWorkflows.registerPILTermsAndAttach({ ipId: ipId, - terms: commUseTerms + terms: commUseTerms, + sigAttach: WorkflowStructs.SignatureData({ signer: testSender, deadline: deadline, signature: signature }) }); assertEq(licenseTermsId, pilTemplate.getLicenseTermsId(commUseTerms)); diff --git a/test/integration/workflows/RoyaltyIntegration.t.sol b/test/integration/workflows/RoyaltyIntegration.t.sol index 7e59b95..2a3447d 100644 --- a/test/integration/workflows/RoyaltyIntegration.t.sol +++ b/test/integration/workflows/RoyaltyIntegration.t.sol @@ -310,26 +310,15 @@ contract RoyaltyIntegration is BaseIntegration { uint256 deadline = block.timestamp + 1000; // set permission for licensing module to attach license terms to ancestor IP - { - (bytes memory signature, , bytes memory data) = _getSetPermissionSigForPeriphery({ - ipId: ancestorIpId, - to: licenseAttachmentWorkflowsAddr, - module: licensingModuleAddr, - selector: licensingModule.attachLicenseTerms.selector, - deadline: deadline, - state: IIPAccount(payable(ancestorIpId)).state(), - signerSk: testSenderSk - }); - - IIPAccount(payable(ancestorIpId)).executeWithSig({ - to: accessControllerAddr, - value: 0, - data: data, - signer: testSender, - deadline: deadline, - signature: signature - }); - } + (bytes memory signature, , ) = _getSetPermissionSigForPeriphery({ + ipId: ancestorIpId, + to: licenseAttachmentWorkflowsAddr, + module: licensingModuleAddr, + selector: licensingModule.attachLicenseTerms.selector, + deadline: deadline, + state: IIPAccount(payable(ancestorIpId)).state(), + signerSk: testSenderSk + }); // register and attach Terms A and C to ancestor IP commRemixTermsIdA = licenseAttachmentWorkflows.registerPILTermsAndAttach({ @@ -339,7 +328,8 @@ contract RoyaltyIntegration is BaseIntegration { commercialRevShare: defaultCommRevShareA, royaltyPolicy: royaltyPolicyLRPAddr, currencyToken: address(StoryUSD) - }) + }), + sigAttach: WorkflowStructs.SignatureData({ signer: testSender, deadline: deadline, signature: signature }) }); commRemixTermsIdC = licenseAttachmentWorkflows.registerPILTermsAndAttach({ @@ -349,7 +339,8 @@ contract RoyaltyIntegration is BaseIntegration { commercialRevShare: defaultCommRevShareC, royaltyPolicy: royaltyPolicyLAPAddr, currencyToken: address(StoryUSD) - }) + }), + sigAttach: WorkflowStructs.SignatureData({ signer: testSender, deadline: deadline, signature: signature }) }); // register childIpA as derivative of ancestorIp under Terms A diff --git a/test/story-nft/OrgNFT.t.sol b/test/story-nft/OrgNFT.t.sol index ebfa072..bc51ab8 100644 --- a/test/story-nft/OrgNFT.t.sol +++ b/test/story-nft/OrgNFT.t.sol @@ -73,7 +73,7 @@ contract OrgNFTTest is BaseTest { ); } - function test_OrgNFT_interfaceSupport() public { + function test_OrgNFT_interfaceSupport() public view { assertTrue(IOrgNFT(address(orgNft)).supportsInterface(type(IOrgNFT).interfaceId)); assertTrue(orgNft.supportsInterface(type(IERC721).interfaceId)); assertTrue(orgNft.supportsInterface(type(IERC721Metadata).interfaceId)); diff --git a/test/story-nft/StoryBadgeNFT.t.sol b/test/story-nft/StoryBadgeNFT.t.sol index 4919b5b..00a74d0 100644 --- a/test/story-nft/StoryBadgeNFT.t.sol +++ b/test/story-nft/StoryBadgeNFT.t.sol @@ -210,7 +210,7 @@ contract StoryBadgeNFTTest is BaseTest { bytes memory signature = _signAddress(rootStoryNftSignerSk, u.carl); vm.startPrank(u.carl); - (uint256 tokenId, address ipId) = rootStoryNft.mint(u.carl, signature); + (uint256 tokenId, ) = rootStoryNft.mint(u.carl, signature); vm.expectRevert(IStoryBadgeNFT.StoryBadgeNFT__TransferLocked.selector); rootStoryNft.approve(u.bob, tokenId); diff --git a/test/story-nft/StoryNFTFactory.t.sol b/test/story-nft/StoryNFTFactory.t.sol index d808c57..fb0369a 100644 --- a/test/story-nft/StoryNFTFactory.t.sol +++ b/test/story-nft/StoryNFTFactory.t.sol @@ -200,7 +200,7 @@ contract StoryNFTFactoryTest is BaseTest { function test_StoryNFTFactory_getStoryNftAddress() public { vm.startPrank(u.carl); - (address orgNft, uint256 orgTokenId, address orgIpId, address storyNft) = storyNftFactory.deployStoryNft({ + (, uint256 orgTokenId, address orgIpId, address storyNft) = storyNftFactory.deployStoryNft({ storyNftTemplate: defaultStoryNftTemplate, orgNftRecipient: u.carl, orgName: orgName, diff --git a/test/utils/BaseTest.t.sol b/test/utils/BaseTest.t.sol index d60ef6b..330bc4a 100644 --- a/test/utils/BaseTest.t.sol +++ b/test/utils/BaseTest.t.sol @@ -419,7 +419,7 @@ contract BaseTest is Test, DeployHelper { } /// @dev Uses `signerSk` to sign `addr` and return the signature. - function _signAddress(uint256 signerSk, address addr) internal view returns (bytes memory signature) { + function _signAddress(uint256 signerSk, address addr) internal pure returns (bytes memory signature) { bytes32 digest = keccak256(abi.encodePacked(addr)).toEthSignedMessageHash(); (uint8 v, bytes32 r, bytes32 s) = vm.sign(signerSk, digest); signature = abi.encodePacked(r, s, v); diff --git a/test/workflows/LicenseAttachmentWorkflows.t.sol b/test/workflows/LicenseAttachmentWorkflows.t.sol index a3e37d8..2104928 100644 --- a/test/workflows/LicenseAttachmentWorkflows.t.sol +++ b/test/workflows/LicenseAttachmentWorkflows.t.sol @@ -49,7 +49,7 @@ contract LicenseAttachmentWorkflowsTest is BaseTest { address payable ipId = ipAsset[1].ipId; uint256 deadline = block.timestamp + 1000; - (bytes memory signature, , bytes memory data) = _getSetPermissionSigForPeriphery({ + (bytes memory signature, , ) = _getSetPermissionSigForPeriphery({ ipId: ipId, to: address(licenseAttachmentWorkflows), module: address(licensingModule), @@ -59,25 +59,16 @@ contract LicenseAttachmentWorkflowsTest is BaseTest { signerSk: sk.alice }); - vm.prank(address(0x111)); - IIPAccount(ipId).executeWithSig({ - to: address(accessController), - value: 0, - data: data, - signer: u.alice, - deadline: deadline, - signature: signature - }); - uint256 ltAmt = pilTemplate.totalRegisteredLicenseTerms(); uint256 licenseTermsId = licenseAttachmentWorkflows.registerPILTermsAndAttach({ - ipId: ipAsset[1].ipId, + ipId: ipId, terms: PILFlavors.commercialUse({ mintingFee: 100, currencyToken: address(mockToken), royaltyPolicy: address(royaltyPolicyLAP) - }) + }), + sigAttach: WorkflowStructs.SignatureData({ signer: u.alice, deadline: deadline, signature: signature }) }); assertEq(licenseTermsId, ltAmt + 1); @@ -168,7 +159,7 @@ contract LicenseAttachmentWorkflowsTest is BaseTest { address payable ipId = ipAsset[1].ipId; uint256 deadline = block.timestamp + 1000; - (bytes memory signature, , bytes memory data) = _getSetPermissionSigForPeriphery({ + (bytes memory signature1, , ) = _getSetPermissionSigForPeriphery({ ipId: ipId, to: address(licenseAttachmentWorkflows), module: address(licensingModule), @@ -178,22 +169,24 @@ contract LicenseAttachmentWorkflowsTest is BaseTest { signerSk: sk.alice }); - IIPAccount(ipId).executeWithSig({ - to: address(accessController), - value: 0, - data: data, - signer: u.alice, - deadline: deadline, - signature: signature - }); - uint256 licenseTermsId1 = licenseAttachmentWorkflows.registerPILTermsAndAttach({ ipId: ipId, terms: PILFlavors.commercialUse({ mintingFee: 100, currencyToken: address(mockToken), royaltyPolicy: address(royaltyPolicyLAP) - }) + }), + sigAttach: WorkflowStructs.SignatureData({ signer: u.alice, deadline: deadline, signature: signature1 }) + }); + + (bytes memory signature2, , ) = _getSetPermissionSigForPeriphery({ + ipId: ipId, + to: address(licenseAttachmentWorkflows), + module: address(licensingModule), + selector: ILicensingModule.attachLicenseTerms.selector, + deadline: deadline, + state: IIPAccount(ipId).state(), + signerSk: sk.alice }); // attach the same license terms to the IP again, but it shouldn't revert @@ -203,7 +196,8 @@ contract LicenseAttachmentWorkflowsTest is BaseTest { mintingFee: 100, currencyToken: address(mockToken), royaltyPolicy: address(royaltyPolicyLAP) - }) + }), + sigAttach: WorkflowStructs.SignatureData({ signer: u.alice, deadline: deadline, signature: signature2 }) }); assertEq(licenseTermsId1, licenseTermsId2); @@ -229,7 +223,7 @@ contract LicenseAttachmentWorkflowsTest is BaseTest { uint256[] memory licenseTermsIds = new uint256[](1); licenseTermsIds[0] = licenseTermsIdParent; - (address ipIdChild, uint256 tokenIdChild) = derivativeWorkflows.mintAndRegisterIpAndMakeDerivative({ + (address ipIdChild, ) = derivativeWorkflows.mintAndRegisterIpAndMakeDerivative({ spgNftContract: address(nftContract), derivData: WorkflowStructs.MakeDerivative({ parentIpIds: parentIpIds, @@ -243,7 +237,7 @@ contract LicenseAttachmentWorkflowsTest is BaseTest { uint256 deadline = block.timestamp + 1000; - (bytes memory signature, , bytes memory data) = _getSetPermissionSigForPeriphery({ + (bytes memory signature, , ) = _getSetPermissionSigForPeriphery({ ipId: ipIdChild, to: address(licenseAttachmentWorkflows), module: address(licensingModule), @@ -253,15 +247,6 @@ contract LicenseAttachmentWorkflowsTest is BaseTest { signerSk: sk.alice }); - IIPAccount(payable(ipIdChild)).executeWithSig({ - to: address(accessController), - value: 0, - data: data, - signer: u.alice, - deadline: deadline, - signature: signature - }); - // attach a different license terms to the child ip, should revert with the correct error vm.expectRevert(CoreErrors.LicensingModule__DerivativesCannotAddLicenseTerms.selector); licenseAttachmentWorkflows.registerPILTermsAndAttach({ @@ -270,7 +255,8 @@ contract LicenseAttachmentWorkflowsTest is BaseTest { mintingFee: 100, currencyToken: address(mockToken), royaltyPolicy: address(royaltyPolicyLAP) - }) + }), + sigAttach: WorkflowStructs.SignatureData({ signer: u.alice, deadline: deadline, signature: signature }) }); } } diff --git a/test/workflows/RoyaltyWorkflows.t.sol b/test/workflows/RoyaltyWorkflows.t.sol index 378c57b..55b670d 100644 --- a/test/workflows/RoyaltyWorkflows.t.sol +++ b/test/workflows/RoyaltyWorkflows.t.sol @@ -394,7 +394,7 @@ contract RoyaltyWorkflowsTest is BaseTest { // set permission for licensing module to attach license terms to ancestor IP { - (bytes memory signature, , bytes memory data) = _getSetPermissionSigForPeriphery({ + (bytes memory signatureA, , ) = _getSetPermissionSigForPeriphery({ ipId: ancestorIpId, to: address(licenseAttachmentWorkflows), module: address(licensingModule), @@ -404,36 +404,41 @@ contract RoyaltyWorkflowsTest is BaseTest { signerSk: sk.admin }); - IIPAccount(payable(ancestorIpId)).executeWithSig({ - to: address(accessController), - value: 0, - data: data, - signer: u.admin, - deadline: deadline, - signature: signature + // register and attach Terms A and C to ancestor IP + commRemixTermsIdA = licenseAttachmentWorkflows.registerPILTermsAndAttach({ + ipId: ancestorIpId, + terms: PILFlavors.commercialRemix({ + mintingFee: defaultMintingFeeA, + commercialRevShare: defaultCommRevShareA, + royaltyPolicy: address(royaltyPolicyLRP), + currencyToken: address(mockTokenA) + }), + sigAttach: WorkflowStructs.SignatureData({ signer: u.admin, deadline: deadline, signature: signatureA }) }); } - // register and attach Terms A and C to ancestor IP - commRemixTermsIdA = licenseAttachmentWorkflows.registerPILTermsAndAttach({ - ipId: ancestorIpId, - terms: PILFlavors.commercialRemix({ - mintingFee: defaultMintingFeeA, - commercialRevShare: defaultCommRevShareA, - royaltyPolicy: address(royaltyPolicyLRP), - currencyToken: address(mockTokenA) - }) - }); + { + (bytes memory signatureC, , ) = _getSetPermissionSigForPeriphery({ + ipId: ancestorIpId, + to: address(licenseAttachmentWorkflows), + module: address(licensingModule), + selector: licensingModule.attachLicenseTerms.selector, + deadline: deadline, + state: IIPAccount(payable(ancestorIpId)).state(), + signerSk: sk.admin + }); - commRemixTermsIdC = licenseAttachmentWorkflows.registerPILTermsAndAttach({ - ipId: ancestorIpId, - terms: PILFlavors.commercialRemix({ - mintingFee: defaultMintingFeeC, - commercialRevShare: defaultCommRevShareC, - royaltyPolicy: address(royaltyPolicyLAP), - currencyToken: address(mockTokenC) - }) - }); + commRemixTermsIdC = licenseAttachmentWorkflows.registerPILTermsAndAttach({ + ipId: ancestorIpId, + terms: PILFlavors.commercialRemix({ + mintingFee: defaultMintingFeeC, + commercialRevShare: defaultCommRevShareC, + royaltyPolicy: address(royaltyPolicyLAP), + currencyToken: address(mockTokenC) + }), + sigAttach: WorkflowStructs.SignatureData({ signer: u.admin, deadline: deadline, signature: signatureC }) + }); + } // register childIpA as derivative of ancestorIp under Terms A {