Перейти до основного вмісту

Адреси смарт-контрактів

У цьому розділі буде описано специфіку адрес смарт-контрактів у блокчейні TON. Він також пояснить, як актори є синонімами смарт-контрактів на TON.

Все - це смарт-контракт

На TON смарт-контракти будуються за допомогою [моделі актора] (/learn/overviews/ton-blockchain#single-actor). Фактично, актори в TON технічно представлені як смарт-контракти. Це означає, що навіть ваш гаманець є простим актором (і смарт-контрактом).

Зазвичай актори обробляють вхідні повідомлення, змінюють свій внутрішній стан і в результаті генерують вихідні повідомлення. Ось чому кожен актор (тобто смарт-контракт) в блокчейні TON повинен мати адресу, щоб мати можливість отримувати повідомлення від інших акторів.

ДОСВІД EVM

У віртуальній машині Ethereum (EVM) адреси повністю відокремлені від смарт-контрактів. Ви можете дізнатися більше про відмінності, прочитавши нашу статтю ["Шість унікальних аспектів TON Blockchain, які здивують розробників Solidity"] (https://blog.ton.org/six-unique-aspects-of-ton-blockchain-that-will-surprise-solidity-developers), автор - Тал Кол.

Адреса смарт-контракту

Адреси смарт-контрактів, що працюють на TON, зазвичай складаються з двох основних компонентів:

  • (workchain_id): позначає ідентифікатор робочого ланцюжка (знакове 32-бітне ціле число)

  • (account_id) позначає адресу облікового запису (64-512 біт, залежно від ланцюжка)

У розділі огляду сирих адрес цієї документації ми обговоримо, як виглядають пари (workchain_id, account_id).

Ідентифікатор ланцюжка та ідентифікатор облікового запису

Ідентифікатор ланцюжка

[Як ми бачили раніше (/learn/overviews/ton-blockchain#workchain-blockchain-with-your-own-rules), можна створити цілих 2^32 робочих ланцюжків, що працюють на TON Blockchain. Ми також звернули увагу на те, як 32-розрядні префіксні адреси смарт-контрактів ідентифікуються і пов'язуються з адресами смарт-контрактів в різних ланцюжках. Це дозволяє смарт-контрактам відправляти і отримувати повідомлення до і від різних ланцюжків в TON Blockchain.

На сьогоднішній день в блокчейні TON працює лише майстер-ланцюг (workchain_id=-1) та іноді основний ланцюг (workchain_id=0).

Обидва вони мають 256-бітові адреси, тому ми припускаємо, що ідентифікатор workchain_id дорівнює або 0, або -1, а адреса всередині ланцюжка має точно 256 біт.

Ідентифікатор облікового запису

Всі ідентифікатори облікових записів на TON використовують 256-бітові адреси в Masterchain і Basechain (або базовому ланцюжку).

Фактично, ідентифікатор облікового запису (account_id) визначається як хеш-функція для об'єктів смарт-контракту (зокрема, SHA-256). Кожен смарт-контракт, що працює на блокчейні TON, зберігає два основних компоненти. До них відносяться:

  1. Скомпільований код. Логіка смарт-контракту, скомпільована у вигляді байт-коду.
  2. Початковий стан. Значення контракту на момент його розгортання в ланцюжку.

Нарешті, щоб точно отримати адресу контракту, необхідно обчислити хеш, що відповідає парі (Початковий код, Початковий стан) об'єкта. Наразі ми не будемо заглиблюватися в те, як працює TVM, але важливо розуміти, що ідентифікатори облікових записів на TON визначаються за такою формулою: : account_id = hash(початковий код, початковий стан).

Згодом, в цій документації, ми зануримося глибше в технічні характеристики і огляд схеми TVM і TL-B. Тепер, коли ми ознайомилися з генерацією account_id і їх взаємодією з адресами смарт-контрактів на TON, давайте пояснимо, що таке Raw і User-Friendly адреси.

Стан адреси

Кожна адреса може перебувати в одному з можливих станів:

  • неіснуючий - за цією адресою не було жодної прийнятої транзакції, тому вона не має жодних даних (або договір було видалено). Можна сказати, що спочатку всі2256 адрес знаходяться в цьому стані.
  • uninit - адреса має деякі дані, які містять баланс і метаінформацію. У цьому стані адреса ще не має коду смарт-контракту/постійних даних. Адреса переходить в цей стан, наприклад, коли її не існувало, а якась інша адреса надіслала на неї токени.
  • активний - адреса має код смарт-контракту, постійні дані та баланс. У цьому стані вона може виконувати певну логіку під час транзакції та змінювати свої постійні дані. Адреса переходить в цей стан, коли вона була uninit і було вхідне повідомлення з параметром state_init (зверніть увагу, що для розгортання цієї адреси хеш state_init і code повинен бути рівним адресі).
  • frozen - адреса не може виконувати жодних операцій, цей стан містить лише два хеші попереднього стану (комірку коду та комірку стану відповідно). Коли витрати на зберігання адреси перевищують її баланс, вона переходить у цей стан. Щоб розморозити його, ви можете відправити внутрішнє повідомлення з state_init і code, які зберігають хеші, описані раніше, і трохи Toncoin. Відновити його може бути складно, тому не варто допускати такої ситуації. Існує проект для розморожування адреси, який ви можете знайти [тут] (https://unfreezer.ton.org/).

Сирі та зручні для користувача адреси

Після короткого огляду того, як адреси смарт-контрактів в ланцюжках ланцюжків і ідентифікаторів облікових записів TON (зокрема, для Masterchain і Basechain), важливо розуміти, що ці адреси виражаються в двох основних форматах:

  • Сирі адреси: Оригінальне повне представлення адрес смарт-контрактів.
  • Зручні адреси: Зручні для користувача адреси - це покращений формат сирої адреси, який забезпечує кращу безпеку та простоту використання.

Нижче ми пояснимо відмінності між цими двома типами адрес і зануримося глибше в те, чому в TON використовуються зручні для користувача адреси.

Сира адреса

Сирі адреси смарт-контрактів складаються з ідентифікатора ланцюжка і ідентифікатора облікового запису (workchain_id, account_id) і відображаються в наступному форматі:

  • [десятковий ідентифікаторланцюга]:[64 шістнадцяткових цифри з ідентифікаторомрахунку]

Нижче наведено приклад необробленої адреси смарт-контракту з використанням ідентифікатора ланцюжка і ідентифікатора облікового запису разом (у вигляді workchain_id і account_id):

-1:fcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260

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

примітка

В адресних рядках можна використовувати великі літери (наприклад, 'A', 'B', 'C', 'D' і т.д.) замість малих (наприклад, 'a', 'b', 'c', 'd' і т.д.).

Проблеми з необробленими адресами

Використання форми Raw Address пов'язане з двома основними проблемами:

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

Зручна для користувача адреса

Зручні адреси були розроблені для того, щоб убезпечити і спростити роботу користувачів TON, які обмінюються адресами в Інтернеті (наприклад, на платформах обміну повідомленнями або через своїх постачальників послуг електронної пошти), а також в реальному світі.

Зручна для користувача адресна структура

Зручні для користувача адреси складаються загалом з 36 байт і отримуються шляхом генерації наступних компонентів по порядку:

  1. [прапори - 1 байт] - Прапори, які прив'язуються до адрес, змінюють спосіб реагування смарт-контрактів на отримане повідомлення. Типи прапорів, які використовують зручний для користувача формат адреси, включають наступні:

    • isBounceable. Позначає тип адреси, що підлягає або не підлягає поверненню. (0x11 для "bounceable", 0x51 для "non-bounceable")
    • isTestnetOnly. Позначає тип адреси, який використовується лише для цілей тестової мережі. Адреси, що починаються з 0x80, не повинні прийматися програмним забезпеченням, що працює у виробничій мережі
    • isUrlSafe. Позначає застарілий прапорець, який визначає адресу як URL-безпечну. Після цього всі адреси вважаються URL-безпечними.
  2. [workchain_id - 1 байт] - Ідентифікатор ланцюжка (workchain_id) визначається знаковим 8-бітним цілим числом workchain_id.\ (0x00 для BaseChain, 0xff для MasterChain)

  3. [account_id - 32 byte] - Ідентифікатор облікового запису складається з (big-endian) 256-бітної адреси в робочому ланцюжку.

  4. [перевірка адреси - 2 байти] - У зручних для користувача адресах перевірка адреси складається з підпису CRC16-CCITT з попередніх 34 байт. (Приклад) Насправді, ідея перевірки для зручних для користувача адрес дуже схожа на алгоритм Луна, який використовується на всіх кредитних картках, щоб запобігти помилковому введенню користувачами неіснуючих номерів карток.

Додавання цих 4 основних компонентів означає, що 1 + 1 + 32 + 2 = 36 байт загалом (на одну зручну для користувача адресу).

Щоб згенерувати зручну для користувача адресу, розробник повинен закодувати всі 36 байт, використовуючи будь-яку з них:

  • base64 (тобто з цифрами, великими та малими латинськими літерами, символами '/' та '+')
  • base64url (з '_' та '-' замість '/' та '+')

Після завершення цього процесу завершується генерація зручної для користувача адреси довжиною 48 символів без пробілів.

ПРАПОРИ DNS-АДРЕС

У домені TON DNS-адреси, такі як mywallet.ton, іноді використовуються замість сирих і зручних для користувача адрес. Насправді DNS-адреси складаються зі зручних для користувача адрес і включають всі необхідні прапори, які дозволяють розробникам отримати доступ до всіх прапорів з DNS-запису в домені TON.

Зручні для користувача приклади кодування адрес

Наприклад, смарт-контракт "test giver" (спеціальний смарт-контракт, що знаходиться в майстер-ланцюжку testnet і надсилає 2 тестових токени кожному, хто їх запитує) використовує наступну сиру адресу:

-1:fcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260

Наведена вище сира адреса "постачальника тесту" має бути перетворена у зручну для користувача адресну форму. Це можна зробити за допомогою форм base64 або base64url (які ми розглядали раніше) наступним чином:

  • kf/8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15+KsQHFLbKSMiYIny (base64)
  • kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny (base64url)
інформація

Зверніть увагу, що обидві форми (base64 і base64url) є дійсними і повинні бути прийняті!

Відновлювані та невідновлювані адреси

Основна ідея прапорця bounceable address - це безпека коштів відправника.

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

Зокрема, це стосується адрес, які можуть бути ретрансльованими:

  1. Прапор bounceable=false зазвичай означає, що отримувач є гаманцем.
  2. Прапорець bounceable=true зазвичай позначає кастомний смарт-контракт з власною прикладною логікою (наприклад, DEX). У цьому прикладі з міркувань безпеки не слід надсилати повідомлення, що не відбиваються.

Не соромтеся читати більше на цю тему в нашій документації, щоб краще зрозуміти [повідомлення, що не відскакують] (/develop/smart-contracts/guidelines/non-bouncable-messages).

Броньовані представлення base64

Додаткові двійкові дані, пов'язані з блокчейном TON, використовують подібні "броньовані" зручні для користувача представлення адрес у форматі Base64. Вони відрізняються один від одного в залежності від перших 4 символів їх байтового тегу. Наприклад, 256-бітові публічні ключі Ed25519 представляються шляхом створення 36-байтової послідовності, використовуючи описаний нижче процес:

  • Однобайтовий тег у форматі 0x3E позначає відкритий ключ
  • Однобайтовий тег у форматі 0xE6 позначає відкритий ключ Ed25519
  • 32 байти, що містять стандартне двійкове представлення відкритого ключа Ed25519
  • 2 байти, що містять представлення CRC16-CCITT у великій системі числення попередніх 34 байт

Отримана 36-байтна послідовність перетворюється в 48-символьний рядок base64 або base64url стандартним способом. Наприклад, відкритий ключ Ed25519 E39ECDA0A7B0C60A7107EC43967829DBE8BC356A49B9DFC6186B3EAC74B5477D (зазвичай представлений послідовністю з 32 байт, наприклад 0xE3, 0x9E, ..., 0x7D) через "броньоване" представлення виглядає наступним чином:

Pubjns2gp7DGCnEH7EOWeCnb6Lw1akm538YYaz6sdLVHfRB2.

Перетворення зручних для користувача адрес і сирих адрес

Найпростіший спосіб перетворення зручних для користувача та необроблених адрес - це використання одного з декількох API TON та інших інструментів, зокрема:

Крім того, існує два способи перетворення зручних і необроблених адрес гаманців за допомогою JavaScript:

Також можна скористатися подібними механізмами за допомогою [SDK] (/develop/dapps/apis/sdk).

Приклади адрес

Дізнайтеся більше прикладів про адреси TON у [Кулінарній книзі TON] (/develop/dapps/cookbook#working-with-contracts-addresses).

Можливі проблеми

При взаємодії з блокчейном TON дуже важливо розуміти наслідки переказу монет TON на адреси гаманців "uninit". У цьому розділі описані різні сценарії та їх результати, щоб забезпечити ясність щодо того, як обробляються такі транзакції.

Що відбувається, коли ви переводите Toncoin на адресу юніта?

Транзакція з включеним `state_init

Якщо ви додаєте state_init (який складається з коду і даних гаманця або смарт-контракту) до своєї транзакції. Смарт-контракт спочатку розгортається з використанням наданого state_init. Після розгортання, вхідне повідомлення обробляється, подібно до відправки на вже ініціалізований акаунт.

Транзакція без встановлених прапорів state_init та bounce

Повідомлення не може бути доставлене до смарт-контракту uninit, і воно буде повернуте назад відправнику. Після вирахування плати за спожитий газ сума, що залишилася, повертається на адресу відправника.

Транзакція без встановлених прапорів state_init та bounce

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

Як це зробити правильно

Найкращий спосіб розгорнути гаманець - це надіслати на його адресу (яка ще не ініціалізована) TON зі скинутим прапорцем bounce. Після цього кроку власник може розгорнути та ініціалізувати гаманець, використовуючи кошти за поточною неініціалізованою адресою. Цей крок зазвичай відбувається при першій операції з гаманцем.

У блокчейні TON реалізовано захист від помилкових транзакцій

У блокчейні TON стандартні гаманці та додатки автоматично керують складнощами транзакцій на неініціалізовані адреси, використовуючи bounceable і non-bounceable адреси, які описані [тут] (#bounceable-vs-non-bounceable-addresses). Загальноприйнятою практикою для гаманців при відправці монет на неініціалізовані адреси є відправка монет як на bounceable, так і на non-bounceable адреси без повернення.

Якщо є потреба швидко отримати адресу в bounceable/non-bounceable формі, це можна зробити тут.

Відповідальність за кастомні продукти

Якщо ви розробляєте власний продукт на блокчейні TON, важливо реалізувати подібні перевірки та логіку:

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