In this article, we will analyze what True NFT is, how the technology was created, its architecture, main scenarios, talk about customization options, and answer the main question — what requirements a finished system must meet to be called True NFT.
What is True NFT?
True NFT is a technology created jointly by the developer teams Surf and RSquad to implement NFT tokens based on the Free TON network.
The technology allows:
- to be sure that all NFT data is stored on the blockchain without relying on any third-party protocols;
- to simplify and standardize queries for finding collections and user’s NFT tokens;
- users to interact with their tokens in decentralized browsers and dApps knowing only their own address, and to transfer them knowing just the recipient’s address.
At the start of development, NFT implementations already existed in the Free TON blockchain, for example, TIP-3 NFT. Also, TIP-31 has just been released, developing the ideas of TIP-3 and providing new opportunities for developing contracts, and no one has canceled the option with the implementation of the ERC-721 analogue.
The Surf and RSquad teams were tasked with studying existing solutions and developing NFT technology for Free TON that meets the following requirements:
- to focus on maximum usability: a user who only knows his Surf address should have a full set of tools to work with his NFT tokens;
- to allow the user to transfer tokens to other users or systems, knowing only the recipient’s address;
- to show tokens in the wallet without specifying additional addresses;
- to create a universal and highly customizable system;
- to save token content exclusively on-chain.
The study of existing solutions showed they do not fit the above requirements and have a lot of problems regarding the task. For example, the currently classic ERC-721 is conditionally unrealizable in Free TON because of large mappings, and TIP-3 forces users to deploy additional wallets for each NFT collection.
Moreover, you can send tokens only between these very wallets, whose addresses you need to know. Multiplying these problems because it is necessary to come up with a mechanism for getting all the user’s tokens, knowing only his address, we get the conclusion: it is necessary to come up with something new.
How the Idea Was Born and Developed
As a result of brainstorming, it became obvious to the team that each NFT wallet must generate an address so that it can be found throughout the network, for example, by storing the owner’s address in the initial data.
The solution would allow finding all the user’s wallets that contain his tokens. This approach removed a number of abstractions from TIP-3 and brought elements of TIP-31, but still left a lot of questions:
- how to transfer tokens to a user who does not yet have a wallet within the collection?
- who should pay for deploying wallets?
- how to ensure maximum customization as part of the implementation for a particular system?
All these questions prompted the team to conclude that it is necessary to get rid of wallets as part of the system.
As a result, the team decided, inspired by TIP-31, to create a new functionality — to store the owner of a specific token in the initial data, thereby making it searchable, keeping the address unique, and deleting the old contract, and deploying a new one when transferring the token.
Moreover, to put the data into a separate non-removable contract and create some kind of search indexes that can be recreated when the token owner changes. Thus, a way was found that led the team to the solution of the task.
The solution itself became possible due to the representation of the Free TON blockchain as a key:value storage, where key is a certain combination of the contract code and initial data, and value is the address or the contract itself.
In Free TON, there are many ways to find the right contract besides the usual “I know the address — I can pull”. There are a huge number of similar contracts within the network in terms of functionality (such as contests or NFT collections), and Free TON allows you to get them all.
It is enough to understand that a contract has a code, you can take a hash from it, use GraphQL and get all the addresses where the contracts corresponding to the specified code are located.
The address in Free TON is some combination of the contract code and its initial data. Thus, knowing these two parameters used in the contract deployment, it is possible to calculate its address.
It is important to understand that the code can be changed later, but the address cannot. Therefore, searching by a code hash and collecting an address are fundamentally different things.
Before the publication of TIP-31, the ability to “salt” the contract code was added, i.e. add a data set (“salt”) to the compiled code with the subsequent ability to read it. This does not affect the mechanisms described above, but it allows you to store data not only in the initial data but also in the contract code itself, adding some flexibility to the initialization process.
Thus, we got a simple concept: to make a set of immutable system contracts that will serve as search indexes, and add to them a set of contracts that will contain customized logic and data.
Figure 1 shows a contract diagram of the resulting conceptual system. The developed system core and examples can be found in the repository.
IndexBasis, or simply basis, is a contract that is used to find all NFT collections in the network. From the diagram you can see that its code is not “salted”, and the uniqueness of the address is achieved by adding a NftRoot contract address and the hash code of the Data contract. Thus, to be considered TrueNFT, each system must issue a basis for each NFT collection.
IndexOwner and IndexOwnerRoot
These contracts are combined into one group because they are essentially identical and inherit the Index contract. In other words, they have the same code, but they are needed for different purposes and are “salted” in different ways.
In both indexes, the address of the Data contract is stored in the initial data, which is a link from the index to Data. IndexOwner is “salted” with only the owner address, which allows us to search for all tokens of a specific user, and IndexOwnerRoot is “salted” with both the owner address and the NftRoot address, which allows us to find all user tokens within a specific collection in one query. Bottom line: to be considered TrueNFT, each system must issue an IndexOwner and IndexOwnerRoot for each NFT.
An NFT collection contract generally contains token-minting logic and information about a collection. It is worth noting that because the contract has a basis, implementing the contract can be completely different within different systems. The project repository and the diagram contain only an example of the basic implementation of NftRoot for a general understanding of the system concept.
The NFT token data contract, or simply NFT, contains the token data, a link to the media, usually the transfer logic, and a set of additional logic. The contract, like NftRoot, is completely customizable because the token has a different set of fields within different collections.
In the example of the basic implementation, the transfer is also implemented in Data, in order to save transactions, but in real systems, it can be moved to a separate contract or be absent altogether. To be considered TrueNFT, each system must store all NFT data in a Data contract or have links to other contracts within the network, all data from other sources is not considered part of the system.
Data includes a script to upload media and create a link to it. We will consider this aspect of the system in future publications.
We have a set of three search indexes that must be immutable within any TrueNFT systems, NftRoot and Data contracts, which contain the logic of a single system and are fully customizable.
The most important part of the technology is the transfer ownership scenario. The logic around the transfer can be absolutely any, but to be called TrueNFT, the system must preserve the NFT transition logic from one owner to another, regardless of the logic around it.
Consider a basic transfer ownership scenario in a system where the owner of a token can transfer his token to anyone. The user knows the address of the other user to whom he wants to send his NFT.
The user enters the recipient’s address in the interface and the token is transferred without additional action. The recipient can see the received token in his interface without performing any actions at all. Sounds simple. Under the hood, the user calls the transfer method from his Data contract. Next, Data deletes its search indexes, changes ownership, and deploys new indexes with a new owner in the initial data.
The data integrity is preserved. At any given time, the NFT (both in terms of indexes and in terms of the Data contract) belongs to one owner or does not belong to anyone.
Additional logic, for example, royalties to the author, can be implemented as part of the transfer ownership method itself, or there may be no method at all, and the transfer can be carried out only upon purchase — it does not matter. The important thing is that for the system to be called TrueNFT, it must preserve the logic of the transfer of ownership with the re-creation of search indexes and the change of ownership in the Data contract.
Token minting works almost the same way as a transfer.
The user who may issue tokens calls NftRoot while transferring NFT data. NftRoot deploys the Data contract, which in turn deploys its indexes. Minting rights, the presence/absence of it as such, or minting at purchase, for example, is a customizable part of the system. At the same time, for the system to be called TrueNFT, it must preserve the logic of creating tokens with date deployment and search indexes.
Search And Display
In the process, specific requirements for search capabilities were formalized. The system must allow you to find everything:
- user tokens;
- user tokens within the collection;
- tokens within the collection.
As we already know, Free TON provides us with the GraphQL API as an interface for getting data from the blockchain (in fact, of course, not directly from the blockchain, but from the caching database, which gives us additional tools for searching and filtering), from which we can get addresses.
- To get data about all user tokens, we need to take the IndexOwner contract code, salt the user’s address, hash it, and query from GraphQL API the accounts with the received code_hash.
- The same action for all collections — we take the IndexBasis contract code, hash it, query it, and get all the collections of the network.
- For user tokens within a collection, we take IndexOwnerRoot, salt it with the user’s address and the address of the collection of interest, hash it, query it.
- To find all the tokens of one collection, we just need to take the basis of this collection, and it already has a date code hash, by which we can find all the tokens of the collection, as Data is salted by the NftRoot address.
- All operations are actually performed by a single query, but, of course, to get the data directly, it will have to go through each contract separately, but the list is easy enough to get.
The answer to the question of why we need these indexes if we can customize the interface within each individual project is simple. As the ecosystem grows, catalogs showing all collections and wallets showing all user tokens will be created. Standardization in this matter will allow all systems that meet the standard to be automatically listed in these catalogs, simply by being deployed to the network.
We have deduced several requirements for a system to be considered TrueNFT, it must:
- issue IndexBasis for each NftRoot;
- issue IndexOwner and IndexOwnerRoot for each Data;
- store all data in the Data contract or to have links to other contracts within the network;
- IndexBasis, IndexOwner, and IndexOwnerRoot contracts are unified and not subjected to any changes within any TrueNFT systems;
- preserve the logic of transfer of ownership with a re-creation of search indexes and change of ownership in the Data contract.
In the next articles, we will talk about media uploading, write our simple TrueNFT system, consider examples of receiving and displaying tokens, and discuss how to develop applications that work with decentralized ledgers in modern blockchains.