Skip to content

Commit

Permalink
wip testing
Browse files Browse the repository at this point in the history
  • Loading branch information
Raul committed Nov 16, 2023
1 parent 0061422 commit 33a195a
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 43 deletions.
5 changes: 3 additions & 2 deletions contracts/IPAssetRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,13 @@ contract IPAssetRegistry is IIPAssetRegistry {
}

// Crate a new IP asset with the provided IP attributes.
ipAssetId = totalSupply++;
ipAssetId = ++totalSupply;
uint64 registrationDate = uint64(block.timestamp);
_ipAssets[ipAssetId] = IPA({
name: name_,
ipAssetType: ipAssetType_,
status: 0, // TODO(ramarti): Define status types.
// For now, let's assume 0 == unset, 1 is OK. TODO: Add status enum and synch with License status
status: 1,
registrant: registrant_,
ipOrg: ipOrg_,
hash: hash_,
Expand Down
54 changes: 41 additions & 13 deletions contracts/StoryProtocol.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { LibRelationship } from "contracts/lib/modules/LibRelationship.sol";
import { Registration } from "contracts/lib/modules/Registration.sol";
import { ModuleRegistryKeys } from "contracts/lib/modules/ModuleRegistryKeys.sol";
import { Licensing } from "contracts/lib/modules/Licensing.sol";
import "forge-std/console2.sol";

contract StoryProtocol {

Expand Down Expand Up @@ -223,22 +224,24 @@ contract StoryProtocol {
bytes[] calldata preHooksData_,
bytes[] calldata postHooksData_
) external returns (uint256) {
console2.log("createLicenseNft");
bytes memory params = abi.encode(
params_,
Licensing.LicenseeType.LNFTHolder,
abi.encode(licensee_)
);
return abi.decode(
MODULE_REGISTRY.execute(
IIPOrg(ipOrg_),
msg.sender,
ModuleRegistryKeys.LICENSING_MODULE,
params,
preHooksData_,
postHooksData_
bytes memory result = MODULE_REGISTRY.execute(
IIPOrg(ipOrg_),
msg.sender,
ModuleRegistryKeys.LICENSING_MODULE,
abi.encode(
Licensing.CREATE_LICENSE,
params
),
(uint256)
preHooksData_,
postHooksData_
);
return abi.decode(result, (uint256));
}

/// Creates a License bound to a certain IPA. It's not an NFT, the licensee will be the owner of the IPA.
Expand All @@ -255,26 +258,31 @@ contract StoryProtocol {
bytes[] calldata preHooksData_,
bytes[] calldata postHooksData_
) external returns (uint256) {
console2.log("createIpaBoundLicense");
bytes memory params = abi.encode(
params_,
Licensing.LicenseeType.BoundToIpa,
abi.encode(ipaId_)
);
return abi.decode( MODULE_REGISTRY.execute(
bytes memory result = MODULE_REGISTRY.execute(
IIPOrg(ipOrg_),
msg.sender,
ModuleRegistryKeys.LICENSING_MODULE,
params,
abi.encode(
Licensing.CREATE_LICENSE,
params
),
preHooksData_,
postHooksData_
),
(uint256));
);
return abi.decode(result, (uint256));
}

function activateLicense(
address ipOrg_,
uint256 licenseId_
) external {
console2.log("activateLicense");
MODULE_REGISTRY.execute(
IIPOrg(ipOrg_),
msg.sender,
Expand All @@ -287,4 +295,24 @@ contract StoryProtocol {
new bytes[](0)
);
}

function boundLnftToIpa(
address ipOrg_,
uint256 licenseId_,
uint256 ipaId_
) external {
console2.log("boundLnftToIpa");
MODULE_REGISTRY.execute(
IIPOrg(ipOrg_),
msg.sender,
ModuleRegistryKeys.LICENSING_MODULE,
abi.encode(
Licensing.BOUND_LNFT_TO_IPA,
abi.encode(licenseId_, ipaId_)
),
new bytes[](0),
new bytes[](0)
);
}

}
3 changes: 3 additions & 0 deletions contracts/lib/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,8 @@ library Errors {
error LicensingModule_LicenseAlreadyActivated();
error LicensingModule_CallerNotLicensor();
error LicensingModule_ParentLicenseNotActive();
error LicensingModule_InvalidIpa();
error LicensingModule_CallerNotLicenseOwner();

////////////////////////////////////////////////////////////////////////////
// LicenseRegistry //
Expand All @@ -289,6 +291,7 @@ library Errors {
error LicenseRegistry_CallerNotRevoker();
error LicenseRegistry_LicenseNotPending();
error LicenseRegistry_InvalidLicenseStatus();


////////////////////////////////////////////////////////////////////////////
// RegistrationModule //
Expand Down
1 change: 1 addition & 0 deletions contracts/lib/modules/Licensing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,5 @@ library Licensing {
bytes32 constant LICENSING_FRAMEWORK_CONFIG = keccak256("LICENSING_FRAMEWORK_CONFIG");
bytes32 constant CREATE_LICENSE = keccak256("CREATE_LICENSE");
bytes32 constant ACTIVATE_LICENSE = keccak256("ACTIVATE_LICENSE");
bytes32 constant BOUND_LNFT_TO_IPA = keccak256("BOUND_LNFT_TO_IPA");
}
65 changes: 49 additions & 16 deletions contracts/modules/licensing/LicensingModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { IPAsset } from "contracts/lib/IPAsset.sol";
import { TermIds, TermCategories } from "contracts/lib/modules/ProtocolLicensingTerms.sol";
import { ShortStringOps } from "contracts/utils/ShortStringOps.sol";

import "forge-std/console2.sol";

/// @title License Creator module
/// @notice Story Protocol module that:
/// - Enables each IP Org to select a collection of terms from the TermsRepository to form
Expand Down Expand Up @@ -141,7 +143,7 @@ contract LicensingModule is BaseModule, TermsRepository{
(bytes32 action, bytes memory params) = abi.decode(params_, (bytes32, bytes));
if (action == Licensing.CREATE_LICENSE) {
_verifyCreateLicense(ipOrg_, caller_, params);
} if (action == Licensing.ACTIVATE_LICENSE) {
} else if (action == Licensing.ACTIVATE_LICENSE) {
_verifyActivateLicense(ipOrg_, caller_, params);
} else {
revert Errors.LicensingModule_InvalidAction();
Expand Down Expand Up @@ -182,20 +184,28 @@ contract LicensingModule is BaseModule, TermsRepository{
revert Errors.LicensingModule_ParentLicenseNotActive();
}
// ------ Derivative license checks: Terms ------
FixedSet.ShortStringSet storage termIds = _getIpOrgTermIds(lParams.isCommercial, address(ipOrg_));
bytes[] storage termData = _getIpOrgTermData(lParams.isCommercial, address(ipOrg_));

// Share Alike ----
uint256 nftShareAlikeIndex = termIds.indexOf(TermIds.NFT_SHARE_ALIKE.toShortString());
// If there is no NFT_SHARE_ALIKE term, or if it is false then we cannot have
// a derivative license unless caller owns the parent license
if (nftShareAlikeIndex == FixedSet.INDEX_NOT_FOUND ||
!abi.decode(termData[nftShareAlikeIndex], (bool))
) {
address parentLicensor = LICENSE_REGISTRY.getLicensor(lParams.parentLicenseId);
if (parentLicensor != caller_) {
revert Errors.LicensingModule_ShareAlikeDisabled();
}
if (licenseeType == Licensing.LicenseeType.BoundToIpa) {
_verifyShareAlike(lParams, caller_, ipOrg_);
}

}
}

function _verifyShareAlike(Licensing.LicenseCreation memory lParams, address caller_, IIPOrg ipOrg_) private {
FixedSet.ShortStringSet storage termIds = _getIpOrgTermIds(lParams.isCommercial, address(ipOrg_));
bytes[] storage termData = _getIpOrgTermData(lParams.isCommercial, address(ipOrg_));

// Share Alike ----
uint256 nftShareAlikeIndex = termIds.indexOf(TermIds.NFT_SHARE_ALIKE.toShortString());
// If there is no NFT_SHARE_ALIKE term, or if it is false then we cannot have
// a derivative license unless caller owns the parent license
if (
nftShareAlikeIndex == FixedSet.INDEX_NOT_FOUND ||
!abi.decode(termData[nftShareAlikeIndex], (bool))
) {
address parentLicensor = LICENSE_REGISTRY.getLicensor(lParams.parentLicenseId);
if (parentLicensor != caller_) {
revert Errors.LicensingModule_ShareAlikeDisabled();
}
}
}
Expand All @@ -216,6 +226,23 @@ contract LicensingModule is BaseModule, TermsRepository{

}

function _verifyBoundNftToIpa(
IIPOrg ipOrg_,
address caller_,
bytes memory params_
) private {
(uint256 licenseId, uint256 ipaId) = abi.decode(params_, (uint256, uint256));
if (caller_ != LICENSE_REGISTRY.ownerOf(licenseId)) {
revert Errors.LicensingModule_CallerNotLicenseOwner();
}
if (!LICENSE_REGISTRY.isLicenseActive(licenseId)) {
revert Errors.LicensingModule_ParentLicenseNotActive();
}
if (IPA_REGISTRY.status(ipaId) == 0) {
revert Errors.LicensingModule_InvalidIpa();
}
}

/// Module entrypoint to create licenses
function _performAction(
IIPOrg ipOrg_,
Expand All @@ -225,8 +252,11 @@ contract LicensingModule is BaseModule, TermsRepository{
(bytes32 action, bytes memory params) = abi.decode(params_, (bytes32, bytes));
if (action == Licensing.CREATE_LICENSE) {
return _createLicense(ipOrg_, caller_, params);
} if (action == Licensing.ACTIVATE_LICENSE) {
} else if (action == Licensing.ACTIVATE_LICENSE) {
return _activateLicense(ipOrg_, caller_, params);
} else if (action == Licensing.BOUND_LNFT_TO_IPA) {
(uint256 licenseId, uint256 ipaId) = abi.decode(params_, (uint256, uint256));
LICENSE_REGISTRY.boundLnftToIpa(licenseId, ipaId);
} else {
revert Errors.LicensingModule_InvalidAction();
}
Expand Down Expand Up @@ -323,6 +353,9 @@ contract LicensingModule is BaseModule, TermsRepository{
uint256 ipaId,
address parentLicenseOwner
) private view returns (address) {
console2.log("ipaId", ipaId);
console2.log("parentLicenseOwner", parentLicenseOwner);
console2.log("IPA_REGISTRY", IPA_REGISTRY.ipAssetOwner(ipaId));
// TODO: Check for Licensor term in terms registry.
if (parentLicenseOwner != address(0) || ipaId == 0) {
return parentLicenseOwner;
Expand Down
12 changes: 1 addition & 11 deletions test/foundry/modules/licensing/BaseLicensingTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -129,17 +129,7 @@ contract BaseLicensingTest is BaseTest {
nonCommTermData = [bytes(""), bytes("")];
commTermIds = [commTextTermId];
commTermData = [bytes("")];
(uint256 rootIpaId, uint256 ignored) = spg.registerIPAsset(
address(ipOrg),
Registration.RegisterIPAssetParams({
owner: ipaOwner,
name: "bob",
ipAssetType: 2,
hash: keccak256("test")
}),
new bytes[](0),
new bytes[](0)
);
rootIpaId = _createIpAsset(ipaOwner, 2, bytes(""));
}

function getEmptyFramework() public pure returns (Licensing.FrameworkConfig memory) {
Expand Down
35 changes: 34 additions & 1 deletion test/foundry/modules/licensing/LicenseCreatorModule.Terms.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ contract LicensingCreatorModuleTermsTest is BaseLicensingTest {
new bytes[](0)
);
Licensing.License memory license = licenseRegistry.getLicense(lId);
assertTrue(licenseRegistry.isLicenseActive(lId));
assertTerms(license);
vm.expectRevert();
licenseRegistry.ownerOf(lId);
Expand Down Expand Up @@ -91,6 +92,8 @@ contract LicensingCreatorModuleTermsTest is BaseLicensingTest {
new bytes[](0)
);
Licensing.License memory license = licenseRegistry.getLicense(lId);
assertEq(uint8(license.status), uint8(Licensing.LicenseStatus.Pending));
assertFalse(licenseRegistry.isLicenseActive(lId));
console.log("lId", lId);
console.log("licenseeType", uint8(license.licenseeType));
assertEq(licenseRegistry.ownerOf(lId), ipaOwner);
Expand All @@ -99,8 +102,38 @@ contract LicensingCreatorModuleTermsTest is BaseLicensingTest {
vm.prank(ipaOwner);
licenseRegistry.transferFrom(ipaOwner, ipaOwner2, lId);
// have other guy activate license

vm.prank(ipaOwner2);
spg.activateLicense(address(ipOrg), lId);

license = licenseRegistry.getLicense(lId);
assertEq(uint8(license.status), uint8(Licensing.LicenseStatus.Pending));
assertFalse(licenseRegistry.isLicenseActive(lId));
// Fail to bound if not active
vm.expectRevert();
spg.boundLnftToIpa(
address(ipOrg),
lId,
1
);
// Bond if active
vm.prank(license.licensor);
spg.activateLicense(
address(ipOrg),
lId
);
license = licenseRegistry.getLicense(lId);
assertEq(uint8(license.status), uint8(Licensing.LicenseStatus.Active));
assertTrue(licenseRegistry.isLicenseActive(lId));
vm.prank(ipaOwner2);
spg.boundLnftToIpa(
address(ipOrg),
lId,
1
);
license = licenseRegistry.getLicense(lId);
assertEq(uint8(license.licenseeType), uint8(Licensing.LicenseeType.BoundToIpa));
assertEq(licenseRegistry.ownerOf(lId), address(0));
assertEq(licenseRegistry.getLicensee(lId), ipaOwner2);
}

}

0 comments on commit 33a195a

Please sign in to comment.