Skip to content

Commit

Permalink
License activation (#176)
Browse files Browse the repository at this point in the history
* hookity hook

* hook ouuuut

* lol

* wip testing

* simplify licensing

* WIP

* fixes

* more fixes

* wip

* fix tests

* typo

* separated termrepository from accesscontrol

* Update contracts/modules/licensing/LicensingModule.sol

Co-authored-by: kingster-will <[email protected]>

---------

Co-authored-by: Raul <[email protected]>
Co-authored-by: kingster-will <[email protected]>
  • Loading branch information
3 people authored Nov 18, 2023
1 parent 915f380 commit 22ce9c0
Show file tree
Hide file tree
Showing 23 changed files with 1,449 additions and 1,165 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
67 changes: 54 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 { FixedSet } from "contracts/utils/FixedSet.sol";

contract StoryProtocol {

Expand Down Expand Up @@ -228,17 +229,18 @@ contract StoryProtocol {
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 @@ -260,14 +262,53 @@ contract StoryProtocol {
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 {
MODULE_REGISTRY.execute(
IIPOrg(ipOrg_),
msg.sender,
ModuleRegistryKeys.LICENSING_MODULE,
abi.encode(
Licensing.ACTIVATE_LICENSE,
abi.encode(licenseId_)
),
new bytes[](0),
new bytes[](0)
);
}

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

}
23 changes: 12 additions & 11 deletions contracts/hooks/base/AsyncBaseHook.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { Hook } from "contracts/lib/hooks/Hook.sol";
abstract contract AsyncBaseHook is BaseHook {
using ERC165Checker for address;

address private immutable CALLBACK_CALLER;
/// @dev requestId => callback handler
mapping(bytes32 => ICallbackHandler) public callbackHandlers;

Expand All @@ -40,15 +39,10 @@ abstract contract AsyncBaseHook is BaseHook {

/// @notice Constructs the AsyncBaseHook contract.
/// @param accessControl_ The address of the access control contract.
/// @param callbackCaller_ The address of the callback caller contract.
/// @dev The constructor sets the access control and callback caller addresses.
constructor(
address accessControl_,
address callbackCaller_
) BaseHook(accessControl_) {
if (callbackCaller_ == address(0)) revert Errors.ZeroAddress();
CALLBACK_CALLER = callbackCaller_;
}
address accessControl_
) BaseHook(accessControl_) {}

/// @notice Executes an asynchronous hook.
/// @dev Modules would utilize the function to make an async call.
Expand Down Expand Up @@ -108,21 +102,28 @@ abstract contract AsyncBaseHook is BaseHook {
bytes memory hookParams_
) internal virtual returns (bytes memory hookData, bytes32 requestId);

/// @dev Internal function to get the address of the callback caller.
/// concrete hoot implementation should override the function.
/// @param requestId_ The ID of the request.
/// @return The address of the callback caller.
function _callbackCaller(bytes32 requestId_) internal view virtual returns (address);

/// @dev Internal function to handle a callback from an asynchronous call.
/// @param requestId_ The ID of the request.
/// @param callbackData_ The data returned by the callback.
function _handleCallback(
bytes32 requestId_,
bytes calldata callbackData_
bytes memory callbackData_
) internal virtual {
// Only designated callback caller can make a callback
if (msg.sender != CALLBACK_CALLER) {
address caller = _callbackCaller(requestId_);
if (msg.sender != caller) {
revert Errors.Hook_OnlyCallbackCallerCanCallback(
msg.sender,
CALLBACK_CALLER
caller
);
}

// Checking if a callback handler exists for the given request ID
if (address(callbackHandlers[requestId_]) == address(0)) {
revert Errors.Hook_InvalidAsyncRequestId(requestId_);
Expand Down
4 changes: 2 additions & 2 deletions contracts/ip-org/IPOrg.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ contract IPOrg is

/// @notice Gets the current owner of an IP asset within the IP Org.
function ownerOf(uint256 id) public view override(IIPOrg, ERC721Upgradeable) returns (address) {
return ERC721Upgradeable.ownerOf(id);
return super.ownerOf(id);
}

/// @notice Retrieves the token URI for an IP Asset within the IP Asset Org.
Expand Down Expand Up @@ -102,7 +102,7 @@ contract IPOrg is
/// @notice Registers a new IP Asset wrapper for the IP Org.
function mint(address owner_) public onlyRegistrationModule returns (uint256 id) {
totalSupply++;
id = lastIndex++;
id = ++lastIndex;
_mint(owner_, id);
}

Expand Down
3 changes: 3 additions & 0 deletions contracts/lib/AccessControl.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,7 @@ library AccessControl {
// Role that can execute Hooks
bytes32 constant HOOK_CALLER_ROLE = keccak256("HOOK_CALLER_ROLE");

// Role to set legal terms in TermsRepository
bytes32 constant TERMS_SETTER_ROLE = keccak256("TERMS_SETTER_ROLE");

}
35 changes: 24 additions & 11 deletions contracts/lib/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -250,39 +250,42 @@ library Errors {
error TermsRegistry_CommercialStatusUnset();

////////////////////////////////////////////////////////////////////////////
// LicenseCreatorModule //
// LicensingModule //
////////////////////////////////////////////////////////////////////////////

/// @notice The franchise does not exist.
error LicensingModule_NonExistentIPOrg();
error LicensingModule_CallerNotIpOrgOwner();
error LicensingModule_InvalidConfigType();
error LicensingModule_InvalidTermCommercialStatus();
error LicensingModule_IpOrgFrameworkAlreadySet();
error LicensingModule_DuplicateTermId();
error LicensingModule_InvalidIntent();
error LicensingModule_IpaNotActive();
error LicensingModule_IpaIdRequired();
error LicensingModule_CommercialLicenseNotAllowed();
error LicensingModule_NonCommercialTermsRequired();
error LicensingModule_IpOrgNotConfigured();
error LicensingModule_ipOrgTermNotFound();
error LicensingModule_ShareAlikeDisabled();

error LicensingModule_InvalidAction();
error LicensingModule_CallerNotLicensor();
error LicensingModule_ParentLicenseNotActive();
error LicensingModule_InvalidIpa();
error LicensingModule_CallerNotLicenseOwner();
error LicensingModule_CantFindParentLicenseOrRelatedIpa();
error LicensingModule_InvalidLicenseeType();
error LicensingModule_InvalidLicensorType();
////////////////////////////////////////////////////////////////////////////
// LicenseRegistry //
////////////////////////////////////////////////////////////////////////////

error LicensingModule_InvalidLicenseeType();
error LicenseRegistry_ZeroIpaRegistryAddress();
error LicenseRegistry_LNFTShouldNotHaveIpaId();
error LicenseRegistry_BoundToIpaShouldHaveIpaId();
error LicenseRegistry_UnknownLicenseId();
error LicenseRegistry_NotLicenseNFT();
error LicenseRegistry_InvalidIpa();
error LicenseRegistry_ZeroModuleRegistryAddress();
error LicenseRegistry_CallerNotLicensingModule();

error LicenseRegistry_CallerNotRevoker();
error LicenseRegistry_LicenseNotPending();
error LicenseRegistry_InvalidLicenseStatus();

////////////////////////////////////////////////////////////////////////////
// RegistrationModule //
////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -331,7 +334,7 @@ library Errors {
error RelationshipModule_UnsupportedRelationshipDst();

error RelationshipModule_InvalidConfigOperation();

error RelationshipModule_CallerNotIpOrgOwner();
error RelationshipModule_InvalidRelatable();
error RelationshipModule_RelTypeNotSet(string relType);
Expand Down Expand Up @@ -371,4 +374,14 @@ library Errors {

/// @notice The address is not the owner of the token.
error TokenGatedHook_NotTokenOwner(address tokenAddress, address ownerAddress);

////////////////////////////////////////////////////////////////////////////
// LicensorApprovalHook //
////////////////////////////////////////////////////////////////////////////

error LicensorApprovalHook_ApprovalAlreadyRequested();
error LicensorApprovalHook_InvalidLicensor();
error LicensorApprovalHook_InvalidLicenseId();
error LicensorApprovalHook_NoApprovalRequested();
error LicensorApprovalHook_InvalidResponseStatus();
}
22 changes: 16 additions & 6 deletions contracts/lib/modules/Licensing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ library Licensing {
struct License {
/// States the commercial nature of the license. All terms will follow.
bool isCommercial;
/// License status. // TODO: IPA status should follow
LicenseStatus status;
/// address granting the license
address licensor;
/// address that could make a license invalid
Expand All @@ -30,8 +32,13 @@ library Licensing {
ShortString[] termIds;
/// The data configuring each term. May be empty bytes. May be passed to the term hook
bytes[] termsData;
/// Future use
bytes data;
}

enum LicenseStatus {
Unset,
Active,
Revoked,
Pending
}

/// User facing parameters for creating a license
Expand All @@ -47,6 +54,8 @@ library Licensing {
struct RegistryAddition {
/// States the commercial nature of the license. All terms will follow.
bool isCommercial;
/// Only Active or Pending will be accepted here
LicenseStatus status;
/// address granting the license
address licensor;
/// address that could make a license invalid
Expand All @@ -59,8 +68,6 @@ library Licensing {
ShortString[] termIds;
/// The data configuring each term. May be empty bytes. May be passed to the term hook
bytes[] termsData;
/// Future use
bytes data;
}

enum LicenseeType {
Expand Down Expand Up @@ -110,12 +117,15 @@ library Licensing {
bytes[] termData;
}

/// Input for IpOrg legal terms configuration in LicenseCreatorModule
/// Input for IpOrg legal terms configuration in LicensingModule
struct FrameworkConfig {
TermsConfig comTermsConfig;
TermsConfig nonComTermsConfig;
}

/// Input for IpOrg legal terms configuration in LicenseCreatorModule (for now, the only option)
/// Input for IpOrg legal terms configuration in LicensingModule (for now, the only option)
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 BOND_LNFT_TO_IPA = keccak256("BOND_LNFT_TO_IPA");
}
15 changes: 14 additions & 1 deletion contracts/lib/modules/ProtocolLicensingTerms.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ pragma solidity ^0.8.19;

/// List of Licensing Term categories
library TermCategories {
string constant FORMAT_CATEGORIES = "FORMAT_CATEGORIES";
string constant CATEGORIZATION = "CATEGORIZATION";
string constant SHARE_ALIKE = "SHARE_ALIKE";
string constant ACTIVATION = "ACTIVATION";
string constant LICENSOR = "LICENSOR";
}

/// List of Protocol Term Ids (meaning the Licensing Module will have specific instructions
Expand All @@ -13,4 +15,15 @@ library TermCategories {
/// see https://docs.openzeppelin.com/contracts/4.x/api/utils#ShortStrings
library TermIds {
string constant NFT_SHARE_ALIKE = "NFT_SHARE_ALIKE";
string constant LICENSOR_APPROVAL = "LICENSOR_APPROVAL";
string constant FORMAT_CATEGORY = "FORMAT_CATEGORY";
string constant LICENSOR_IPORG_OR_PARENT = "LICENSOR_IPORG_OR_PARENT";
}

library TermsData {
enum LicensorConfig {
Unset,
IpOrg,
ParentLicensee
}
}
Loading

0 comments on commit 22ce9c0

Please sign in to comment.