Навчальний посібник з розробки проекту TON (частина 1): Як створити NFT на основі ланцюжка TON з точки зору вихідного коду

Автор оригінального тексту: @Web3 Mario (_mario)

Після того, як я написав статтю про вступ до технології TON, я докладно вивчив офіційну документацію TON протягом останнього часу. Здається, що вивчення трохи складне, оскільки поточний зміст документації схожий на внутрішній документ розробника, і для новачків це не дуже зручно. Тому я спробував створити серію статей про розробку проекту TON Chain вздовж свого шляху вивчення, сподіваюся, що це буде корисно для швидкого введення у розробку додатків TON. Якщо є хибки у тексті, буду вдячний за виправлення. Давайте вивчати разом.

Які різниці між розробкою NFT в EVM та розробкою NFT на ланцюзі TON

Випуск FT або NFT є найбільш базовим вимогами для розробника DApp. Тому я також використовую це як вхід. Спочатку давайте розберемося в різниці між розробкою NFT в технологічному стеку EVM і на ланцюжку TON. Зазвичай, NFT на основі EVM вибирають стандарт ERC-721 для успадкування. NFT - це тип недільного шифрованого активу, кожен актив має унікальність, тобто має певні ексклюзивні характеристики. ERC-721 - це загальний парадигма розробки для цього типу активу. Давайте подивимось, які функції повинна реалізувати загальна контракт ERC 721 та яку інформацію вона повинна зберігати. На наступному зображенні показано інтерфейс ERC 721. Ви можете побачити, що, на відміну від FT, в передачі інтерфейсу необхідно вказати ідентифікатор tokenId, а не кількість. Цей tokenId є найбільш базовим виявом унікальності NFT-актива, і, звичайно, для зберігання більшої кількості властивостей зазвичай реєструється метадані для кожного tokenId. Цей метадані є зовнішнім посиланням, яке зберігає інші розширені дані цього NFT, наприклад, посилання на зображення PFP, деякі назви властивостей тощо.

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

Для розробників, які знайомі з Solidity або об’єктно-орієнтованим програмуванням, реалізація такого розумного контракту є простою справою. Достатньо визначити необхідні типи даних в контракті, такі як критичні відображення (mapping), і розробити відповідну логіку зміни цих даних залежно від необхідних функцій, щоб реалізувати NFT.

Але в TON Chain все це стає трохи іншим, з двох основних причин:

  • У TON зберігання даних базується на клітинах (Cell), а клітини одного рахунку реалізовані за допомогою орієнтованого ациклічного графа. Це призводить до того, що дані, які потребують довгострокового зберігання, не можуть необмежено зростати, оскільки глибина графа визначає вартість запитів. Якщо глибина нескінченно росте, це може призвести до надмірних витрат на запити та проблем з блокуванням контракту.
  • Для досягнення високої продуктивності TON відмовився від послідовного виконання архітектури на користь розробки середовища виконання, яке було створене спеціально для паралельності, моделі акторів. Це призвело до впливу того, що між смарт-контрактами можна взаємодіяти лише асинхронним способом шляхом відправлення так званих внутрішніх повідомлень. Зверніть увагу, що якщо це виклик пов’язаний з модифікацією стану або тільки для читання, його також потрібно виконувати відповідно до цього принципу. Крім цього, також потрібно ретельно розглядати, як у разі невдачі асинхронного виклику обробляти проблему відкату даних.

Звичайно, щодо технічних відмінностей, які були детально описані в попередній статті, ця стаття сподівається зосередитися на розробці смарт-контрактів, тому не буде розгортати обговорення. Вищезазначені два принципи проектування роблять розробку смарт-контрактів в TON дуже відмінною від EVM. У вступному викладі ми знаємо, що у контракті NFT потрібно визначити деякі відображення, тобто мапування, для збереження даних, пов’язаних з NFT. Один з найважливіших - це власники, це відображення зберігає відображення адреси власника NFT, який відповідає певному tokenID, що визначає власність NFT, переміщення - це зміна цієї власності. Оскільки в теорії це безмежна структура даних, потрібно уникати цього якомога більше. Тому офіційно рекомендується використовувати наявність безмежної структури даних як критерій для розподілу. Тобто, коли є подібна потреба у зберіганні даних, вона замінюється парадигмою головного та підчиненого контракту, шляхом створення підконтрактів для керування даними кожного ключа. І через головний контракт керувати глобальними параметрами або допомагати у взаємодії між підконтрактами.

Це також означає, що в TON NFT потрібно використовувати подібну архітектуру для проектування, де кожен NFT є окремим дочірнім контрактом, який зберігає ексклюзивні дані, такі як адреса власника, метадані тощо, та керується головним контрактом для управління глобальними даними, такими як назва, символ та загальний обсяг NFT.

Після визначення архітектури потрібно вирішити вимоги до основних функцій. Оскільки використовується майстер-слуга контракт, потрібно визначити, які функції будуть виконуватися основним контрактом, а які - підконтрактом, і як буде відбуватися внутрішня комунікація між ними. Також потрібно зрозуміти, як відновити дані у разі виникнення помилки виконання. Зазвичай перед розробкою складних великих проектів необхідно створити діаграму класів, яка чітко визначає потік інформації між ними, і ретельно обговорити логіку відновлення після невдачі внутрішнього виклику. Звичайно, розробка NFT, незважаючи на її простоту, також може бути піддана подібній перевірці.

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

Вивчення розробки розумного контракту TON з вихідного коду

TON обрав мову розробки розумного договору під назвою Func, що є статичною типізованою мовою, подібною до мови C. Тепер давайте вивчимо, як розробляти розумний договір TON, дивлячись на вихідний код. Я обрав приклад NFT з офіційної документації TON, щоб розповісти про нього. Якщо ви зацікавлені, ви можете самостійно знайти цю інформацію. У цьому випадку реалізовано простий приклад TON NFT. Давайте подивимося на структуру договору, яка складається з двох функціональних договорів та трьох необхідних бібліотек.

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

Основні контракти функції, розгляньте код основного контракту nft-collection відповідно до вищезазначених принципів.

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

Це введе першу точку знань, як зберігати дані у розумних контрактах TON. Ми знаємо, що у Solidity дані автоматично зберігаються відповідно до типів параметрів EVM, зазвичай змінні стану розумного контракту будуть автоматично збережені після виконання, і розробнику не потрібно думати про цей процес. Але в Func ситуація не така, розробник повинен самостійно реалізувати відповідну логіку обробки, ця ситуація трохи схожа на необхідність у C та C++ враховувати процес GC, але інші нові мови програмування зазвичай автоматизують цю частину логіки. Давайте подивимося на код, спочатку введемо деякі необхідні бібліотеки, а потім побачимо першу функцію load_data для зчитування збережених даних, її логіка полягає в тому, що спочатку за допомогою get_data повертається збережена клітина розумного контракту, зверніть увагу, що це реалізовано стандартною бібліотекою stdlib.fc, зазвичай деякі з цих функцій можна розглядати як системні функції для використання.

Тип повернення цієї функції - це комірка, це тип комірки в TVM. Як ми вже знаємо з попереднього вступу, всі постійні дані в ланцюгу блоків TON зберігаються в дереві комірок. Кожна комірка може містити максимум 1023 біти довільних даних та максимум чотири посилання на інші комірки. У TVM на основі стеку комірка використовується як пам’ять. У комірці зберігаються тільки тісно закодовані дані, щоб отримати конкретні відкриті дані, потрібно перетворити комірку в тип, який називається сріз. Комірку можна перетворити на тип сріз за допомогою функції begin_parse, а потім завантажити дані та посилання на інші комірки з срізу, щоб отримати дані з комірки. Зверніть увагу, що цей спосіб виклику в 15 рядку коду є сахаром мови у функції, яку можна викликати безпосередньо з результатом першої функції другої функції. І в останньому рядку послідовно завантажувати відповідні дані згідно з порядком постійного збереження даних. Зверніть увагу, що цей процес відрізняється від solidity, і не базується на викликах hashmap, тому цей порядок викликів не може бути порушений.

У функції save_data логіка схожа, лише це процес у зворотньому напрямку, що вводить нову точку знань, новий тип будівельника, це тип будівельника клітини. Дані біти та посилання на інші клітини можуть бути збережені в будівельнику, а потім будівельник може бути остаточно перетворений на нову клітину. Спочатку за допомогою стандартної функції begin_cell створіть будівельник, а потім послідовно зберігайте відповідні функції за допомогою функції зберігання, слід звернути увагу на те, що порядок виклику вищезазначеного та порядок збереження тут повинні бути ідентичними. На останок, завершіть побудову нової клітини за допомогою end_cell, тоді ця клітина керується в пам’яті, і, на завершення, за допомогою зовнішнього set_data, можна завершити постійне збереження цієї клітини.

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

Далі давайте розглянемо функції, пов’язані з бізнесом. Спочатку потрібно пояснити одну річ, як створити новий контракт за допомогою контракту, що буде часто використовуватися в архітектурі майстра-слейва, як було введено раніше. Ми знаємо, що в TON виклик між розумними контрактами здійснюється шляхом відправлення внутрішніх повідомлень. Це здійснюється за допомогою функції send_raw_message, зверніть увагу, що перший параметр - це закодована клітинка повідомлення, другий параметр - прапорець, який вказує на різницю в способі виконання цієї угоди, в TON встановлено різні режими відправки внутрішніх повідомлень, наразі є 3 режими повідомлень та 3 режими прапорців. Щоб отримати потрібний режим, можна поєднати один окремий режим з декількома (можливо, немає) прапорцями. Комбінація означає просто додавання їх значень й заповнення результату. Нижче наведено таблицю з описом режимів та прапорців:

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

Тож давайте подивимося на першу основну функцію, deploy_nft_item, як зрозуміло з назви, це функція для створення або, можна сказати, виготовлення нового екземпляру NFT, після кодування певного повідомлення за допомогою msg, воно відправляє цей внутрішній контракт за допомогою send_raw_message та вибирає прапорець відправки з флагом 1, виключно використовуючи вказану в кодуванні комісію як газову комісію для цього виконання. За згаданим вище вступом легко зрозуміти, що це правило кодування повинно бути способом створення нового смарт-контракту. Тож давайте подивимося, як це конкретно реалізовано.

Давайте спершу подивимось на рядок 51, вище наведені дві функції - це допоміжні функції для генерації інформації, необхідної для створення повідомлення. Тому ми розглянемо це пізніше. Це процес кодування внутрішнього повідомлення для створення розумного контракту, деякі цифри в середині є ідентифікаторами, які вказують вимоги цього внутрішнього повідомлення. Ось основна інформація: TON обрав бінарну мову TL-B для опису виконання повідомлення та використовує різні прапори для реалізації деяких конкретних функцій внутрішнього повідомлення. Дві найочевидніші ситуації використання - створення нового контракту та виклик функції вже розгорнутого контракту. А рядок 51 відповідає першому випадку, створенню нового контракту nft item, і це основне визначається рядками 55, 56, 57. По-перше, ці цифри в рядку 55 - це послідовність прапорів, зверніть увагу, що перший аргумент store_uint - це значення, другий - довжина в бітах, що визначає, що це внутрішнє повідомлення є створенням контракту, а останні три прапори відповідають значенню 111 (у десятковому форматі 4 + 2 + 1), перші два прапори позначають, що це повідомлення буде мати дані StateInit, які є вихідним кодом нового контракту та даними для ініціалізації. А останній прапор позначає прикріплення внутрішнього повідомлення, тобто бажання виконати відповідну логіку та параметри, які необхідні. Тому ви бачите, що в рядку 66 код не встановлює ці три значення, що означає виклик функції розгорнутого контракту. Докладні правила кодування можна переглянути тут.

Таким чином, правила кодування StateInit відповідають 49 рядкам коду, що обчислюється через calculate_nft_item_state_init. Варто звернути увагу на те, що кодування даних stateinit також слідує встановленому правилу кодування TL-B, за винятком деяких маркерів, і головним чином стосується двох частин нового коду контракту та ініціалізації даних. Послідовність кодування даних повинна відповідати порядку збереження поживних клітин, визначеного в новому контракті. На 36 рядку можна побачити, що ініціалізаційні дані містять item_index, схожий на tokenId у ERC 721, а також адресу поточного контракту, що повертається стандартною функцією my_address, а саме collection_address. Порядок цих даних відповідає оголошенням у nft-item.

Наступною точкою знань є те, що в TON адреси всіх незгенерованих смарт-контрактів можна попередньо обчислити. Це схоже на функцію create2 в Solidity. У TON генерація нової адреси складається з двох частин: мітки робочого ланцюжка та хеш-значення stateinit, які об’єднуються. Перша частина вже була описана у попередньому розділі і вона є стандартною функцією workchain. Друга частина отримується за допомогою стандартної функції cell_hash. Тому, якщо повернутися до цього прикладу, функція calculate_nft_item_address використовується для попереднього обчислення адреси нового контракту. Значення, яке згенерувала ця функція на 53-му рядку, кодується у повідомленні і використовується як адреса отримувача внутрішнього повідомлення. Параметр nft_content відповідає ініціалізаційному виклику створеного контракту. Детальніше про це буде описано у наступній статті.

Щодо send_royalty_params, воно повинно бути відповіддю на внутрішнє повідомлення для певного запиту на читання. У попередньому описі ми особливо підкреслили, що в TON внутрішнє повідомлення не лише містить операції, які можуть змінювати дані, але й операції читання також потребують реалізації через цей спосіб. Таким чином, цей контракт є прикладом такої операції. По-перше, варто звернути увагу, що на 67-му рядку позначено відповідь на цей запит для позначки функції зворотного виклику запитувача, а потім йдуть повернені дані, які складаються з індексу запиту та відповідних даних про роялті.

Далі давайте введемо наступний пункт, у TON інтелектуальний контракт має лише два єдині входи, що називаються recv_internal та recv_external, перший з яких є єдиним входом для всіх внутрішніх повідомлень, а другий - для всіх зовнішніх повідомлень. Розробник повинен відповідно до потреб використовувати внутрішній вміст функції, подібно до switch, щоб відповідати різним запитам, які вказуються у message за допомогою різних прапорів, що є зворотним викликом з 67 рядка. Повернувшись до цього прикладу, спочатку перевіряється наявність порожніх місць у повідомленні, після чого розбирається інформація з message. Спочатку на 83 рядку розбирається sender_address, цей параметр буде використовуватися для перевірки прав доступу в майбутньому, слід звернути увагу на оператор ~, який є іншим цукерком. Наразі не розкриватимемо його. Далі розбирається прапор операції op, а потім обробляються відповідні запити в залежності від різних прапорів. Серед них викликаються вищезазначені функції відповідно до деякої логіки. Наприклад, відповідь на запити до параметра royalty або мінтингу нового nft з підвищенням глобального індексу.

Наступна точка знань відповідає 108 рядку, ймовірно, з назви функції ви можете зрозуміти логіку обробки цієї функції, аналогічно до функції require в Solidity, в Func через стандартну функцію throw_unless викидається виняток, перший параметр - код помилки, другий - булеве значення перевірки, якщо значення дорівнює false, то виникає виняток з цим кодом помилки. А в цьому рядку за допомогою equal_slices перевіряється, чи дорівнює sender_address, яке було розібране вище, owner_address, яке зберігається в постійному сховищі цього контракту, для перевірки прав.

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

Нарешті, щоб зробити структуру коду більш зрозумілою, я почав створювати ряд допоміжних функцій для отримання інформації про постійність. Тут я не буду розгортати деталі, розробники можуть скористатися цією структурою для розробки свого власного розумного контракту.

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

Розробка DApp в екосистемі TON - це дуже цікава справа, що має велику відмінність від парадигми розробки EVM. Тому я розповім у ряді статей, як розробляти DApp на ланцюжку TON. Давайте разом вчитися і використовувати цю можливість. Також запрошую всіх до спілкування зі мною на Twitter, де ми можемо обмінюватися новими цікавими ідеями для DApp та спільно їх розробляти.

TON2,93%
Переглянути оригінал
Ця сторінка може містити контент третіх осіб, який надається виключно в інформаційних цілях (не в якості запевнень/гарантій) і не повинен розглядатися як схвалення його поглядів компанією Gate, а також як фінансова або професійна консультація. Див. Застереження для отримання детальної інформації.
  • Нагородити
  • Прокоментувати
  • Репост
  • Поділіться
Прокоментувати
0/400
Немає коментарів
  • Закріпити