Appearance
Abstract ​
This proposal introduces a generic way to represent intellectual property on chain, along with a refined royalty representation mechanism and associated metadata link. This standard is not associated with a specific type of IP and could represent many types of IP, such as musical IP, videos, books, images, and more. The standard is kept very generic to allow the industry to evolve new ecosystems that can all rely on the same basic standard at their core.
This standard allows market participants to:
- Observe the canonical on-chain representation of an intellectual property
- Discover its attached metadata
- Discover its related royalty structure
- This will enable building registration, licensing, and payout mechanisms for intellectual property assets in the future.
Motivation ​
There is no accepted standard mechanism to license intellectual property or to represent it, except using traditional NFTs. However, regular NFTs only represent a collectible item use case and cannot easily represent more complicated use cases of licensing IP for different types of uses. We can enable such licensing mechanisms if we can:
- Declare that IP exists, SEPARATELY from its purchase ability
- Declare possibly multiple interested parties to be paid for such IP
For 1, no standard exists today.
For 2, traditional split standards exist based on NFT purchases or through mechanisms like 0xsplits. While these solve the main problem, they do not contain the ability to name multiple types of collaboration participants.
Specification ​
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
contracts that want to represent IP on chain MUST implement EIP-721 AND this Proposal
This standard extends EIP-721 with the following IIPRepresentation
(IPR for short) interface. Implementers of this standard MUST have all of the following functions:
royaltyPortionTokens() function ​
This function MUST return an array of addresses related to EIP-20 tokens that MUST represent royalty portions to different types of interested parties. These royalty portion tokens represent a more granular and streamlined way to declare royalty splits for multiple collaboration participants for the creation of the IP.
For example, for a musical IP, we might have two tokens representing the composition/writing/publishing royalty portion side and the recording/master side. These royalty portion tokens are distributed to the collaboration participants and can later be queried by the various holders to distribute royalties. I.e., if one holds 10% of a royalty portion token, that holder will get 10% of the financial distribution related to that type of royalty.
metadataURI() function ​
This function MUST return the URI to a metadata file containing any required metadata for the IP or an empty string. Each IP type MAY implement its metadata standard, defined separately. The file MUST be hosted in IPFS, Arweave, or other decentralized content-addressable systems in which the file's contents are not changeable without changing the URI.
changeMetadataURI() function ​
This function allows changing the metadata URI to point to a new version of the metadata file. Calling this function MUST trigger the event MetadataChanged
in case of success.
ledger() function ​
This function MUST return the registry or registrar contract address or an EOA account that initialized the IP and associated royalty tokens. An IP representation MAY be registered in multiple places by different actors for different purposes. This function enables market participants to discover which registry mechanism is the parent of the IP and might have special access rights to manage the IP.
solidity
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.9;
import '@openzeppelin/contracts/interfaces/IERC165.sol';
///
/// @dev Interface for Intellectual Property Representation
///
interface IIPRepresentation is IERC165 {
/// @notice Called with the new URI to an updated metadata file
/// @param _newUri - the URI pointing to a metadata file (file standard is up to the implementer)
/// @param _newFileHash - The hash of the new metadata file for future reference and verification
function changeMetadataURI(string memory _newUri, string memory _newFileHash) external ;
/// @return array of addresses of ERC20 tokens representing royalty portion in the IP
/// @dev i.e implementing ERC5501 (IRoyaltyInterestToken interface)
function royaltyPortionTokens() external view returns (address[] memory) ;
/// @return the address of the contract or EOA that initialized the IP registration
/// @dev i.e., a registry or registrar, to be implemented in the future
function ledger() external view returns (address) ;
/// @return the URI of the current metadata file for the II P
function metadataURI() external view returns (string memory) ;
/// @dev event to be triggered whenever metadata URI is changed
/// @param byAddress the addresses that triggered this operation
/// @param oldURI the URI to the old metadata file before the change
/// @param oldFileHash the hash of the old metadata file before the change
/// @param newURI the URI to the new metadata file
/// @param newFileHash the hash of the new metadata file
event MetadaDataChanged(address byAddress, string oldURI, string oldFileHash, string newURI, string newFileHash);
}
Rationale ​
Returning an array of EIP-20 tokens presents a more robust royalty portions structure/ ​
Current royalty implementations deal only with a single type of royalty payment: NFT sales. They also only allow a single type of royalty - i.e., Music NFTs cannot pay different people in different scenarios. In other words, currently, a royalty split works the same way no matter what type of purchase or license deal has happened for all parties involved.
With this proposal, multiple types of royalty scenarios are allowed. A classic case is the music industry, in which we have writing/composition royalties and recording/master royalties. Different licensing types will pay different percentages to different parties based on context.
In the case of a song cover, a license payment formula can be created so that that a) Original IP's writers get paid for using the lyrics or composition of the song b) recording artists of the original song do not get paid since their recording is not used c) recording artists of the new IP will get paid d) there are no writing royalties for the creators of the cover.
Moreover, this EIP has a single structure that connects to all types of royalty types and allows finding them more easily. Lastly, moving EIP-20 tokens around is much easier than managing an 0xsplits contract.
Separating the IP contract from the collectible and licensing NFTs enables scaling licensing types ​
By separating the canonical version of the IP from its various licensed uses (NFT purchase, streaming, usage of art and more.), this EIP introduces a path for an ecosystem of various license types and payment distributions to evolve. In other words, when people use this scheme, they will not start by creating a music NFT or art NFT; they start by creating the IP Representation and then create types of licenses or collectibles for it, each as its own sellable NFT.
A single pointer to the IP's metadata ​
The IPR points to metadata housed in IPFS or Arweave and allows changing it and keeping track of the changes in a simple and standard way. Today the only metadata standard is NFT metadata extension, but it is impossible to know to which standard the document adheres. With different IP types, different metadata standards for different IP types can be formulated and have a simple, easy place to discover attached metadata.
Reference Implementation ​
Implementing a Musical IP Representation (MIPR for short) based on IIPRepresentation ​
solidity
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.9;
import '@openzeppelin/contracts/token/ERC721/ERC721.sol';
import "./interfaces/IIPRepresentation.sol";
import "./interfaces/Structs.sol";
contract MusicalIP is ERC721, IIPRepresentation {
address public songLedger;
address public compToken;
address public recToken;
string public metadataURI;
string public fileHash;
uint256 public tokenId;
bool public activated =false;
function supportsInterface(bytes4 interfaceId) public view virtual override( ERC721, IERC165) returns (bool) {
return
interfaceId == type(IIPRepresentation).interfaceId ||
super.supportsInterface(interfaceId);
}
function getInterfaceId() public pure returns (bytes4){
return type(IIPRepresentation).interfaceId;
}
constructor (
uint256 _tokenId,
address _songLedger,
SongMintingParams memory _params,
address _compAddress,
address _recAddress
)
ERC721(_params.shortName, _params.symbol){
songLedger = _songLedger;
compToken = _compAddress;
recToken = _recAddress;
metadataURI = _params.metadataUri;
fileHash = _params.fileHash;
tokenId = _tokenId;
_safeMint(_songLedger, _tokenId);
emit Minted(_params.shortName,_songLedger,_compAddress,_recAddress,_msgSender(),tokenId,_params.metadataUri);
}
function changeMetadataURI(string memory _newURI,string memory _newFileHash) public
{
string memory oldURI = metadataURI;
string memory oldHash = fileHash;
metadataURI = _newURI;
fileHash = _newFileHash;
emit MetadataChanged(oldURI, oldHash,_newURI,_newFileHash);
}
function royaltyPortionTokens() external view returns (address[] memory) {
address[] memory items = new address[](2);
items[0] = compToken;
items[1] = recToken;
return items;
}
function ledger() external view returns (address) {
return songLedger;
}
event MetadataChanged(
string oldUri, string oldFileHash,
string newUri, string newFileHash
);
event Minted(
string abbvName,
address ledger,
address compToken,
address recToken,
address creator,
uint256 tokenId,
string metadataUri
);
}
Deploying a new Musical IP using a simple song registry contract ​
solidity
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/utils/Counters.sol";
import "./MusicalIP.sol";
import "./CompositionRoyaltyToken.sol";
import "./RecordingRoyaltyToken.sol";
contract SimpleSongLedger is IERC721Receiver {
using Counters for Counters.Counter;
Counters.Counter private mipIds;
function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) {
return IERC721Receiver.onERC721Received.selector;
}
function mintSong(SongMintingParams memory _params) public {
CompositionRoyaltyToken comp = new CompositionRoyaltyToken(address(this),"SONGCOMP","COMP");
RecordingRoyaltyToken rec = new RecordingRoyaltyToken(address(this),"SONGREC","REC");
mipIds.increment();
MusicalIP mip = new MusicalIP(
mipIds.current(),
address(this),
_params,
address(comp),
address(rec)
);
}
}
Security Considerations ​
There might be potential security challenges of attackers persuading holders of royalty portion tokens to send them those tokens and gaining royalty portion in various IPRs. However, these are not specific to royalties and are a common issue with EIP-20 tokens.
In the case of the IP registration ownership, it will be recommended that registry contracts own the IP registration, which will be non-transferrable (account bound to the registry that created it).
Copyright ​
Copyright and related rights waived via CC0.