TON Project Development Tutorial (I): How to create an NFT on TON Chain from a source code perspective?

All articles8个月前更新 wyatt
53 0 0
TON EcosystemDAppDevelopment is really interesting.

Author: @Web3Mario

Summary:Following the previous article about the introduction of TON technology, I have studied the official development documents of TON in depth during this period. I feel that there are still some barriers to learning. The current document content seems to be more like an internal development document, which is not very friendly to new developers. Therefore, I try to sort out a series of articles about the development of the TON Chain project based on my own learning trajectory, hoping to help everyone quickly get started with TON. DAppThe development is of some help. If there are any mistakes in the text, you are welcome to correct them and learn together.

What are the differences between developing NFTs in EVM and developing NFTs on TON Chain?

发行一个FT或NFT对于DApp开发者来说通常是最基本的需求。因此我也以此作为学习入口。首先让我们来了解以下在EVM技术栈中开发一个NFT和在TON Chain中的区别。基于EVM的NFT通常会选择继承ERC-721的标准。所谓NFT,指的是不可分割的加密资产类型,且每个资产具有唯一性,即存在某些专属的特性。而ERC-721就是对这个类型的资产的一种通用的开发范式。让我们看一个常见的ERC721contractWhat functions need to be implemented and what information needs to be recorded. The following figure is an ERC721 interface. It can be seen that unlike FT, what needs to be entered in the transfer interface is the tokenId to be transferred rather than the amount. This tokenId is also the most basic embodiment of the uniqueness of NFT assets. Of course, in order to carry more attributes, a metadata is usually recorded for each tokenId. This metadata is an external link that saves other extensible data of the NFT, such as a link to a PFP picture, certain attribute names, etc.

TON 项目开发教程(一):源码角度看如何在 TON Chain 上创建一个 NFT?

For developers who are familiar with Solidity or object-oriented programming, implementing such an intelligentcontract是件容易的事,只要定义好contract中需要的数据类型,例如一些关键的映射关系mapping,并根据所需功能开发相应的对这些数据的修改逻辑,即可实现一个NFT。

However, in TON Chain, everything is different. There are two core reasons for this difference:

l Xiaobai NavigationIn TON, data storage is based on Cell, and the Cell of the same account is implemented through a directed acyclic graph. This means that the data that needs to be stored cannot grow indefinitely, because for a directed acyclic graph, the query cost is determined by the depth of the data. When the depth is infinitely extended, the query cost may be too high, causing the contract to fall into a deadlock problem.

In pursuit of high concurrent performance, TON abandoned the serial execution architecture and adopted a development paradigm designed for parallelism.Actor Model, to reconstruct the execution environment. This has an impact that smart contracts can only be called asynchronously by sending so-called internal messages. Note that this principle must be followed for both state modification type and read-only type calls. In addition, it is also necessary to carefully consider how to handle data rollback if the asynchronous call fails.

Of course, other technical differences have been discussed in detail in the previous article. This article hopes to focus on smart contract development, so we will not discuss it in detail. The above two design principles make the smart contract development in TON very different from EVM. In the initial discussion, we know that some mapping relationships, that is, mapping, need to be defined in an NFT contract to save NFT-related data. The most important of these is owners. This mapping stores the mapping relationship between the owner address of the NFT corresponding to a tokenID, which determines the ownership of the NFT. The transfer is a modification of the ownership. In theory, this is a data structure that can be boundless and needs to be avoided as much as possible. Therefore, the official recommendation is to use the existence of a boundless data structure as the standard for sharding. That is, when there are similar data storage requirements, throughThe master-slave contract paradigmInstead, we create sub-contracts to manage the data corresponding to each key. We also use the main contract to manage global parameters or help process internal information interactions between sub-contracts.

This means that NFTs in TON also need to be designed with a similar architecture. Each NFT is an independent sub-contract that stores exclusive data such as the owner's address and metadata, and manages global data such as NFT name, symbol, total supply, etc. through a main contract.

After clarifying the architecture, the next step is to solve the core function requirements. Due to the use of this master-slave contract method,

Therefore, it is necessary to clarify which functions are carried by the main contract and which functions are carried by the sub-contract, and what internal information is communicated between the two. At the same time, when an execution error occurs, how to roll back the previous data. Usually, before developing a complex large-scale project, it is necessary to use a class diagram and clarify the information flow between each other, and carefully think about the rollback logic after the internal call fails. Of course, although the above NFT development is simple, similar verification can also be done.

TON 项目开发教程(一):源码角度看如何在 TON Chain 上创建一个 NFT?

Learn to develop TON smart contracts from source code

TON has chosen to design a C-like, statically typed language called Func as a smart contract development language. Let’s learn how to develop TON smart contracts from the source code. I have chosen the NFT example in the TON official documentation to introduce it.Interested friends can check it out by themselvesIn this case, a simple TON NFT example is implemented. Let's take a look at the contract structure, which is divided into two functional contracts and three necessary libraries.

TON 项目开发教程(一):源码角度看如何在 TON Chain 上创建一个 NFT?

These two main functional contracts are designed according to the above principles. First, let’s take a look at the main contract.nft-collection code:

TON 项目开发教程(一):源码角度看如何在 TON Chain 上创建一个 NFT?

This introduces the first knowledge point, how to persist data in TON smart contracts. We know that in Solidity, the persistent storage of data is automatically handled by EVM according to the type of parameters. Normally, the state variables of the smart contract will be automatically persisted according to the latest value after the execution, and developers do not need to consider this process. But this is not the case in Func. Developers need to implement the corresponding processing logic themselves. This situation is somewhat similar to the process of considering GC in C and C++, but other new development languages usually automate this part of the logic. Let's take a look at the code. First, we introduce some required libraries, and then we see that the first function load_data is used to read the persistently stored data. Its logic is to first return the persistent contract storage cell through get_data. Note that this is implemented by the standard library stdlib.fc. Usually, some of these functions can be used as system functions.

The return value type of this function is cell, which is the cell type in TVM. In the previous introduction, we already know that TON BlockchainAll persistent data in is stored in the cell tree. Each cell has up to 1023 bits of arbitrary data and up to four references to other cells. Cells are used as memory in the stack-based TVM. Cells store tightly encoded data. To obtain the specific plaintext data in them, the cell needs to be converted to a type called a slice. Cells can be converted to slice type through the begin_parse function, and then the data in the cell can be obtained by loading data bits and references to other cells from the slice. Note that this calling method in line 15 of the code is a syntactic sugar in a func, which can directly call the second function of the return value of the first function. And finally load the corresponding data in the order of data persistence. Note that this process is different from solidity and is not called according to the hashmap, so the calling order cannot be messed up.

In the save_data function, the logic is similar, except that this is a reverse process, which introduces the next knowledge point, a new type builder, which is the type of cell builder. Data bits and references to other cells can be stored in the builder, and then the builder can eventually be transformed into a new cell. First, create a builder through the standard function begin_cell, and store related functions in turn through the store related functions. Note that the calling order in the above text must be consistent with the storage order here. Finally, the new cell construction is completed through end_cell. At this time, the cell is managed in memory, and finally through the outermost set_data, the persistent storage of the cell can be completed.

TON 项目开发教程(一):源码角度看如何在 TON Chain 上创建一个 NFT?

Next, let's look at business-related functions. First, we need to introduce the next knowledge point, how to create a new contract through a contract, which will be frequently used in the master-slave architecture just introduced. We know that in TON, calls between smart contracts are implemented by sending internal messages. This is implemented through a function called send_raw_message. Note that the first parameter is the cell after the message is encoded, and the second parameter is the flag, which is used to indicate the difference in the execution method of the transaction. Different execution methods for sending internal messages are set in TON. There are currently 3 message modes and 3 message flags. A single mode can be combined with multiple (perhaps no) flags to obtain the desired mode. Combining just means filling in the sum of their values.The following is a description table of Modes and Flags:

TON 项目开发教程(一):源码角度看如何在 TON Chain 上创建一个 NFT?

So let's look at the first main function, deploy_nft_item, as the name implies, is a function used to create or mint a new NFT instance. After some operations, it encodes a msg, sends the internal contract through send_raw_message, and selects the flag 1 sending flag, and only uses the fee specified in the encoding as the gas fee for this execution. After the above introduction, it is easy to realize that this encoding rule should correspond to the way to create a new smart contract.

So let’s take a look at how this is done.

Let's look directly at line 51. The two functions above are auxiliary functions for generating the information required for the message, so we will look at them later. This is an encoding process for creating an internal message of a smart contract. The numbers in the middle are actually some identification bits, which are used to illustrate the requirements of the internal message. Here we need to introduce the next knowledge point. TON chose a binary language called TL-B to describe the execution method of the message, and implemented internal messages with certain specific functions by setting different marker bits. The two most easily thought of usage scenarios are new contract creation and deployed contract function calls. The method in line 51 corresponds to the former, creating a newnft item contract, which is mainly specified by lines 55, 56, and 57. First of all, the long string of numbers in line 55 is a series of identification bits. Note that the first input parameter of store_uint is the value, and the second is the bit length. The last three flag bits determine that the internal message is created by the contract, and the corresponding binary value bits are 111 (4+2+1 in decimal). The first two indicate that the message will be accompanied by StateInit data, which is the source code of the new contract and the data required for initialization. The latter flag bit indicates that the internal message is attached, that is, it is hoped to execute the relevant logic and the required parameters. Therefore, you will see that the three bits of data are not set in the code on line 66, indicating a function call to a deployed contract.Specific encoding rules can be found here.

Then the encoding rule of StateInit corresponds to 49 lines of code, which is calculated by calculate_nft_item_state_init. Note that the encoding of stateinit data also follows an established TL-B encoding rule. In addition to some markers, it mainly involves two parts: new contract code and initialization data. The encoding order of data needs to be consistent with the storage order of the persistent cell specified by the new contract. In line 36, we can see that the initialization data has item_index, which is similar to the tokenId in ERC721, and the current contract address returned by the standard function my_address, which is collection_address. The order of this data is consistent with the declaration in nft-item.

The next point of knowledge is that in TON, all ungenerated smart contracts can pre-calculate their generated addresses, which is similar to the create2 function in Solidity. In TON, the generation of new addresses consists of two parts, the workchain identification bit and the hash value of stateinit. We have already known in the previous introduction that the former needs to be specified in order to correspond to the infinite sharding architecture of TON, and it is currently a unified value. It is obtained by the standard function workchain. The latter is obtained by the standard function cell_hash. So back to this example, calculate_nft_item_address is the function that pre-calculates the address of the new contract. And the generated value is encoded into message in line 53 as the receiving address of the internal message. And nft_content corresponds to the initialization call of the created contract, and the specific implementation will be introduced in the next article.

As for send_royalty_params, it needs to be a response to an internal message of a read-only request. In the previous introduction, we specifically emphasized that in TON, internal messages not only include operations that may modify data, but read-only operations also need to be implemented in this way. Therefore, this contract is such an operation. First of all, it is worth noting that line 67 represents the mark of the requester's callback function after responding to the request. Write it down as the returned data, which are the requested item index and the corresponding royalty data.

Next, let’s introduce the next knowledge point. In TON, smart contracts have only two unified entrances, named recv_internal

and recv_external, where the former is the unified call entry for all internal messages, and the latter is the unified call entry for all external messages. Developers need to use a switch-like method to respond to different requests according to the different flags specified by the message according to the needs within the function. The flag here is the callback function flag of line 67 above. Back to this example, first check the empty bit of the message, and then parse the information in the message separately. First, parse the sender_address in line 83. This parameter will be used for subsequent permission checks. Note that the ~ operator here is another syntax sugar. It will not be expanded here. Next, parse the op operation flag, and then process the corresponding requests according to different flags. The above functions are called separately according to certain logic. For example, respond to requests for royalty parameters, or cast new nfts, and increment the global index.

The next knowledge point corresponds to line 108. I believe everyone can know the processing logic of this function through the name. Similar to the require function in Solidity, Func uses the standard function throw_unless to throw an exception. The first input parameter is the error code, and the second is a check bit Boolean value. If it is false, an exception is thrown with the error code. In this line, equal_slices is used to determine whether the sender_address parsed above is equal to the owner_address persistently stored in the contract to make a permission judgment.

TON 项目开发教程(一):源码角度看如何在 TON Chain 上创建一个 NFT?

Finally, in order to make the code structure clearer, a series of auxiliary functions are created to help obtain persistent information. I will not introduce them here. Developers can refer to this structure to develop their own smart contracts.

TON 项目开发教程(一):源码角度看如何在 TON Chain 上创建一个 NFT?

DApp development in the TON ecosystem is really interesting, and it is very different from the development paradigm of EVM. Therefore, I will introduce how to develop DApp in TON Chain through a series of articles. Let's learn together and seize this opportunity. You are also welcome to interact with me on Twitter to collide with some new and interesting DApp ideas and develop together.

The article comes from the Internet:TON Project Development Tutorial (I): How to create an NFT on TON Chain from a source code perspective?

Related recommendations: Detailed explanation of OP Stack Rollup process and corresponding code

The OP Stack is the standardized, shared, and open source development stack that powers Optimism and is maintained by the Optimism Collective. Written by Rayer Optimism Bedrock is the current release of the OP Stack. The Bedrock release provides the tools for launching production quality…

share to
© 版权声明

相关文章