Usually with ERC721 contracts, a single contract is used for an NFT collection. While it is possible to do that with the proposed implementation for ERC1238, we can go further and take advantage of the benefits brought by modelling it after ERC115 and allow for multiple NFT collections to live inside the same contract.
Each collection is represented by a baseId
.
Example scenario: Let’s imagine a single contract for different courses, each identified by a baseId
. This extension lets you create certificates for a course where each certificate has a unique id
but also a reference to the baseId
it belongs to. As a result, one is able to lookup if an account holds a certificate for a specific course by querying by baseId
.
This extension lets you create “semi-fungible” tokens, which are non-fungible tokens with a shared baseId
embedded in their token id using bit packing. This is how each token has a reference to a baseId
.
Here’s how values are packed in the id (which is 256 bits in total):
[baseId (48 bits)][owner (160 bits)][counter (48 bits)]
baseId
is included as a reference to the collection.owner
creates a convenient namespacing and doesn’t change since the tokens are non-transferable.counter
is included to guarantee uniqueness of tokens. For example, let's imagine a game where you receive tokens when you complete a level. All levels use the same ERC128 contract and each level is represented by a baseId
. You might redo a level to get a better score (more tokens) so baseId+owner alone isn't enough, a counter helps to make each of your achievements unique while still belonging to the same collection.<aside> 💡 The token owner’s address is included to construct the token Id but there is no validation done, i.e nothing prevents someone from minting to address A a token Id which includes address B. Should this extension be more opinionated and enforce validation?
</aside>
Account balances for each baseId
are tracked via a mapping.
/**
* @dev Returns the balance of an address for a specific baseId.
*/
function balanceFromBaseId(address account, uint48 baseId) external view returns (uint256);