Кросчейн Підключені контракти з LayerZero

ExtezyMr
Moonbeam in Ukrainian
9 min readDec 4, 2022

--

Moonbeam розширив вбудовану сумісність парачейнів на Polkadot до віддалених блокчейнів із підключеними контрактами, які були додатково посилені за допомогою нового протоколу: LayerZero.

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

LayerZero розроблено як легкий протокол взаємодії для міжланцюжкової передачі повідомлень. Переваги дизайну підключеного контракту LayerZero включають невпорядковані повідомлення та настроювану надійність. Використовуючи рішення підключених контрактів LayerZero, розробники можуть створювати dApps, які можуть використовувати функції Polkadot, Ethereum, Avalanche, Swimmer тощо.

Multichain dApps наразі є уніфікованими інтерфейсами для протоколів, дубльованих у кількох EVM. Протоколи зможуть з’єднувати свої контракти між ланцюжками, використовуючи передачу повідомлень LayerZero, щоб стати мультиланцюжковими, забезпечуючи розширену взаємодію та функціональність між тими, що інакше були б ізольованими екосистемами.

Щоб продемонструвати силу підключених контрактів, ця демонстрація надсилатиме та зберігатиме рядок від однієї TestNet EVM до іншої. Для демонстрації потрібен обліковий запис MetaMask із доданою мережею Moonbase Alpha, що можна зробити, відвідавши сайт документів Moonbeam.

Знайомство з LayerZero
LayerZero — протокол із можливістю налаштування довіри, який забезпечує безпечний міжланцюговий зв’язок. Надлегкі вузли (ULN) у формі смарт-контрактів надають ланцюгам заголовки блоків інших ланцюжків з мостами, але лише на вимогу з метою ефективності. Кінцева точка LayerZero, яка є розумним контрактом, містить ULN, спілкується з оракулом і ретранслятором.

Компонент Oracle надає та отримує заголовки блоків. Програми можуть вибирати з ринку оракулів, включаючи Chainlink, і проектувати компонент оракула, щоб вимагати згоди від кількох суб’єктів. Заголовки блоків публікуються в ланцюжках призначення, що дозволяє перевіряти повідомлення в ланцюжку. Ретранслятор отримує та надає докази міжланцюжкових повідомлень, які можна перевірити за допомогою заголовків блоків, дозволяючи завершувати повідомлення в ланцюжках призначення. Ретранслятори можуть підтримуватися будь-ким. На практиці, однак, LayerZero керує службою ретрансляції, яку програми можуть використовувати сьогодні. Протягом наступних кількох місяців реалізація ретранслятора з відкритим вихідним кодом створить ринок ретрансляторів для вибору додатків і розробить додаткові децентралізовані системи ретрансляторів, подібні до компонента Oracle. Безпека системи залежить від поділу між системами оракула та ретранслятора, і, таким чином, недовірливість системи успадковується від того, скільки довіри вимагається від акторів ретранслятора та оракула.

Зображення з LayerZero

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

Підключений контракт SimpleGeneralMessage

Тепер спробуйте це найпростішим способом. Щоб зрозуміти, що ви робите, подивіться на контракт, який ви розгортаєте, який був доступний у GitHub.

Батьківським контрактом є NonblockingLzApp, який було імпортовано з репозиторію LayerZero GitHub. Цей батьківський контракт абстрагує технічні аспекти роботи зі смарт-контрактом кінцевої точки LayerZero, тому отримувати міжланцюгові повідомлення дуже легко.

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

З короткого огляду того, як контракт NonblockingLzApp отримує повідомлення нижче, стає зрозуміло, що функція _blockingLzReceive (викликана blockingLzReceive) із батьківського контракту LzApp перевизначена. Це функція з’являється, коли підключений контракт отримує міжланцюжкове повідомлення. Ця реалізація містить рядок коду, який викликає функцію nonblockingLzReceive та перевіряє її успішність.

Перегляньте реалізацію функції nonblockingLzReceive. Все, що він робить, це гарант, що контракт викликає сам себе (отже, попередня функція), а потім викликає функцію-огортку, яку розробник може перевизначити. Єдине, що робить цей ланцюжок функцій (blockingLzReceive, _blockingLzReceive, nonblockingLzReceive), це перехоплює кожне виключення та пересилає виклик до _nonblockingLzReceive, щоб розробник міг написати спеціальну логіку, коли він отримує повідомлення.

Далі подивіться, як контракт SimpleGeneralMessage реалізує функцію _nonblockingLzReceive. Усе, що він робить, це бере корисне навантаження та записує його у відображення, щоб його можна було прочитати пізніше!

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

Тепер повернемося до коду. Для цього також потрібні лише два рядки. У першому випадку контракт кодує повідомлення в байтовий формат, щоб його можна було надіслати через ланцюги. У другому випадку повідомлення надсилається через ланцюги до контракту, до якого воно підключено. Параметри здебільшого не мають пояснень, а ті, які не є такими, не мають значення для цілей цього контракту. Основний момент полягає в тому, що ідентифікатор ланцюга призначення встановлюється для введення функції, корисне навантаження встановлюється як повідомлення, адреса повернення встановлюється як відправник повідомлення, а оплата газу ланцюга призначення (_nativeFee) є значенням повідомлення.

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

Робити — це найкращий спосіб навчитися, тому намагайтеся слідкувати за розгортанням і передавати повідомлення на Moonbase Alpha.

Розгортання з Remix на Moonbase Alpha
Найпростіший спосіб розгорнути єдиний демо-контракт — через Remix. DEV потрібен для розгортання на Moonbase Alpha, який доступний через кран, якщо у вас його ще немає.

Щоб розгорнути контракт, спочатку скопіюйте та вставте контракт у Remix або перейдіть до нього за цим посиланням Remix. Потім скомпілюйте на вкладці Solidity Compiler. Переконайтеся, що ваш MetaMask підключена до мережі Moonbase Alpha. Потім на вкладці Deploy & Run Transactions Remix встановіть середовище Injected Web3. Це використовуватиме MetaMask як постачальника Web3.

Щоб контракт міг взаємодіяти з основними функціями LayerZero, йому потрібно буде використовувати контракт кінцевої точки LayerZero. Кінцевою точкою Moonbase Alpha є 0xb23b28012ee92E8dE39DEb57Af31722223034747, а кінцеві точки інших мереж можна знайти на сайті документації LayerZero. Використовуйте цю адресу контракту в конструкторі під час розгортання контракту на Moonbase Alpha.

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

Додавання надійних джерел

Оскільки розглянутий смарт-контракт успадковується від батьківського смарт-контракту LzApp, з ним також постачається надійна система безпеки контракту. Щоб смарт-контракт викликав _nonblockingReceive під час отримання повідомлення, воно має надходити з надійного джерела.

Щоб додати контракт як довірений віддалений пристрій, необхідно викликати функцію setTrustedRemote. Лише власник контракту, за замовчуванням розгортач, може встановлювати довірені віддалені адреси. _srcChainId — це ідентифікатор ланцюга LayerZero вихідного ланцюжка, який можна знайти на сайті документації та в таблиці вище. _path — це адреса, якій слід довіряти, у форматі байтів.

LzApp зберігає одне надійне джерело з кожного ланцюжка на карті trustedRemoteLookup. Однак спосіб його зберігання складніший, ніж просто адреса. Для цього формату потрібні дві адреси, упаковані разом у формат байтів: перша є джерелом повідомлення, а остання — адресатом повідомлення. Це може здатися дивним способом, але це полегшує реалізацію в LzApp під час перевірки неавторизованих повідомлень.

Наприклад, якщо ви хочете надіслати повідомлення з контракту 0xAAAAAAAAAAAAAAAAAAAAAA у ланцюжку з lzID 100 до контракту 0xBBBBBBBBBBBBBBBBBBBBBB у ланцюжку з lzID 101, ви повинні відформатувати довірений віддалений виклик в останньому ланцюжку ось так:

setTrustedRemote(101, 0xBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAA)

Однак є простіший спосіб зробити це. У своїй реалізації LayerZero надав функцію setTrustedRemoteAddress, яка допомагає форматувати повідомлення. Все, що потрібно ввести, це ідентифікатор ланцюжка LayerZero (_remoteChainId) і адреса, якій ви хочете, щоб контракт довіряв у цільовому/віддаленому ланцюжку (_remoteAddress).

Тепер використовуйте Remix, щоб переконатися, що обидва ваші контракти довіряють один одному. Ви повинні будете зробити це в обох контрактах, які ви розгорнули. Щоб переключатися між контрактами в різних мережах, підключіться до потрібної мережі через MetaMask. Переконайтеся, що ви перебуваєте в середовищі Injected Provider і що контракт все ще має назву «SimpleGeneralMessage». Потім візьміть адресу контракту призначення та вставте її у вхідне поле За адресою.

Щоб додати довірені віддалені адреси, знайдіть функцію setTrustedRemoteAddress у контракті SimpleGeneralMessage і відкрийте її.

Коли ви перебуваєте на Moonbase Alpha, установіть _remoteChainId як ідентифікатор ланцюга LayerZero іншої вибраної мережі EVM TestNet (ідентифікатор ланцюга LayerZero можна знайти в їхній документації або в таблиці вище). Встановіть _remoteAddress як адресу контракту, який ви розгорнули в іншій мережі EVM TestNet. Після цього зробіть транзакцію та підтвердьте її в MetaMask.

Коли ви перебуваєте в альтернативній мережі EVM TestNet, установіть _remoteChainId як ідентифікатор ланцюга LayerZero Moonbase Alpha (10126). Встановіть _remoteAddress як адресу контракту, який ви розгорнули на Moonbase Alpha. Нарешті, зробіть транзакцію та підтвердьте її в MetaMask.

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

Надсилання міжланцюжкового повідомлення з Moonbase за допомогою LayerZero

Щоб надіслати міжланкове повідомлення з автоматичною транзакцією ланцюга призначення, необхідно надіслати додатковий платіж за газ із повідомленням кінцевої точки LayerZero, щоб компенсувати витрати на газ ланцюга призначення. Цей додатковий платіж за газ здійснюється у формі рідної валюти (GLMR, ETH тощо), яку ви включаєте в транзакцію та встановлюєте як вартість повідомлення.

Для цієї публікації спосіб оцінки комісії за газ між мережевими транзакціями виходить за рамки. Для простоти в TestNet найкраще надсилати велику суму, наприклад 500000000 Gwei рідної валюти, разом із міжланковим повідомленням. Якщо залишилася сума, її можна повернути, якщо вона буде визнана достатньо недорогою для цього.

Тепер ви можете використовувати інтерфейс Remix. У цьому прикладі буде надіслано міжланцюгове повідомлення до Fantom TestNet, але ви можете замінити значення газу та назву ланцюга на будь-який EVM, який хочете. Перевірте наступне:

  • Середовище є ін’єкційним постачальником — Web3 у мережі 1287 (Moonbase Alpha). У вашому гаманці з крана є значні кошти, щоб покрити як вартість транзакції, так і DEV, включений для газу ланцюга призначення
  • Ви маєте плату за газ 500000000 Gwei на попередньому кроці, розміщену у введеному значенні
  • Вставте коротке повідомлення за вашим вибором у вхід повідомлення виклику sendMessage (у цьому випадку «gm»)
    Помістіть нульовий ідентифікатор шару цільового ланцюга у вхідні дані destChainId виклику sendMessage. Оскільки ви надсилаєте транзакцію через TestNets, ідентифікатор має бути вище 10000

Коли все це буде зроблено, зробіть транзакцію виконання та підтвердьте її в MetaMask.

Відстеження Cross Chain повідомлень
Після надсилання транзакції ви зможете перейти в дослідник блоків Moonbase Alpha, щоб переглянути транзакцію, використовуючи її хеш транзакції. Якщо все пройшло добре, це буде підтверджено, і ви зможете побачити сліди введення вашої транзакції в самому низу, переглядаючи її як UTF-8.

У типовій транзакції статус і дані транзакції будуть видимі на одній сторінці в одному провіднику. Але, оскільки це обмін повідомленнями між ланцюжками, у двох ланцюгах дійсно відбуваються дві транзакції EVM.

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

Якщо ви хочете побачити повідомлення, збережене в контракті, ви можете зробити це через Remix. Спочатку підключіться до цільової мережі через MetaMask. Переконайтеся, що ви перебуваєте в середовищі Injected Provider і що вибраний контракт усе ще «SimpleGeneralMessage». Потім візьміть адресу контракту призначення та вставте її у вхідне поле За адресою. Натисніть її, і ви зможете використовувати контракт результатів, щоб переглянути останнє повідомлення.

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

Дізнайтеся більше про підключені контракти

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

Якщо ви зацікавлені в Moonbeam і хочете дізнатися більше, підпишіться на розсилку та слідкуйте за нами в соціальних мережах (посилання в шапці сторінки).

Переклад: Ernest#2379
Оригінал: https://moonbeam.network/blog/connected-contracts-layerzero/

--

--