TONプロジェクトの開発チュートリアル(1):ソースコードの観点から、TON Chain上にNFTを作成する方法を見る

原作者: @Web3 Mario (_mario)

前回のTON技術紹介記事に続き、この間TON公式開発ドキュメントを詳しく調査し、学習には少しハードルがあるように感じました。現在のドキュメント内容は内部開発ドキュメントのように思えます。新規開発者にとってはあまり親切ではないようです。そのため、自分の学習軌跡でTONチェーンプロジェクト開発に関する一連の記事を整理し、TON DApps開発の初心者が素早く入門できるよう、皆さんのお役に立てることを願っています。もし誤りがあれば、ご指摘いただけると嬉しいです。一緒に学んでいきましょう。

EVMでのNFTの開発とTON ChainでのNFTの開発にはどのような違いがありますか

DApp開発者にとって、FTまたはNFTを発行することは通常、最も基本的な要件です。したがって、私もそれを学習の入り口としています。まず、EVMテクノロジースタックでのNFTの開発とTON Chainでの開発の違いについて理解しましょう。EVMベースのNFTは、通常、ERC-721の標準を継承することを選択します。NFTとは、分割できない暗号化資産のタイプであり、各資産がユニークであり、特定の固有の特性を持っていることを意味します。ERC-721は、このタイプの資産に対する一般的な開発パターンです。一般的なERC 721コントラクトがどのような関数を実装し、どのような情報を記録する必要があるかを見てみましょう。次の図はERC 721インターフェースです。FTとは異なり、トランスファーインターフェースでは、数量ではなく転送するトークンIDを入力する必要があります。このトークンIDは、NFTアセットのユニーク性の基本的な表現です。もちろん、より多くのプロパティを持たせるために、通常、各トークンIDにメタデータを記録します。このメタデータは外部リンクであり、NFTの他の拡張可能なデータ(例:PFP画像のリンク、特定のプロパティ名など)を保存します。

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

Solidityまたはオブジェクト指向の開発者にとって、このようなスマートコントラクトを実現することは簡単なことです。必要なデータ型(例:いくつかの重要なマッピング関係)を定義し、これらのデータの変更ロジックに対応する必要な機能を開発するだけで、NFTを実現することができます。

しかし、TONチェーンでは、すべてが少し異なり、異なる主要な原因が2つあります。

*TONでは、データの格納はCellに基づいており、同じアカウントのCellは有向非巡回グラフを介して実現されています。これにより、永続化する必要があるデータは無限に増加することができないため、有向非巡回グラフでは、データの深さがクエリコストに影響を与えます。深さが無限になると、クエリコストが高すぎる可能性があり、それによって契約がデッドロック状態に陥る可能性があります。 高並行性能を追求するため、TONは直列実行アーキテクチャを捨て、並列に最適化された開発范式であるActorモデルを採用して実行環境を再構築しました。それにより、スマートコントラクト同士は内部メッセージを送信する方法で非同期呼び出しされる必要があるため、状態変更型または読み取り専用型の呼び出しに関係なく、この原則に従う必要があります。また、非同期呼び出しが失敗した場合、データをロールバックする方法についても注意深く考慮する必要があります。

もちろん、他の技術の違いについては前回の記事で詳しく説明しており、この記事ではスマートコントラクトの開発に焦点を当てたいので、それらについては説明しません。 上記の2つの設計原則により、TONでのスマートコントラクト開発はEVMとは大きく異なります。 議論の冒頭で、NFTコントラクトは、NFT関連のデータを保存するために、いくつかのマッピング関係、つまりマッピングを定義する必要があることを知っています。 これらの中で最も重要なのは所有者であり、NFTの所有者のアドレスのマッピングをNFTの所有権を決定するトークンIDに格納し、譲渡は所有権の変更です。 これは理論的にはボーダレスなデータ構造であるため、極力避ける必要があります。 そのため、ボーダレスなデータ構造の存在をシャーディングの標準として使用することが公式に推奨されています。 つまり、データストレージ要件が類似している場合は、マスタースレーブ契約のパラダイムで置き換え、各キーに対応するデータをサブコントラクトを作成して管理します。 また、元請け契約を通じてグローバルパラメータを管理したり、下請け契約間の内部情報取引所の処理を支援したりします。

これはまた、TON内のNFTも同様の構造で設計する必要があることを意味します。各NFTは独自のサブコントラクトであり、所有者のアドレス、メタデータなどの専用データを保存し、NFT名、シンボル、総供給量などのグローバルデータを管理するメインコントラクトを介しています。

架构が明確になったら、次に中核機能の要件を解決する必要があります。このマスター/スレーブ契約方式を採用したため、どの機能がマスター契約で実行され、どの機能がサブ契約で実行されるかを明確にする必要があります。また、それらの間でどのような内部情報が通信に使用されるかについても明確にする必要があります。同時に、実行エラーが発生した場合、以前のデータをロールバックする方法も検討する必要があります。通常、大規模で複雑なプロジェクトを開発する前に、クラス図を作成し、情報フローを明確にし、内部呼び出しの失敗時のロールバックロジックを慎重に考えることが必要です。もちろん、前述のNFTの開発は単純ですが、同様の検証を行うこともできます。

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

ソースコードを使用してTONスマートコントラクトの開発を学ぶ

TON、スマートコントラクト開発言語としてFuncと呼ばれるCライクな言語、静的型付け言語を設計することを選択し、ソースコードからTON スマートコントラクトを開発する方法を学びましょう、私はTONの公式ドキュメントでNFT例を選択して紹介し、関心のあるパートナーは自分で参照できます。 この場合、簡単なTON NFT例が実装されます。 2つの機能コントラクトと3つの必要なライブラリに分かれているコントラクト構造を見てみましょう。

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

これらの2つの主要な機能契約は、上記の原則に従って設計されています。まず、主契約nft-collectionのコードを見てみましょう:

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

これには最初の知識点が導入されており、TONスマートコントラクト内でデータを永続化する方法について説明します。Solidityでは、データの永続化はEVMによって自動的に処理されますが、通常、スマートコントラクトの状態変数は実行後に最新の値に基づいて自動的に永続化されます。しかし、Funcでは異なり、開発者は対応する処理ロジックを自分で実装する必要があります。この状況は、CおよびC++でGCの処理を考慮する必要がある状況に少し似ていますが、他の新しい開発言語では通常、この部分のロジックを自動的に処理します。コードを見てみましょう。まず、必要なライブラリを導入し、次に最初の関数load_dataが持続化されたデータを読み取るために使用されます。そのロジックは、まずget_dataを使用して永続化されたコントラクトストレージセルを返します。これは通常、標準ライブラリstdlib.fcによって実装されており、いくつかの関数はシステム関数と見なすことができます。

この関数の戻り値の型は cell で、これは TVM で使用される cell 型です。以前の説明で、TON ブロックチェーンのすべての永続的なデータが cell ツリーに格納されることを知っています。各 cell には最大で 1023 ビットの任意のデータと、最大で他の cell 4 つへの参照が含まれます。cell は、スタックベースの TVM でメモリとして使用されます。cell には圧縮されたデータが格納されており、具体的な平文データを取得するには、cell を slice と呼ばれる型に変換する必要があります。cell は begin_parse 関数を使用して slice 型に変換でき、その後、slice からデータビットと他の cell への参照をロードすることで、cell のデータを取得できます。注意すべきは、15 行目のコードの呼び出し方法は、func 内のシンタックスシュガーであるということです。つまり、最初の関数の戻り値の 2 番目の関数を直接呼び出すことができます。最後に、データの永続化の順序に従って、対応するデータを順番にロードする必要があります。これは Solidity とは異なり、ハッシュマップの呼び出しに基づいていないため、この呼び出し順序は間違えてはいけません。

save_data関数では、論理ANDと同様の処理が行われますが、これは逆の過程です。これにより、次の知識ポイント、新しいタイプのbuilderが導入されます。これはcellビルダーのタイプです。データビットと他のcellへの参照はビルダーに格納され、その後ビルダーは最終的に新しいcellになります。まず、標準関数begin_cellを使用してビルダーを作成し、関連する関数を順番にstore関連関数を使用して格納します。注:前述の呼び出し順序とここでの格納順序は一致している必要があります。最後にend_cellを使用して新しいcellの構築を完了すると、このcellはメモリ内で管理されます。最後にset_dataを使用してそのcellを永続的に保存できます。

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

次に、ビジネス関連の関数を見てみましょう。まず、契約を使用して新しい契約を作成する方法を紹介する必要があります。これは、マスター/スレーブアーキテクチャで頻繁に使用されます。 TONでは、スマートコントラクト間の呼び出しは内部メッセージの送信によって実現されます。これはsend_raw_messageという名前の関数によって実現されます。注意:最初のパラメータは、エンコードされたメッセージセルであり、2番目のパラメータは、トランザクションの実行方法の違いを示すフラグです。 TONでは、異なる内部メッセージ送信の実行方法が設定されており、現在3つのメッセージモードと3つのメッセージフラグがあります。単一のモードを複数の(おそらくない)フラグと組み合わせて、必要なモードを取得できます。組み合わせは、それらの値の合計を埋め込むだけを意味します。以下に、モードとフラグの説明表が示されています:

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

では、最初の主要な関数であるdeploy_nft_itemを見てみましょう。その名前からも分かる通り、これは新しいNFTインスタンスを作成または鋳造するための関数です。あるメッセージをエンコードした後、その内部契約をsend_raw_messageで送信し、送信フラグ1を選択しました。指定された手数料のみをガス手数料として使用します。前述の説明を読んでいただければ、このエンコード規則が新しいスマートコントラクトを作成する方法に対応していることがわかりやすいでしょう。それでは、具体的にどのように実装されているのかを見てみましょう。

51行目を直接見てみましょう。上の2つの関数は、メッセージを生成するための補助関数であり、後で再度見ることになります。これは、内部メッセージのエンコードプロセスであり、中間のいくつかの数字は、その内部メッセージの要件を説明するために使用されるいくつかの識別子です。次に、TONは、メッセージの実行方法を説明するためにTL-Bというバイナリ言語を採用し、特定の機能を持つ内部メッセージを設定に応じて実現するために異なるマークビットを使用します。最も一般的な2つの使用シナリオは、新しいコントラクトの作成と、すでに展開されたコントラクト関数の呼び出しです。そして、51行目の方法は前者に対応し、新しいnftアイテムコントラクトを作成します。これは、55、56、57行で指定されたものによって主に行われます。まず、55行のこの長い数字列は、いくつかの識別子であり、store_uintの最初の引数は値であり、2番目はビット長であり、それによって、この内部メッセージがコントラクト作成であることが決定されます。後3つのマークビットで、対応する2進数値は111(10進数で4 + 2 + 1)です。最初の2つは、このメッセージにStateInitデータが付属することを示しており、このデータは新しいコントラクトのソースコードと初期化に必要なデータです。最後のマークビットは内部メッセージが搭載されていることを示し、関連するロジックと必要なパラメータを実行することを望んでいます。したがって、コードの66行目では、この3つのデータが設定されておらず、すでに展開されたコントラクトの関数呼び出しを意味しています。詳細なエンコードルールはこちらで確認できます。

そのため、StateInitのエンコード規則は、49行目のコードに対応しており、calculate_nft_item_state_initによって計算されます。stateinitデータのエンコードも、TL-Bの規則に従っています。いくつかのフラグビットを除いて、主に新しい契約コードと初期化データの2つの部分に関わります。データのエンコード順序は、新しい契約で指定された永続化セルの格納順序と一致する必要があります。36行では、初期化データにitem_indexがあり、これはERC 721のtokenIdに類似しています。また、標準関数my_addressが返す現在の契約アドレスであるcollection_addressも含まれます。これらのデータの順序は、nft-itemでの宣言と一致しています。

知識の次のポイントは、TONでは、すべての未生成のスマートコントラクトは、生成されたアドレスの後に事前に計算できるということです、これはSolidityのcreate 2関数に似ており、TONでの新しいアドレスの生成は、ワークチェーン識別子ビットとstateinitのハッシュ値の2つの部分で構成され、前者は前の紹介ですでに知っていたTON無限シャーディングアーキテクチャに対応するために注文で指定する必要があり、現在は均一な値です。 標準関数ワークチェーンによって取得されます。 後者は、標準関数 cell_ハッシュによって取得されます。 したがって、例に戻ると、calculate_nft_item_address は、新しいコントラクトのアドレスを事前に計算する関数です。 そして、53 行目で生成された値を、その内部メッセージの受信アドレスとして message にエンコードします。 NFT_content は、次の記事で説明する、作成されたコントラクトへの初期化呼び出しに対応し仲介者

send_royalty_paramsについては、読み取り専用リクエストへの内部メッセージの応答である必要があります。前述の説明でも、TONでは内部メッセージにはデータを変更する可能性がある操作だけでなく、読み取り操作もこの方法で実現する必要があることを強調しました。したがって、この契約はそのような操作です。まず、注目すべきは、67行目でリクエストに対する応答後のコールバック関数のマーカーを表しており、それを記録して返されるデータです。それぞれ、リクエストのアイテムインデックスと対応する特許料データです。

次に、知識の次のポイントを紹介しましょう。TONのスマートコントラクトには、recv_internalとrecv_externalという2つの統一されたエントリポイントしかありません。前者はすべての内部メッセージの統一された呼び出しポイントであり、後者はすべての外部メッセージの統一された呼び出しポイントです。開発者は、関数内でメッセージが指定する異なるフラグに基づいて、異なる要求に応答するために、switchに似た方法を使用する必要があります。ここでのフラグは、上記の67行のコールバック関数のフラグです。この例に戻ると、まずメッセージの空の場所をチェックし、それを通過した後、メッセージの情報をそれぞれ解析します。まず、83行でsender_addressを解析します。このパラメータは、後続の権限チェックに使用されます。ここでの~演算子に注意してください。これは別の構文糖です。この点については、詳細は述べません。次に、op操作フラグを解析し、その後、異なるフラグに基づいて、対応する要求を処理します。これには、ロイヤリティパラメータに対する要求への応答、または新しいNFTのミントとグローバルインデックスのインクリメントなどが含まれます。

次に、108行に対応する知識点があります。おそらく、名前からも関数の処理ロジックがわかると思います。Solidityのrequire関数と同様に、Funcでは標準関数throw_unlessを使用して例外をスローします。最初の引数はエラーコードで、2番目の引数はチェックビットのブール値です。ビットがfalseの場合は例外をスローし、エラーコードを添えています。また、この行では、equal_slicesを使用して、解析したsender_addressがこの契約の永続的ストレージに保存されているowner_addressと等しいかどうかを判断し、アクセス権を確認しています。

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

最後に、コードの構造をより明確にするために、永続的な情報を取得するための補助関数の一連の作業を開始しましたが、ここでは詳細に説明しません。開発者は、このような構造を参考にして独自のスマートコントラクトを開発することができます。

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

TONエコシステムのDAppsの開発は非常に興味深いことであり、EVMの開発パラダイムとは大きく異なるため、TON ChainでDAppsを開発する方法について一連の記事を通じて紹介します。皆さんと一緒に学びながら、この機会を活かしましょう。また、Twitterでの交流も歓迎しますので、新しい面白いDAppsのアイデアを共有し、一緒に開発しましょう。

TON2.2%
原文表示
このページには第三者のコンテンツが含まれている場合があり、情報提供のみを目的としております(表明・保証をするものではありません)。Gateによる見解の支持や、金融・専門的な助言とみなされるべきものではありません。詳細については免責事項をご覧ください。
  • 報酬
  • コメント
  • リポスト
  • 共有
コメント
0/400
コメントなし
  • ピン