We’re pleased to release today the Solidity smart contract implementation of our WNFT (Websites NFT) concept. You can find the release in our Github under MIT license.
This version of the WNFT contract is still experimental. Our goal in doing this is to get community feedback on the concept and implementation, but also to give builders the option to already create WNFTs themselves.
We will release ourselves a WNFT experimental website based on this smart contract in the next few weeks.
Neither the WNFT concept nor our implementation are trivial. Let’s first make an overview of things, and then highlight the key implementation ideas in the smart contract.
What is WFNT?
A WNFT is a concept of a website, where some areas of the website are controlled by an NFT.
Before WNFT, We always thought of websites as “one object”, with all the pages belonging to one person (or one company), and each webpage is seen as one object.
However, in WNFT we look at websites as a collection of objects, each object is owned by a different person.
In WNFT, not only that each webpage is a separate object, but even each area in a webpage is an object.
In our implementation of WNFT, we represent each area in each webpage by an NFT token. The person who owns this token controls what is shown in this area. To create harmony in the website, all the holders of the tokens will govern the website together.
The main thing the WNFT contract does is handle the creation and management of the token and website.
WNFT smart contract: an overview
WNFT tokens are kind of NFTs.
Hence, there is no surprise the WNFT contract is based on the ERC721 (standard for NFTs) contract from OpenZeppelin. We additionally use OpenZeppelin’s ERC165 contract (basic info about interfaces) and Ownerable contract (to prepare for a governance process in the future), both from from OpenZeppelin.
When designing the contract we took into account several facts. In later sections, we describe the functions created to handle each fact.
- Content hashes are crucial for WNFTs. Each token in WNFT must have a contenthash attached to it, determining the content shown in the area of the website corresponding to the token. The WNFT token collection as a whole must also have a contenthash attached to it as well, which is either the contenthash of the website itself or global configuration parameters of the website.
- Some of the WNFT metadata must be onchain. This allows some governance processes or minting algorithms that are otherwise impossible.
- The WNFT contract is going to be an owner of an ENS name (the ENS name of the website). For this, we created some functions to communicate with ENS.
- Minting is a challenge since we want to prepare for an uncountable amount of minting scenarios. We tried to make the minting as general as possible, giving future developers the possibility to implement their own minting mechanism. We supply for the start an example of a simple minting contract, allowing to mint a finite amount of WNFT (the amount is set by the WNFT contract owner).
- The WNFT website needs some data about the WNFT tokens, like how many exist. It also needs a way to enumerate the tokens. We could have left this data to be retrieved from The Graph, but due to their importance, we wanted to have them as part of the EVM state for easy retrieval.
WNFT and Contenthash
Contenthash has crucial importance in WNFT. A website in a WNFT is a decentralized website, so the token collection itself must set the contenthash of this website.
More importantly, If a token doesn’t set a contenthash for itself it is practically useless in WNFT.
The functions ‘setENSContenthash’ and ’setWNFTURI’ set contenthash for the collection itself.
- ’setENSContenthash’ sets the content hash of the ENS name the WNFT holds in ENS. This is the contenthash of the WNFT website.
- ’setWNFTURI’ sets a separate contenthash which’ is saved locally in the WNFT contract. This is meant for global parameters that the WNFT may use.
The functions ’setTokenURI’ and ’mintWithTokenURI’ sets contenthash for specific tokens. This contenthash will be dynamically loaded when someone visited the website and shows the content on the area in the website which correspondsto the token.
- ’setTokenURI’ sets a contenthash for the token. This is a standard function for NFTs.
- ’mintWithTokenURI’ combines minting a token and setting a contenthash. While there is also a possibility to mint tokens without a contenthash, we hope that most will use mintWithTokenURI.
We created a possibility to keep some tokens metadata onchain.
This is can be used for minting, governance, or simply to have metadata with global rules.
For example, a WNFT website may decide to sell places of two sizes, ‘small’ and ‘big’, but would like to limit the ‘big’ size to only 100 WNFT token holders. They can use onchain metadata for this.
To create a new onchain field use the ‘addTokenOnchainMetadataField’. In the parameters, you specify the field name, the address of the smart contracts that manage its logic, and its interface signature.
The interface of this smart contract needs to fit one of the interfaces that the WNFT contracts allow. We managed this list in the mapping _onchainMetadataInterface. The owner of the WNFT smart contract can add a new interface using the function ‘addInterface‘.
This version of the WNFT smart contract supports only String and Uint fields. You can add them with ‘setTokenOnchainMetadataString‘ and ‘setTokenOnchainMetadataUint’ correspondingly, or read onchain metadata with ‘tokenOnchainMetadataString‘ and ‘tokenOnchainMetadataUint‘.
Similarly, we offer onchain metadata for the whole WNFT collection. This version supports only String metadata. You can set and read it with the functions ‘setCollectionOnchainMetadata’ and read with ‘collectionOnchainMetadata’.
We already spoke about the difference between ‘mint’ function and the more recommended ‘mintWithTokenURI’ functions above.
The minting logic is stored in an external contract. The interface of this contract is specified in the file IMinting.sol.
Only the owner of the WNFT smart contract can set the minting contract using ‘setMintingContract’ function. The address of the current minting contract can be read with the ‘mintingContract’ function.
We provided a simple example of a minting contract in MintingLimitedAmount.sol. It allows minting a finite amount of WNFT tokens.
Integration with ENS
A WNFT contract owns the ENS name of the WNFT website. We added several functions to manage this name.
The functions are:
- ‘setENSNode’ and ‘ENSNode’: sets and read correspondingly the ENS node (=id of the ENS name) the contract owns.
- ‘setENSContenthash’ sets the contenthash. Reading the contenthash is done from the ENS Resolver, not from the WNFT contract.
- ‘setENSResolver’ and ‘ENSResolver’ to set and read the address of the ENS resolver the name uses.
- ‘transferENSName’ for transferring the ownership of the ENS hash to another address.
We included functions to enumerate the WNFT tokens. For this, the contract includes the keys variables
uint private keys;
Two functions are meant to use this enumeration. The function ‘tokenAmount’ returns the number of minted tokens, while the function ‘NthToke’ returns the Nth token that was minted.
We will have soon two extra releases related to the WNFT smart contract.
The first is a web app to work with the contract. The second is a WNFT experiment to test out the concept.
These two releases allow us to examine the functionality, cost, and effectiveness of the contract we release today.
In the meanwhile, we are asking for feedback from Solidity developers, dWeb enthusiasts, or anyone who is into innovative web experiments.
This work is supported by an Open Grant from Protocol Labs. We thank them for helping us to work on our dreams.