Ознакомьтесь с этим Github-репозиторием, чтобы найти
исходный код этого проекта. Свободно клонируйте репозиторий и экспериментируйте с ним, или кодите вместе с нами.
Понимание Web3 Actions
Смарт-контракты позволяют вам выполнять пользовательский код при срабатывании события, вызове функции или, возможно, периодически. Tenderly помогает упорядочить этот процесс с помощью Web3 Actions. Вы можете написать свои Web3 Actions в одном JavaScript-файле или развернуть как NodeJS-проект. Web3 Actions также позволяют выполнять любые действия, которые обычно делают с NodeJS. Этот туториал покажет, как использовать Tenderly CLI для развёртывания Web3 Actions и обеспечения их запуска при выполнении определённых условий.Узнайте больше о Web3 Actions и о том, как использовать их в своих проектах, в Основах
Web3 Actions.
Обзор проекта
Цель этого проекта — показать вам, как развернуть смарт-контракт и написать несколько JavaScript-функций, которые Tenderly будет вызывать при возникновении события. Вы узнаете, как использовать Tenderly CLI для развёртывания ваших Web3 Actions на инфраструктуре Tenderly. Вот пошаговый обзор того, как это сделать:- Разверните смарт-контракт в тестовую сеть
- Используйте Tenderly CLI для настройки JavaScript- и конфигурационных файлов, необходимых для запуска Web3 Actions
- Разработайте функции, реагирующие на события игры
- Разверните эти функции на инфраструктуре Tenderly с помощью CLI
0: Разверните смарт-контракт
Если вы кодите вместе с нами, вы можете пропустить этот шаг и использовать контракт, который мы развернули и верифицировали в
Tenderly.
- Начало игры
- Игрок присоединяется к игре
- Игрок делает ход
- Конец игры
Предварительные условия
Создайте два аккаунта — разверните смарт-контракт в любую сеть, поддерживаемую Tenderly. Наиболее удобный способ это сделать — с помощью Remix и плагина кошелька MetaMask. Вам нужны два аккаунта с положительным балансом Ether. Эти аккаунты будут представлять двух игроков. Для целей этого туториала мы используем Sepolia. Если вы планируете следовать этому туториалу, вы можете использовать кран Sepolia для пополнения аккаунтов эфиром. Скомпилируйте контракт — используйте IDE Remix для компиляции смарт-контракта. Создайте новый файл контракта и добавьте код, найденный здесь..webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=6f20b3090790b771b014692cdcf7be9a)
Injected Web3. Нажмите «Deploy», убедившись, что аккаунт соответствует аккаунту в MetaMask.
.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=a8cfef3f43f563adbb3dfdd62177b50f)
.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=4a2339153a44fa17921bce22e01e703b)
0x133...), и сохраните его где-нибудь, так как он нам понадобится на следующих шагах.
Теперь перейдите в Tenderly Dashboard, чтобы верифицировать контракт. Это позволит нам взаимодействовать с контрактом позже в туториале.
1: Настройка Web3 Actions через Tenderly CLI
Чтобы продолжить туториал, на вашей машине должен быть установлен Tenderly CLI. Следуйте этому руководству, чтобы узнать, как его настроить и аутентифицировать доступ. С установленным CLI создайте новый каталог и перейдите в него (cd). Инициализируйте свои Web3 Actions, выполнив команду tenderly actions init:
example
tenderly actions init --language javascript.
package.json содержит npm-зависимости, которые будут доступны при развёртывании вашего Web3 Action.
Файл tsconfig.json содержит конфигурацию TypeScript,
относящуюся только к файлам .ts в каталоге
actions.1.1. Добавьте ABI контракта Tic-Tac-Toe
Прежде чем углубляться в код, скопируйте ABI, сгенерированный компилятором, в каталог actions. В нашем примере это каталогtdly-actions.
В Remix перейдите к files/artifacts/TicTacToe.json, скопируйте содержимое файла и вставьте его в файл TicTacToe.json вашего проекта.
1.2. Настройте TypeScript для импорта JSON-файла как модуля
По умолчанию TypeScript не позволяет импортировать JSON-файлы как модули. Нужно настроить TypeScript так, чтобы можно было импортировать файлTicTacToe.json как модуль и обращаться к нему как к объекту.
Перейдите в файл tsconfig.json и добавьте следующие две настройки в раздел compilerOptions:
example
2: Напишите функцию для обработки события новой игры
Напишите функцию, которая будет выполняться при начале новой игры. Переименуем файл TypeScript в что-то более описательное:example
players.
2.1. Добавьте Action
example.ts
example.ts
GameCreated, определённое в смарт-контракте.
Взглянув на смарт-контракт, мы видим, что из функции newGame генерируется только одно событие, поэтому нас интересует первая запись лога. Мы можем получить result с помощью ethers.js, декодировав txEvent.logs[0].data события GameCreated на основе TicTacToe.abi.
Здесь мы можем получить ID, ассоциированный с этой конкретной игрой, после того как она была создана: result.gameId. Мы хотим отслеживать данные для этой конкретной игры: игроков и сделанные ими ходы, используя новый экземпляр Game. Мы сохраняем объект, представляющий новую игру, в Storage такой командой: context.storage.putJson(gameId, game).
С пустой доской мы закладываем основу для сохранения будущих изменений, которые обрабатываются другими actions.
Вы также можете написать автоматизированные тесты, чтобы проверить поведение Web3 Action. Некоторые тесты доступны в репозитории, но это выходит за рамки этого туториала.
2.2. Задайте вызов New Game Action
Откройте tenderly.yaml. В разделеspecs определите спецификации для newGame (произвольное имя) для вызова функции newGameAction. Это можно сделать так: newGameAction:newGameAction, сначала определяем имя файла, содержащего функцию, а затем имя функции.
Далее укажите trigger, за которым Tenderly должен следить для вызова action. Это триггер transaction, который сработает при майнинге блока. Мы делаем это для network 3, когда событие NewGame генерируется контрактом по указанному адресу.
Замените TTT_CONTRACT_ADDRESS фактическим адресом вашего смарт-контракта. Если вы хотите развернуть контракт в сеть, отличную от Sepolia, укажите ID сети как значение network.
Замените
YOUR_USERNAME и
YOUR_PROJECT_SLUG на ваше имя пользователя Tenderly и slug вашего
проекта. Их можно скопировать из URL Dashboard:
https://dashboard.tenderly.co/{YOUR_USERNAME}/{YOUR_PROJECT_SLUG}/transactionsexample.yaml
2.3. Верифицируйте ваш смарт-контракт Tic-Tac-Toe в Tenderly
Прежде чем разворачивать контракт, нужно верифицировать его в Tenderly Dashboard. При желании вы можете загрузить контракт через браузер. После загрузки выберите контракт TicTacToe, сеть, в которую вы его развернули, и адрес контракта. Нажмите Add Contract и заполните опции компилятора, как показано на картинке ниже:.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=01b598bfc2a6fbdf63ddb1533f10d40c)
.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=e99c1eb47857101c573bddf8131cf40d)
2.4. Разверните Web3 Action в Tenderly
Чтобы развернуть ваш Web3 Action, выполните командуdeploy через Tenderly CLI:
example
.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=265837ec27e0378acfbc192074661c47)
.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=c35821d0a7d044029d8e1047cfa89ff6)
2.5. Попробуйте начать новую игру 🎉
Чтобы убедиться, что всё работает правильно, вернитесь в Remix и создайте новую игру или несколько игр. Откройте контракт TicTacToe и нажмитеnewGame. MetaMask должен запросить у вас подтверждение выполнения Web3 Action.
После того как транзакция отправлена в цепочку, Remix должен вывести результат, похожий на этот:
.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=a0aad1196ca95ba6470b8b5f0edcee12)
.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=7b2dedf972e0e4a6f9bc11fe27a33f85)
.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=ec2d6994130b322e35d858124d104898)
0xb, что означает, что это 11-я игра, начатая для этого контракта.
2.6. Проверьте Storage вашего Web3 Action
Нажмите кнопку «Go To Storage», чтобы увидеть содержимое Storage. Каждая инициированная игра получит свой слот в этой карте ключ-значение. Когда вы откроете только что созданную игру с ID 11, вы увидите нули во всех полях, что означает, что ни один игрок ещё не играл..webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=88f11391c94122ab621cac47f2bc8bdd)
3: Добавьте Web3 Action для обработки присоединения новых игроков к игре
Присоединение игрока к игре должно обрабатываться регистрацией адреса игрока и его хода (1 или 2). Помимо шаблонного кода, который помогает получить данные события, файлplayerJoinAction.ts также содержит код, позволяющий:
- Читать текущее состояние игры из storage по ID игры (
storage.getJson). - Получать адрес игрока и сохранять его ход:
game.players[player] = playerNumber - Сохранять обновлённый объект игры в storage Web3 Action с помощью
storage.putJson.
example.ts
3.1. Задайте вызов PlayerJoinedGame Action
Нам также нужно расширитьspecs в файле tenderly.yaml, чтобы включить спецификации, необходимые для вызова Web3 Action.
example.yaml
3.2. Разверните action в Tenderly
Разверните ваш Web3 Action, выполнив командуdeploy. Эта команда также переразвернёт ранее развёрнутые Web3 Actions.
example.js
3.3. Попробуйте присоединиться к новой игре
Присоединитесь к новой игре, перейдя в Remix и добавив номер игры из логов в поле вводаnewGame. Чтобы отправить транзакцию, нажмите кнопку joinGame:
.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=b775e77378e6a2706fe73eed98a3d79d)
playerNumber: 1.
.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=c528321ee8ce731435000c561537e60a)
joinGame. После завершения транзакции вы увидите похожий вывод в Execution History.
3.4. Проверьте Storage вашего Web3 Action
.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=0e7db1401134a1407e2857804a9ec87e)
.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=d98b4d0220c38499bde2925eabcc1a6c)
3.5. Добавьте Action для обработки хода игрока
Используя Ethers, мы получаем ID игры и загружаем экземпляр игры из storage. Далее обновляем поле в строкеresult.boardRow и колонке result.boardCol вводом игрока game.players[player].
Функция processNewGameState будет выводить доску в консоль, но также вы можете отправить твит при ходе, вызвать новую транзакцию в цепочке или использовать её любым другим способом.
example.ts
example.yaml
3.6. Сделайте ход, чтобы сыграть в игру
Чтобы сделать ход, используйте MetaMask для переключения на первого игрока, присоединившегося к игре. Далее введите полученный номер игры, а также строку и колонку на доске (0, 1)..webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=d87ef8ceb06a0bbd9474af3eb12c2169)
.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=781967b49bfe714430a3558cbdb95f5d)
Шаг 4. Добавьте Web3 Action для обработки окончания игры
Ниже приведён код для событияGameOver. Событие GameOver срабатывает, когда игрок делает ход, выигрывающий игру, или когда доска заполнена. Это событие срабатывает после события PlayerMadeMove. В списке txEvent.logs событие GameOver — это второй элемент.
Простой способ получить событие GameOver — обратиться к нему через txEvent.logs[1]. Однако мы реализуем более надёжное решение, не зависящее от порядка и количества сгенерированных событий.
Сначала нужно получить gameOverTopic через ethers с помощью iface.getEventTopics. Это даст вам соответствующее шестнадцатеричное значение. Далее нужно найти запись лога в txEvent.logs, список topic’ов которой содержит gameOverTopic. Это лог нашего события GameOver, который мы можем декодировать с помощью Ethers.
example.js
4.1. Задайте вызов GameOver Action
Наконец, нам нужно добавить спецификацию для вызова actionGameOver, расширив specs в tenderly.yaml:
example.yaml
4.2. Играйте в игру
Продолжайте играть, пока один из игроков не выиграет или доска не будет полностью заполнена. В конце игры Execution History должен выглядеть так:.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=eb6b64f3d40bbc512205c312c51d4c04)