Licensing (Module)

Architecture and Concepts

Picture Story Protocol as a global IP Graph, with each node being an IP Asset. Then, we can define licensing as the processes and conditions that determine how derivative IPs get connected into the graph.

The owner address of an IP Asset owns intellectual property rights such as creating derivatives, being commercially exploited, and being reproduced in different platforms. IP Assets can programmatically grant permissions for any users to exercise those rights with some autonomy via License Tokens (an NFT), which point to a particular set of conditions, known as License Terms.

The contracts in blue are built into the protocol. The contracts in white can be developed by the community or 3rd party vendor.

Blue: contracts built into the protocol. White: contracts developed by the community or 3rd party vendor.

The following document will walk through all of the major components of the Licensing Module as shown above.

License Template

πŸ—’οΈ

Contract

View the smart contract for the PIL here.

Let's first discuss the concept of License Template.

A License Template is a legal framework, written in code ("programmable"), that defines various licensing terms for an IP. Such as:

  • "Is commercial use allowed?" - true/false (bool)
  • "Is the license transferrable?" - true/false (bool)
  • "If commercial, what % of royalty do I receive?" - number

These terms and values differ per License Template.

The first example of a License Template was developed by the Story Protocol team directly, and is called the Programmable IP License (PIL πŸ’Š).

πŸ’Š

Programmable IP License Framework

To learn about the first implementation of a License Template, read this page.

License Template Requirements

License Templates are responsible for:

  • Providing a link to the actual, off-chain, legal contract template, with all the parameters, their possible values, and the correspondent legalese, in licenseTextUrl.
    • For a licensing framework to be compatible with Story Protocol, the legal text must be clear and parametrized, with each licensing parameter establishing the possible outcomes of each value.
    • The parameter values in each License Template (called "License Template terms") drive the legal text for each license agreement.
  • Defining a struct with the particular definitions of the parameters in accordance, which must be encoded into the License Terms struct (described below).
  • Providing registration methods for the License Terms, and getters.
  • Verifying that both the minter and the address linking a derivative are allowed by the License Template terms to perform those actions.
    • These conditions could be enforced by the License Template itself or through hooks. They can range from limitations on the derivative creations, token-gating LNFT holders, creative control from licensors, KYC, etc. It's up to the implementation of each License Template.
  • Verifying that the License Terms are compatible if a derivative has or will have multiple parents

Create Your Own Template

You can create your own License Template (like the PIL), but it must be approved by the Story team to be fully embedded into the protocol.

License Terms

License Terms are a particular combination of values defined in a License Template. Indeed, there can and will exist multiple License Terms (variations) for each License Template. You can imagine that a License Template generates many License Term variations.

Guarantees for License Terms

Once registered, License Terms are immutable β€” they can't be tampered with or altered, even by the License Template that generated it.

Additionally, License Terms have a unique numeric ID within the License Template they stem from. This makes License Terms reusable, meaning if someone creates License Terms with a specific set of values, it only needs to be created once and can be used by anyone else.

For example, a particular set of term values of the Programmable IP License (PILπŸ’Š), such as non-commercial usage + derivatives allowed + free minting, defines a unique License Terms with an associated ID.

License Terms Attached to IP Asset

The owner of a root IP Asset can attach License Terms to signal to other users that they can mint License Tokens of those terms to create a derivative of this IP Asset. Once License Terms are attached to an IP Asset, it is now considered "public" and anyone can mint a License Token using those terms.

Inherited License Terms

On the other hand, derivative IP Assets inherit their License Terms from the parent IP Asset. This means that when an IP Asset registers itself as a derivative, it burns the License Token and inherits the associated License Terms. The owner of this derivative cannot set new License Terms.

Expiration

License Terms support an expiration time. Once License Terms expire, any derivatives that abide by that license will no longer be able to generate revenue or create further derivatives. If an IP Asset is a derivative of multiple parents, it will expire when the soonest expiration time between the two parents is reached.

License Token

πŸ—’οΈ

Contract

View the smart contract here.

A License Token is represented as an ERC-721 NFT and contains the specific License Terms it represents. Its associated licenseTokenId is global, as there is one License Token contract.

Once License Terms are attached to an IP Asset, it becomes public so that anyone can mint a License Token for those terms. A License Token is burned when it is used to register another IP as a derivative of the original IP Asset.

A diagram showing what happens when a License Token is minted.

A diagram showing what happens when a License Token is minted.

Private Licenses

In order to mint a private License Token, the owner of a root IP Asset can issue License Tokens that have terms not yet attached to the IP Asset itself. It is important to also note that derivative IP Assets cannot issue private licenses because it is restricted to only issue licenses of its inherited terms.

Transferability of the License Token

License Tokens might be transferrable or not, depending on the values of the License Terms terms they point to.

Once a non-transferrable License Token is minted to a recipient, it is locked there forever.

Registering a Derivative

There are two ways to register a derivative IP Asset.

πŸ“˜

Small Note

An IP Asset can only register as a derivative one time. If an IP Asset has multiple parents, it must register both at the same time. Once an IP Asset is a derivative, it cannot link any more parents.

1. Using an Existing License Token

A License Token is burned when it is used to register another IP as a derivative of the original IP Asset.

2. Registering a Derivative Directly

You can also register a derivative directly, without the need for a License Token. Remember that if License Terms are attached to an IP Asset it is public to mint the License Token anyway, so this is simply a convenient way to go about it, thus skipping the middle step of minting a License Token.

License Registry

πŸ—’οΈ

Contract

View the smart contract here.

The License Registry stores the necessary state for tracking licensing, derivatives, templates, and the like:

struct LicenseRegistryStorage {
  /// The default license template address
  address defaultLicenseTemplate;
  /// The default license terms ID
  uint256 defaultLicenseTermsId;
  /// Registered license templates
  mapping(address licenseTemplate => bool isRegistered) registeredLicenseTemplates;
  /// Mapping of parent IPs to derivative IPs
  mapping(address childIpId => EnumerableSet.AddressSet parentIpIds) parentIps;
  /// Mapping of derivative IPs to parent IPs
  mapping(address parentIpId => EnumerableSet.AddressSet childIpIds) childIps;
  /// attachedLicenseTerms Mapping of attached license terms to IP IDs
  mapping(address ipId => EnumerableSet.UintSet licenseTermsIds) attachedLicenseTerms;
  /// Mapping of license templates to IP IDs
  mapping(address ipId => address licenseTemplate) licenseTemplates;
  /// Mapping of minting license configs to a licenseTerms of an IP
  mapping(bytes32 ipLicenseHash => Licensing.LicensingConfig licensingConfig) licensingConfigs;
  /// Mapping of minting license configs to an IP, the config will apply to all licenses under the IP
  mapping(address ipId => Licensing.LicensingConfig licensingConfig) licensingConfigsForIp;
}

Licensing Module

πŸ—’οΈ

Contract

View the smart contract here.

The licensing module is the main entry point for the licensing system. It is responsible for:

  • Attaching License Terms to IP Assets
  • Minting License Tokens
  • Registering derivatives
  • Setting License Configs

License Config

πŸ—’οΈ

Contract

View the smart contract here.

Optionally, you can attach a LicensingConfig to a license which contains a mintingFee and a licensingHook, as shown below. The hook contained in the config will be run before a user mints a License Token. For example, you may want to set dynamic pricing for minting the License Token based on how many have been minted, the user who is minting, etc.

/// @notice This struct is used by IP owners to define the configuration
/// when others are minting license tokens of their IP through the LicensingModule.
/// When the `mintLicenseTokens` function of LicensingModule is called, the LicensingModule will read
/// this configuration to determine the minting fee and execute the licensing hook if set.
/// IP owners can set these configurations for each License or set the configuration for the IP
/// so that the configuration applies to all licenses of the IP.
/// If both the license and IP have the configuration, then the license configuration takes precedence.
/// @param isSet Whether the configuration is set or not.
/// @param mintingFee The minting fee to be paid when minting license tokens.
/// @param licensingHook  The hook contract address for the licensing module, or address(0) if none
/// @param hookData The data to be used by the licensing hook.
struct LicensingConfig {
  bool isSet;
  uint256 mintingFee;
  address licensingHook;
  bytes hookData;
}

You can also attach the LicensingConfig to an IP as a whole, so it will execute on every license that belongs to the IP. Note that if both an IP-wide config and license-specific config are set, the license-specific config will take priority.

The hook itself is defined below. You can see it contains information about the license, who is minting the License Token, and who is receiving it. You can view the contract here.

/// @notice This function is called when the LicensingModule mints license tokens.
/// @dev The hook can be used to implement various checks and determine the minting price.
/// The hook should revert if the minting is not allowed.
/// @param caller The address of the caller who calling the mintLicenseTokens() function.
/// @param licensorIpId The ID of licensor IP from which issue the license tokens.
/// @param licenseTemplate The address of the license template.
/// @param licenseTermsId The ID of the license terms within the license template,
/// which is used to mint license tokens.
/// @param amount The amount of license tokens to mint.
/// @param receiver The address of the receiver who receive the license tokens.
/// @param hookData The data to be used by the licensing hook.
/// @return totalMintingFee The total minting fee to be paid when minting amount of license tokens.
function beforeMintLicenseTokens(
  address caller,
  address licensorIpId,
  address licenseTemplate,
  uint256 licenseTermsId,
  uint256 amount,
  address receiver,
  bytes calldata hookData
) external returns (uint256 totalMintingFee);

Note that it returns the totalMintingFee. You may be wondering, "I can set the minting fee in the License Terms, in the LicenseConfig, and return a dynamic price from beforeMintLicenseTokens. What will the final minting fee actually be?" Here is the priority:

  1. The result returned from beforeMintLicenseTokens overwrites #2 and #3
  2. The mintingFee set in the LicenseConfig overwrites #3
  3. The mintingFee set in the License Terms