原作者: @ Web3マリオ (https://x.com/ウェブ3_mario)
前回のTON技術紹介記事に続き、最近TON公式開発文書を徹底的に研究してきました。学習にはまだ障壁があると感じています。現在の文書の内容は、内部開発文書のようなもので、新しい開発者にとってはあまり親しみやすいものではありません。そこで、自分の学習軌跡に基づいて、TON Chainプロジェクト開発に関する一連の記事を整理し、皆さんがすぐにTON DApp開発を始められるようにしたいと考えています。本文に誤りがある場合は、訂正して一緒に学んでください。
EVM で NFT を開発することと TON チェーンで NFT を開発することの違いは何ですか?
FT または NFT の発行は、通常、DApp 開発者にとって最も基本的な要件です。そのため、私はこれを学習の入り口としても使用しています。まず、EVM テクノロジー スタックと TON Chain で NFT を開発することの違いを理解しましょう。EVM ベースの NFT は通常、ERC-721 標準を継承することを選択します。いわゆる NFT は、分割できないタイプの暗号化された資産を指し、各資産は一意であり、つまり、特定の排他的な特性があります。ERC-721 は、このタイプの資産の一般的な開発パラダイムです。一般的な ERC 721 契約が実装する必要がある機能と、記録する必要がある情報を見てみましょう。下の図は、ERC 721 インターフェイスです。FT とは異なり、転送インターフェイスに入力する必要があるのは、数量ではなく、転送する tokenId であることがわかります。この tokenId は、NFT 資産の一意性の最も基本的な具体化でもあります。もちろん、より多くの属性を運ぶために、通常、tokenId ごとにメタデータが記録されます。このメタデータは、PFP 画像へのリンク、特定の属性名など、NFT のその他の拡張可能なデータを保存する外部リンクです。
Solidity やオブジェクト指向プログラミングに精通している開発者にとって、このようなスマート コントラクトを実装するのは簡単です。コントラクトに必要なデータ タイプ (いくつかのキー マッピング関係など) が定義され、これらのデータの対応する変更ロジックが必要な機能に従って開発されていれば、NFT を実装できます。
しかし、TON Chain ではすべてが異なります。この違いには、主に 2 つの理由があります。
-
TON では、データ ストレージはセルに基づいており、同じアカウントのセルは有向非巡回グラフを通じて実装されています。これは、有向非巡回グラフの場合、クエリ コストはデータの深さによって決まるため、保存する必要があるデータが無制限に増加できないことを意味します。深さが無限に拡張されると、クエリ コストが高くなりすぎて、契約がデッドロック問題に陥る可能性があります。
-
TON は、高い並行性を追求して、シリアル実行アーキテクチャを放棄し、並列性を重視した開発パラダイムであるアクターモデルを採用して実行環境を再構築しました。これにより、スマートコントラクトは、いわゆる内部メッセージを送信することによってのみ非同期的に呼び出すことができるという影響が出ています。この原則は、状態変更と読み取り専用呼び出しの両方で従う必要があることに注意してください。また、非同期呼び出しが失敗した場合のデータロールバックの処理方法についても慎重に検討する必要があります。
もちろん、その他の技術的な違いについては、前回の記事で詳しく説明しました。この記事では、スマートコントラクトの開発に焦点を当てたいと考えているため、詳しく説明しません。上記の2つの設計原則により、TONのスマートコントラクト開発はEVMとは大きく異なります。最初の説明では、NFT関連のデータを保存するには、NFTコントラクトでいくつかのマッピング関係、つまりマッピングを定義する必要があることがわかりました。最も重要なのは所有者です。このマッピングには、NFTの所有権を決定するtokenIDに対応するNFTの所有者アドレスのマッピング関係が格納されます。譲渡は所有権の変更です。これは理論上は無限にできるデータ構造であるため、可能な限り避ける必要があります。そのため、公式の推奨事項は、無限のデータ構造の存在をシャーディングの基準として使用することです。つまり、同様のデータストレージ要件がある場合は、マスタースレーブコントラクトパラダイムに置き換え、各キーに対応するデータをサブコントラクトを作成して管理します。また、マスター契約はグローバル パラメータを管理したり、サブ契約間の内部情報のやり取りを処理するのに役立ちます。
これは、TON の NFT も同様のアーキテクチャで設計する必要があることを意味します。各 NFT は、所有者のアドレスやメタデータなどの専用データを保存し、メイン コントラクトを通じて NFT 名、シンボル、総供給量などのグローバル データを管理している独立したサブ コントラクトです。
アーキテクチャを明確にした後、次のステップはコア機能要件を解決することです。マスタースレーブ契約方式を採用しているため、メイン契約でどの機能を担い、サブ契約でどの機能を担うのか、両者の間でどのような内部情報が通信されるのかを明確にする必要があります。同時に、実行エラーが発生した場合、以前のデータをどのようにロールバックするかも重要です。通常、複雑で大規模なプロジェクトを開発する前に、クラス図を使用して互いの情報の流れを明確にし、内部呼び出しが失敗した後のロールバックロジックを慎重に検討する必要があります。もちろん、上記のNFT開発は単純ですが、同様の検証を行うこともできます。
ソースコードからTONスマートコントラクトを開発する方法を学ぶ
TON は、スマート コントラクト開発言語として、C に似た静的型付け言語 Func を設計することを選択しました。次に、ソース コードから TON スマート コントラクトを開発する方法を学びましょう。TON 公式ドキュメントの NFT の例を使用して紹介します。 興味のある友人は自分でチェックしてみてください この場合、シンプルな TON NFT の例が実装されています。2 つの機能コントラクトと 3 つの必要なライブラリに分かれているコントラクト構造を見てみましょう。
これら 2 つの主要な機能コントラクトは、上記の原則に従って設計されています。まず、メイン コントラクト nft-collection のコードを見てみましょう。
ここでは、最初の知識ポイント、TON スマート コントラクトでデータを永続化する方法について説明します。Solidity では、データの永続的な保存は、パラメーターの種類に応じて EVM によって自動的に処理されることがわかっています。通常、スマート コントラクトの状態変数は、実行後に最新の値に応じて自動的に永続化されるため、開発者はこのプロセスを考慮する必要はありません。しかし、Func ではそうではありません。開発者は、対応する処理ロジックを自分で実装する必要があります。この状況は、C および C++ が GC を考慮する必要があるプロセスに似ていますが、他の新しい開発言語では通常、このロジックの部分が自動化されます。コードを見てみましょう。まず、必要なライブラリをいくつか紹介し、次に、永続的に保存されたデータを読み取るために使用される最初の関数 load_data を確認します。そのロジックは、最初に get_data を介して永続的なコントラクト ストレージ セルを返すことです。これは、標準ライブラリ stdlib.fc によって実装されていることに注意してください。通常、これらの関数のいくつかはシステム関数として使用できます。
この関数の戻り値の型はセルで、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つのメッセージフラグがあります。1つのモードを複数の(おそらくゼロの)フラグと組み合わせて、目的のモードを取得できます。組み合わせとは、単にそれらの値の合計を入力することを意味します。 以下はモードとフラグの説明表です。
それでは、最初のメイン関数であるdeploy_nft_itemを見てみましょう。名前が示すように、これは新しいNFTインスタンスを作成または作成するために使用される関数です。メッセージをエンコードするためのいくつかの操作の後、内部コントラクトをsend_raw_messageを介して送信し、フラグ1の送信フラグを選択し、エンコードで指定された料金のみをこの実行のガス料金として使用します。上記の紹介の後、このエンコードルールは新しいスマートコントラクトを作成する方法に対応している必要があることは簡単に理解できます。それがどのように実装されているかを見てみましょう。
51行目を直接見てみましょう。上記の2つの関数は、メッセージに必要な情報を生成するための補助関数なので、後で見ていきます。これは、スマートコントラクトの内部メッセージを作成するためのエンコードプロセスです。真ん中の数字のいくつかは、実際にはいくつかの識別ビットであり、内部メッセージのニーズを説明するために使用されます。ここで、次の知識ポイントを紹介する必要があります。TONは、メッセージの実行方法を記述し、異なるマーカービットを設定することで特定の機能を持つ内部メッセージを実装するために、TL-Bと呼ばれるバイナリ言語を選択しました。最も簡単に考えられる2つの使用シナリオは、新しいコントラクトの作成とデプロイされたコントラクト関数の呼び出しです。51行目のメソッドは前者に対応し、主に55、56、57行目で指定されている新しいnftアイテムコントラクトを作成します。まず、55行目の長い数字の文字列は、一連の識別ビットです。store_uintの最初の入力パラメータは値であり、2番目はビット長であることに注意してください。最後の 3 つのフラグ ビットは、内部メッセージがコントラクトによって作成されたことを決定し、対応するバイナリ値は 111 (10 進数では 4+ 2+ 1) です。最初の 2 つは、メッセージに StateInit データが付随することを示します。これは、新しいコントラクトのソース コードと初期化に必要なデータです。最後のフラグ ビットは、内部メッセージが添付されていることを示します。つまり、関連するロジックと必要なパラメーターを実行することが期待されています。したがって、66 行目のコードでは 3 ビットのデータが設定されていないことがわかります。これは、デプロイされたコントラクトへの関数呼び出しを示しています。 具体的なエンコードルールについては、こちらでご覧いただけます。
次に、StateInit のエンコード ルールは 49 行のコードに対応し、calculate_nft_item_state_init によって計算されます。stateinit データのエンコードも、確立された TL-B エンコード ルールに従っていることに注意してください。いくつかのマーカーに加えて、主に新しいコントラクト コードと初期化データの 2 つの部分が含まれます。データのエンコード順序は、新しいコントラクトで指定された永続セルの保存順序と一致している必要があります。36 行目では、初期化データに、ERC 721 の tokenId に似た item_index と、標準関数 my_address によって返される現在のコントラクト アドレス (collection_address) があることがわかります。このデータの順序は、nft-item の宣言と一致しています。
次の知識ポイントは、TONでは、すべての未生成スマートコントラクトは、生成されたアドレスを事前計算できることです。これは、Solidityのcreate 2関数に似ています。TONでは、新しいアドレスの生成は、ワークチェーン識別子とstateinitのハッシュ値の2つの部分で構成されます。前者は、TONの無限シャーディングアーキテクチャに対応するために指定する必要があり、現在は統一された値であることは、前回の紹介ですでにわかっています。これは、標準関数workchainによって取得されます。後者は、標準関数cell_hashによって取得されます。この例に戻ると、calculate_nft_item_addressは、新しいコントラクトのアドレスを事前計算する関数です。そして、生成された値は、内部メッセージの受信アドレスとして、53行目のメッセージにエンコードされます。そして、nft_contentは、作成されたコントラクトの初期化呼び出しに対応しており、具体的な実装は次の記事で紹介します。
send_royalty_params については、読み取り専用リクエストの内部メッセージへの応答である必要があります。前回の紹介では、TON では、内部メッセージにデータを変更する可能性のある操作だけでなく、読み取り専用操作もこのように実装する必要があることを強調しました。したがって、この契約はそのような操作です。まず、67 行目は、リクエストに応答した後のリクエスターのコールバック関数のマークを表していることに注意してください。返されるデータとして書き留めます。これは、要求されたアイテムのインデックスと対応するロイヤリティ データです。
次に、次の知識ポイントを紹介しましょう。TON では、スマート コントラクトには、recv_internal と recv_external という 2 つの統一された入り口しかありません。前者はすべての内部メッセージの統一された呼び出し入り口であり、後者はすべての外部メッセージの統一された呼び出し入り口です。開発者は、必要に応じて、関数内のメッセージで指定されたさまざまなフラグに応じて、スイッチのような方法を使用してさまざまな要求に応答する必要があります。ここでのフラグは、上記の 67 行目のコールバック関数フラグです。この例に戻ると、最初にメッセージに空の位置がないか確認し、次にメッセージ内の情報を個別に解析します。まず、83 行目の sender_address を解析します。このパラメーターは、後続の権限チェックに使用されます。ここでの ~ 演算子は別の構文糖であることに注意してください。ここでは詳しく説明しません。次に、op 操作フラグを解析し、異なるフラグに応じて対応する要求を処理します。上記の関数は、特定のロジックに従って個別に呼び出されます。たとえば、ロイヤリティ パラメーターの要求に応答したり、新しい nft をキャストしたり、グローバル インデックスを増分したりします。
次のナレッジポイントは108行目です。この関数の処理ロジックも名前からわかると思います。Solidityのrequire関数と同様に、Funcは標準関数throw_unlessを使用して例外をスローします。最初の入力パラメータはエラーコードで、2番目はチェックビットのブール値です。falseの場合、エラーコードとともに例外がスローされます。この行では、equal_slicesを使用して、上で解析したsender_addressがコントラクトに永続的に保存されているowner_addressと等しいかどうかを判断し、許可の判断を下します。
最後に、コード構造をより明確にするために、永続的な情報を取得するのに役立つ一連の補助関数が作成されます。ここでは紹介しません。開発者はこの構造を参照して独自のスマート コントラクトを開発できます。
TON エコシステムにおける DApps の開発は非常に興味深く、EVM の開発パラダイムとは大きく異なります。そこで、一連の記事を通じて、TON Chain で DApps を開発する方法を紹介します。一緒に学び、この機会をつかみましょう。また、Twitter で私と交流して、新しい興味深い DApp のアイデアにぶつかり、一緒に開発することも歓迎します。
この記事はインターネットから引用したものです: TON プロジェクト開発チュートリアル (I): ソースコードの観点から TON チェーン上に NFT を作成する方法
関連: 来週必見 | 連邦準備制度理事会が金利決定を発表、Aethirがシーズン1のエアドロップ申請を開始 (
来週のハイライト SingularityNET: FET、AGIX、OCEAN の統合が 6 月 11 日に開始され、統合トークンは ASI になります。Aethir がエアドロップの詳細を発表しました。ATH の総供給量の 6% がエアドロップに使用され、シーズン 1 のエアドロップは 6 月 12 日に利用可能になります。The Block は、zkSync が 6 月 13 日頃にエアドロップを実施する予定であると報告しました (公式確認はまだありません)。Synthetix の子会社である Infinex は、6 月 13 日にガバナンス ポイントの配布を完了します。連邦準備制度理事会は、6 月 14 日に金利決定と経済予測の概要を発表します。10x Research: Chiliz (CHZ) は、6 月 14 日のヨーロッパカップの開始により急上昇する可能性があります。6 月 10 日から 6 月 16 日まで、…