Home >web3.0 >TON project development tutorial (1): How to create an NFT on TON Chain from a source code perspective

TON project development tutorial (1): How to create an NFT on TON Chain from a source code perspective

王林
王林Original
2024-06-25 07:58:391061browse

Author:@Web3Mario(https://x.com/web3_mario)

Abstract: Following up on the previous article aboutTON Technical introduction Article, I have been studying the TON official development documents in depth during this period, and 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 TON Chain project development based on my own learning trajectory. I hope it will be helpful for everyone to quickly get started with TON DApp development. If there are any errors in the writing, you are welcome to correct me and learn together.

What are the differences between

developing NFT in EVM and developing NFT on TON Chain

FT or NFT It is usually the most basic need for DApp developers. So I also use this as an entry point for learning. First, let us understand the following differences between developing an NFT in the EVM technology stack and in TON Chain.NFT based on EVM usually chooses to inherit the standard of ERC-721. The so-called NFT refers to an indivisible type of crypto asset, and each asset is unique, that is, it has certain exclusive characteristics. And ERC-721 is a common development paradigm for this type of assets. Let’s take a look at what functions a common ERC721 contract needs to implement and what information is recorded. The picture below is a ERC721 interface. You can see that unlike FT, what needs to be entered in the transfer interface is the tokenId to be transferred instead of the quantity.This tokenId is also the most basic embodiment of the uniqueness of NFT. 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 scalable 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 familiar with object-oriented, it is easy to implement such a smart contract, as long as the data types required in the contract are defined, such as some key mappings Relationship mapping, and develop corresponding modification logic to these data according to the required functions, you can implement a NFT.

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

  • The storage of data in TON 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 without boundaries, because for a directed acyclic graph, the query cost is determined by the depth of the data. When the depth extends infinitely, the query cost may be too high, leading to The contract is stuck in a deadlock problem.
  • In order to pursue high concurrency performance, TON abandoned the serial execution architecture and adopted a development paradigm designed for parallelism, Actor model, to Refactor the execution environment. This has an impact that smart contracts can only be called asynchronously by sending so-called internal messages. Note that whether it is a state modification type or a read-only type of call, this principle needs to be followed, except In addition, you also need 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 it will not be discussed. The above two design principles make a big difference between smart contract development in

TON and EVM.In the initial discussion, we know that a NFT contract needs to define some mapping relationships, that is, mapping, to save NFT related data. The most important one is owners. This mapping stores the mapping relationship of the owner address of a certain tokenID corresponding to NFT, which determines the ownership and transfer of NFT It is a modification of that ownership. Since this is a data structure that can be unbounded in theory, it needs to be avoided as much as possible. Therefore, it is officially recommended to use the existence of unbounded data structures as the standard for sharding. That is, when there are similar data storage requirements, the master-slave contract paradigm is used instead, and the data corresponding to each key is managed by creating sub-contracts. And manage global parameters through the main contract, or help handle internal information interaction between sub-contracts.

This also means that the NFT in TON also needs to be designed using a similar architecture. Each NFT is an independent sub-contract that saves information such as the owner address. , metadata and other exclusive data, and a main contract is used to manage global data, such as NFT name, symbol, total supply, etc.

After clarifying the architecture, the next step is to solve the core functional requirements. Due to the adoption of this master-slave contract method, So 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, and how to roll back the previous data when an execution error occurs. Usually, before developing a complex large-scale project, it is necessary to pass a class diagram and clarify the information flow between each other, and carefully think about the rollback logic after internal call failure. Of course, the above NFT development is simple , but similar verification can also be done.

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

Learn and develop TONsmart contracts from source code

TONChoose to design a class C language, static type language, named Func as a smart contract Development language, then let us learn how to develop TON smart contracts from the source code. I chose the NFT example in the official document of TON to introduce it. Interested friends can Check it out yourself. A simple TON NFT example is implemented in this case. 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 us look at the code of the main contract nft-collection:

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

This introduces the first knowledge point, how to persistently store data in TON smart contracts. We know that the persistent storage of data in Solidity is performed by EVM according to parameters The type is automatically handled. Normally, the state variables of the smart contract will be automatically persisted and stored based on the latest value after execution. 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 C and C++ which need to consider GC. 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 data through get_data Contract storage cell. Note that this is implemented by the standard library stdlib.fc. Under normal circumstances, 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 all persistent data in the TON blockchain is stored in the cell tree. Each cell has at most 1023 bits of arbitrary data and up to four references to other cell. cell is used as memory in stack-based TVM .cell stores tightly encoded data. To obtain the specific plaintext data, you need to convert cell into a type called slice. cell can be converted to slice type by begin_parse function, which can then be obtained by loading data bits and references to other cell from slice Data in . Note that this calling method in the 15 line of code is a syntactic sugar in func, which can directly call the second function with the return value of the first function. And finally load the corresponding data in order according to the data persistence order.Note that this process is different from solidity, and is not called based on hashmap, so the order of calls 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, this is The type of cell builder. Data bits and references to other cell can be stored in builders, which can then be finalized into new cell. First create a builder through the standard function begin_cell, and store related functions through the store related functions in turn. Note that the calling order above needs to be consistent with the storage order here.Finally, the new cell is constructed through end_cell. At this time, the cell is managed in the memory. Finally, through the outermost set_data, the can be completed. cell’s persistent storage.

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

Next, let’s take a 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 achieved through a file called send_raw_message. Note that the first parameter is the messageencoded cell, and the second parameter is the identification bit, used to indicate the transaction The difference in execution methods, different execution methods of internal message sending are set in TON, currently has 3messagesModes and 3messagesFlags . A single Mode can be combined with multiple (perhaps none) flags to get the desired mode.Combination just means fill in the sum of their values. The description table of Modes and Flags is given below :

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

So let’s look at the first main function, deploy_nft_item, as the name suggests, this is a function for The function that creates or casts a new NFT instance. After some operations to encode a msg, the internal contract is sent through send_raw_message, and the sending of flag 1 is selected. Identification bit, only the fee specified in the encoding is used as the gas fee for this execution. After the above introduction, we can easily realize that this coding rule should correspond to the way to create a new smart contract. Then let’s see how it is implemented.

Let us look directly at the 51 line. The above two functions are auxiliary functions used to generate the information required for message, so we will look at it later. This is an internal message used to create a smart contract In the encoding process, some numbers in the middle are actually some identification bits, used to explain the needs of the internal message. The next knowledge point is introduced here. TON chose a type called TL-B Binary language is used to describe how messages are executed, and internal messages that implement certain specific functions based on setting different flag bits. The two most easily thought of usage scenarios are new contract creation and deployed contract function calls. The method of line 51 corresponds to the former, creating a new nft item contract, which is mainly done through 55, 56, 57 Three lines are specified.First of all, the large series of numbers in the 55 line is a series of identification bits. Note that the first input parameter of store_uint is a numerical value, and the second is a bit length, which determines whether the internal message is created by the contract. are the last three flag bits, and the corresponding binary value bits are 111 (the decimal is 4+2+1), the first two of which indicate that the message will be accompanied by StateInit data, this The data is the source code of the new contract and the data required for initialization. The latter flag bit indicates the internal message attachment, that is, the relevant logic and required parameters are expected to be executed. Therefore, you will see that the three-digit data is not set in line 66, which indicates a function call to the deployed contract. Detailed coding rules can be found here.

Then the encoding rules of StateInit correspond to 49 lines of code, calculated through calculate_nft_item_state_init. Note that the encoding of stateinitdata also follows an established TL- BEncoding rules, except for some flag bits, mainly involve two parts of the new contract code and initialization data. The encoding order of data needs to be consistent with the storage order of persistent cell specified by the new contract.As you can see in line 36, the initialization data includes item_index, which is similar to tokenId in ERC721, and the standard function my_ address The current contract address returned is collection_address. The order of this data is consistent with the statement in nft-item.

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

As for send_royalty_params, it needs to be a response to the internal message of a read-only request. In the previous introduction, we specially emphasized that the internal message in TON not only contains possible modifications Data operations and read-only operations also need to be implemented in this way, so this contract is such an operation. The first thing to note is that the 67 line indicates the mark of the requester's callback function after responding to the request. Write it down. That is the returned data, which are the requested item index and the corresponding royalty data.

Let us introduce the next knowledge point. There are only two unified entrances to smart contracts in TON, named recv_internal and recv_external, where the former is the unification of all internal messages Call entry, the latter is a unified call entry for all external messages. Developers need to use a method similar to switch within the function to respond to different requests based on the different flag bits specified by message. Here The mark bit is the callback function mark of the above line 67. Back to this example, first perform a vacancy check on message, and then parse the information in message respectively. First, parse the 83 line to obtain sender_address. The parameters will be used for subsequent permission checks. Note that the ~ operators here are another syntactic sugar. I won’t expand on it here.Next, the op operation flag bits are parsed, and then the corresponding requests are processed according to different flag bits. Among them, the above functions are called respectively according to certain logic. For example, respond to a request for the royalty parameter, or mint a new nft and increment the global index.

The next knowledge point corresponds to line 108. I believe you can also know the processing logic of this function by naming it. It is similar to the require function in Solidity, Func Exceptions are thrown through the standard function throw_unless. The first input parameter is the error code, and the second is to check the bit Boolean value. If the bit is false, an exception will be 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 stored persistently in the contract, and make permission judgment.

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

Finally, in order to make the code structure clearer, a series of auxiliary functions have been developed to help obtain persistence information. They will not be introduced here. Developers can refer to this structure to develop their own smart contracts. .

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

TONecological DAppdevelopment is really an interesting thing, and it is very different from the development paradigm of EVM, so I will introduce how to develop in TON Chain through a series of articles Developed in DApp. Learn together with everyone and seize this wave of opportunities. You are also welcome to interact with me on twitter to bump into some new and interesting dapp ideas and develop them together.

The above is the detailed content of TON project development tutorial (1): How to create an NFT on TON Chain from a source code perspective. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn