要約: TON テクノロジーの導入に関する前回の記事に続き、この期間中に TON の公式開発ドキュメントを徹底的に調査しましたが、現在のドキュメントの内容にはまだいくつかの障壁があると感じています。初心者向けの内部開発ドキュメントのようなもので、開発者にとってはあまり親切ではありません。そのため、私自身の学習の軌跡に基づいて TON Chain プロジェクト開発に関する一連の記事を整理しようとしています。誰もがすぐに TON DApp 開発を始めることができます。文章に間違いがある場合は、修正して一緒に学んでいただければ幸いです。
FT または NFT の発行は、通常、DApp 開発者にとって最も基本的なニーズです。したがって、私はこれを学習の入り口としても使用します。まず、EVM テクノロジースタックと TON Chain での NFT 開発の次の違いを理解しましょう。 EVM ベースの NFT は通常、ERC-721 標準を継承することを選択します。いわゆる NFT は、分割できないタイプの暗号化資産を指し、各資産は固有です。つまり、特定の排他的な特性を持っています。 ERC-721 は、このタイプの資産の一般的な開発パラダイムです。一般的な ERC721 契約でどのような機能を実装する必要があるか、またどのような情報が記録されるかを見てみましょう。下の写真はERC721インターフェースです。 FT とは異なり、転送インターフェイスに入力する必要があるのは、金額ではなく、転送する tokenId であることがわかります。この tokenId は、NFT アセットの一意性の最も基本的な表現でもあります。もちろん、より多くの属性を保持するために、通常、このメタデータは、NFT の他のスケーラブルなデータを保存する外部リンクです。 PFP 画像、特定の属性名などへのリンクとして。
Solidity に精通している開発者、またはオブジェクト指向に精通している開発者にとって、いくつかのキー マッピング関係など、コントラクトで必要なデータ型が定義されている限り、このようなスマート コントラクトを実装するのは簡単です。 NFTを実現するには、これらのデータに対応する変更ロジックを機能的に開発する必要があります。
ただし、これは TON Chain では同じではありません。その違いには主に 2 つの理由があります:
もちろん、他の技術的な違いについては前の記事で詳しく説明しましたので、この記事ではスマート コントラクトの開発に焦点を当てたいと考えていますので、説明しません。上記の 2 つの設計原則は、TON のスマート コントラクト開発と EVM の間に大きな違いをもたらします。最初の議論では、NFT 関連データを保存するには、NFT コントラクトでいくつかのマッピング関係、つまりマッピングを定義する必要があることがわかりました。それらの中で最も重要なのは所有者です。このマッピングには、特定の tokenID に対応する NFT の所有者アドレスのマッピング関係が保存され、これによって NFT の所有権が変更されます。これは理論上無制限になり得るデータ構造であるため、可能な限り回避する必要があります。したがって、無制限のデータ構造の存在をシャーディングの標準として使用することが公式に推奨されています。つまり、同様のデータ ストレージ要件がある場合は、マスター/スレーブ コントラクト パラダイムが代わりに使用され、各キーに対応するデータはサブコントラクトを作成することによって管理されます。また、メイン コントラクトを通じてグローバル パラメーターを管理したり、サブコントラクト間の内部情報のやり取りの処理を支援したりできます。
これは、TONのNFTも同様のアーキテクチャで設計する必要があることを意味し、各NFTは所有者のアドレス、メタデータなどの排他的なデータを保存し、メインコントラクトを通じて管理されます。 NFT名、シンボル、総供給量などのグローバルデータ
アーキテクチャを明確にしたら、次はコアとなる機能要件を解決する必要があります。このマスタースレーブ契約方式を採用しているため、どの機能をメインコントラクトが担うのか、どの機能をサブコントラクトが担うのかを明確にする必要があります。コントラクトとサブコントラクトがどの機能を実行するか、サブコントラクトがどの機能を実行するか、それらの間の通信にどのような内部情報が使用されるか、実行エラーが発生した場合に以前のデータをロールバックする方法。通常、複雑な大規模プロジェクトを開発する前に、クラス図を渡して相互間の情報の流れを明確にし、内部呼び出しが失敗した後のロールバックロジックを慎重に検討する必要があります。もちろん、上記のNFTですが。開発が簡単なので同様の検証も可能です。
TON は、スマート コントラクト開発言語として、Func という C ライクな静的型付け言語を設計することを選択しました。次に、ソース コードから TON スマート コントラクトを開発する方法を学びましょう。導入用に TON の公式ドキュメントにある NFT の例を選択しました。興味のある友人は自分で確認してください。この場合、単純な TON NFT の例が実装されています。コントラクト構造を見てみましょう。コントラクト構造は 2 つの機能コントラクトと 3 つの必要なライブラリに分かれています。
2 つの主要な機能コントラクトは、上記の原則に従って設計されています。 まず、メイン コントラクト nft-collection のコードを見てみましょう:
これは、最初の知識ポイントである永続ストレージの方法を紹介します。 TON スマート コントラクト内のデータの永続ストレージは、通常、スマート コントラクトの状態変数が実行後の最新の値に従って自動的に保持されることがわかっています。ストレージ、開発者はこのプロセスを考慮する必要はありません。しかし、これは Func には当てはまりません。開発者は対応する処理ロジックを自分で実装する必要があります。この状況は、C や C++ で GC プロセスを考慮する必要があるのと似ていますが、他の新しい開発言語では通常、この部分が自動化されます。論理。コードを見てみましょう。まず、必要なライブラリをいくつか紹介します。次に、最初の関数load_dataが永続的に保存されたデータを読み取るために使用されていることがわかります。そのロジックは、最初にget_dataを通じて永続的なコントラクトストレージセルを返すことです。これは、ライブラリ stdlib.fc によって実装された標準によって行われ、これらの関数の一部は通常、システム関数として使用できます。
この関数の戻り値の型は cell で、TVM のセル型です。前回の紹介で、TON ブロックチェーン内のすべての永続データがセル ツリーに保存されていることはすでにわかりました。各セルには、最大 1023 ビットの任意のデータと、他のセルへの最大 4 つの参照があります。セルはスタックベースの TVM のメモリとして使用されます。セルに格納されるのは、コンパクトに暗号化されたデータです。特定の平文データを取得するには、セルをスライスと呼ばれる型に変換する必要があります。 begin_parse 関数を使用してセルをスライス タイプに変換し、スライスからデータ ビットをロードして他のセルを参照することにより、セル内のデータを取得できます。 15 行目のこの呼び出しメソッドは func の糖衣構文であり、最初の関数の値を返す 2 番目の関数を直接呼び出すことができることに注意してください。そして最後に、データの永続化順序に従って、対応するデータを順番にロードします。このプロセスは Solidity とは異なり、ハッシュマップに基づいて呼び出されないため、呼び出しの順序を間違えることはできないことに注意してください。
save_data 関数では、ロジックは似ていますが、これが逆のプロセスである点が異なり、次の知識ポイントであるセル ビルダーのタイプである新しいタイプ ビルダーが導入されます。データ ビットと他のセルへの参照はビルダーに保存でき、その後、それを新しいセルに完成させることができます。まず、標準関数 begin_cell を使用してビルダーを作成し、次にストア関連関数を使用して関連関数を保存します。上記の呼び出し順序は、ここでの保存順序と一致している必要があることに注意してください。最後に、end_cell を介して新しいセルが構築され、最後に、最外部の set_data を介してセルの永続的な保存が完了します。
次に、ビジネス関連の機能を見てみましょう。まず、次の知識ポイントである、マスター/スレーブ アーキテクチャで頻繁に使用される、コントラクトを通じて新しいコントラクトを作成する方法を紹介する必要があります。紹介された。 TON では、スマート コントラクト間の呼び出しが内部メッセージの送信によって実装されることがわかっています。これは、send_raw_message というメッセージを通じて実現されます。最初のパラメータはメッセージでエンコードされたセルであり、2 番目のパラメータはトランザクションの実行方法の違いを示すために使用される識別ビットであることに注意してください。異なる内部設定が設定されます。 TON には現在、メッセージ送信の実行モードとして 3 つのメッセージ モードと 3 つのメッセージ フラグがあります。単一のモードを複数の (おそらくなしの) フラグと組み合わせて、目的のモードを取得できます。単に結合するとは、それらの値の合計を埋めることを意味します。モードとフラグの説明表は以下のとおりです:
それでは最初のメイン関数、deploy_nft_item を見てみましょう。名前が示すように、これは新しい NFT インスタンスを作成またはキャストするために使用される関数です。メッセージをエンコードするためのいくつかの操作の後、send_raw_message を通じて内部コントラクトを送信し、送信フラグを選択します。フラグ 1 の場合、この実行のガス料金としてエンコーディングで指定された料金のみが使用されます。上記の導入後、このコーディング ルールは新しいスマート コントラクトを作成する方法に対応する必要があることが容易に理解できます。それでは、それがどのように実装されているかを見てみましょう。
51行目を直接見てみましょう。上記の2つの関数は、メッセージに必要な情報を生成するために使用される補助関数です。これは、スマートコントラクトの内部メッセージを作成するためのエンコードプロセスです。実際、これらは内部メッセージの要件を説明するために使用されるいくつかの識別ビットでもあります。次の知識ポイントは、メッセージの実行方法を記述するために TL-B と呼ばれるバイナリ言語を選択しました。特定の関数の内部メッセージを実装するには、新しいコントラクトの作成とデプロイされたコントラクト関数呼び出しの 2 つの最も一般的な使用シナリオが思い浮かびます。 51行目のメソッドは前者に相当し、新たなnftアイテムコントラクトを作成するもので、主に55行目、56行目、57行目で指定します。まず、55 行目の大きな一連の数字は一連の識別ビットです。store_uint の最初の入力パラメータは値で、2 番目は内部メッセージがコントラクトによって作成されたかどうかを決定するビット長であることに注意してください。 、最後の 3 つのマーキング ビット、および対応するバイナリ値は 111 (10 進数で 4+2+1) で、最初の 2 つは、メッセージに StateInit データが伴うことを示します。このデータは、新しいデータのソース コードです。契約書と初期化に必要なデータ。後者のフラグ ビットは、内部メッセージの添付ファイルを示します。つまり、関連するロジックと必要なパラメーターが実行されることが予想されます。したがって、コードの 66 行目では 3 桁のデータが設定されていないことがわかります。これは、デプロイされたコントラクトへの関数呼び出しを示しています。詳細なコーディング規則はここで参照できます。
StateInit のエンコード ルールは、calculate_nft_item_state_init によって計算された 49 行のコードに対応します。stateinit データのエンコードには、いくつかのフラグ ビットに加えて、主に 2 つの部分が含まれることに注意してください。新しい契約と初期化されたデータ。データのエンコード順序は、新しい契約で指定された永続セルの格納順序と一致している必要があります。 36 行目にあるように、初期化データには、ERC721 の tokenId に似た item_index と、標準関数 my_address によって返される現在のコントラクト アドレス (collection_address) が含まれています。このデータの順序は、次の宣言と一致しています。 nftアイテム。
次の知識ポイントは、TON では、すべての未生成のスマート コントラクトが生成されたアドレスを事前に計算できるということです。これは、TON の新しいアドレスの生成は 2 つの部分で構成されます。前回の紹介ですでにわかっているように、前者は TON 無限シャーディング アーキテクチャに対応するために指定する必要があるため、現在は統一された値です。標準関数ワークチェーンから取得します。後者は標準関数 cell_hash によって取得されます。この例に戻りますが、calculate_nft_item_address は、新しい契約アドレスを事前に計算する関数です。そして、生成された値を内部メッセージの受信アドレスとして 53 行目のメッセージにエンコードします。 nft_content は、作成されたコントラクトへの初期化呼び出しに対応します。具体的な実装については、次の記事で紹介します。
send_royalty_params に関しては、読み取り専用リクエストの内部メッセージに対する応答である必要があります。前の紹介では、TON の内部メッセージにはデータを変更する可能性のある操作だけでなく、読み取りも含まれていることを特に強調しました。 -only の操作はこれを渡す必要がある という形で実装されているので、コントラクトはこのような操作になっています まず注目すべきは、67行目はリクエストに応答した後のリクエスターのコールバック関数のマークを示していることです。そして、要求された商品インデックスと対応するロイヤリティーデータであるデータを返します。
次のナレッジ ポイントを紹介します。TON には、recv_internal と recv_external という名前の統合された入口が 2 つだけあります。前者はすべての内部メッセージの統合呼び出し入口であり、後者はすべての外部メッセージの統合呼び出し入口です。メッセージの場合、開発者は、要件に基づいて関数内のメッセージで指定されたさまざまなフラグ ビットに基づいて、スイッチのようなメソッドを使用してさまざまなリクエストに応答する必要があります。ここでのフラグ ビットは、上記の 67 行目のコールバック関数フラグです。この例に戻ります。最初にメッセージの空きチェックを実行し、次にメッセージ内の情報をそれぞれ解析して、sender_address を取得します。このパラメータは以降の権限チェックに使用されることに注意してください。ここは別の構文シュガーに属します。ここでは詳しく説明しません。次に、op 操作のフラグ ビットが解析され、対応するリクエストがさまざまなフラグ ビットに従って処理されます。このうち、上記の関数はそれぞれ一定のロジックに従って呼び出されます。たとえば、ロイヤルティ パラメータのリクエストに応答するか、新しい nft をキャストしてグローバル インデックスをインクリメントします。
次のナレッジポイントは 108 行目です。この関数の処理ロジックは、Solidity の require 関数と同様に、最初の入力関数を通じてスローされると思います。パラメータがエラー コードである場合、2 番目はビットのブール値をチェックします。ビットが false の場合は、エラー コードとともに例外がスローされます。この行では、equal_slicesを用いて上記で解析したsender_addressがコントラクトの永続ストレージのowner_addressと等しいかどうかを判定し、許可判定を行っています。
最後に、コード構造を明確にするために、永続性情報の取得を支援する一連の補助関数が開発されました。開発者はこの構造を参照して独自のスマート コントラクトを開発できます。
TONエコシステムでのDApp開発はEVMの開発パラダイムとは大きく異なるので、一連の記事を通してTON ChainでDAppを開発する方法を紹介します。皆さんと一緒に学び、このチャンスの波を掴みましょう。また、新しくて興味深い dapp のアイデアを考え出し、一緒に開発するために、twitter で私と交流することも歓迎します。
以上がTONプロジェクト開発チュートリアル(1):ソースコードの観点からTON Chain上にNFTを作成する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。