Tenderly Simulate Asset Changes Snap
Демонстрация Tenderly MetaMask Snap
Обзор проекта
Этот проект показывает, как интегрировать симуляции транзакций в кошелёк MetaMask. Мы будем работать с MetaMask Snaps. Вы узнаете, как подключаться к Tenderly Simulation API, отправлять данные транзакции, получать результаты симуляции и отображать их пользователю через UI MetaMask. Сюда входят изменения активов в долларах, изменения баланса нативных активов, выходное значение, изменения хранилища, логи событий и трейсы вызовов. Симулированные транзакции затем можно открыть в Tenderly для дальнейшей отладки и тестирования. Ниже приведён список функций, которые мы будем добавлять в MetaMask Snap. Похожие функции можно также добавить в любой кошелёк, чтобы помочь пользователям обрести уверенность при отправке транзакций.| Функция | Описание |
|---|---|
| Отладка симуляции | Автоматически сгенерированная ссылка для инспекции и отладки симуляции в Tenderly. |
| Публично доступные симуляции | Возможность включать/отключать публичный доступ к симуляциям. |
| Изменения активов в долларовом эквиваленте | Данные в понятном формате, включая изменения активов, автоматически преобразованные в доллары. |
| Изменения баланса нативных активов | Возможность отслеживать изменения баланса нативных активов во время выполнения контракта. |
| Выходное значение | Увидеть результат вызова контракта, отображающий то, что контракт должен вернуть. |
| Изменения хранилища | Увидеть любые изменения хранилища контракта во время выполнения. |
| Логи событий | Увидеть события, которые были сгенерированы во время выполнения контракта. |
| Трейсы вызовов | Разбивка всех вызовов функций, произошедших во время выполнения. |
Предварительные требования
- Установленное расширение браузера MetaMask Flask
- Node.js (версии 16 или новее)
- Yarn (версии 3)
Перед началом сборки MetaMask Snap обязательно отключите «реальную» версию MetaMask
и установите плагин MetaMask Flask
Development.
Шаг 1. Настройка проекта MetaMask Snap
Установите официальный Create Snap CLI от MetaMask и создайте новый проект.example
example
example
Установка правильных разрешений
После установки Snap найдите файл/packages/snap/snap.manifest.json и установите разрешения, как показано ниже. Узнайте о разрешениях MetaMask здесь.
example.json
.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=fe280e95a931009bdc123e0018703f04)
Шаг 2. Генерация токенов доступа Tenderly API
Опция предпросмотра транзакции в MetaMask Snap работает на базе Tenderly Simulation API. Прежде чем начать использовать API, вам нужно сгенерировать токены доступа. Выполните следующие шаги:- Войдите в Tenderly или создайте бесплатный аккаунт здесь.
- Перейдите на страницу Authorization и нажмите кнопку Generate Access Token.
Как сгенерировать токены доступа API
.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=605d334b40293766a111dd1651f30d92)
Шаг 3. Написание логики для Snap
Основная логика, обеспечивающая работу Snap, хранится в трёх файлах:- Credentials Access (
credentials-access.ts): управляет аутентификацией и доступом к Tenderly API. - Simulation (
simulation.ts): основная логика взаимодействия с Tenderly API для симуляции транзакций и получения результатов симуляции. - Formatter (
formatter.ts): логика для парсинга результатов симуляции и форматирования их в удобном виде в UI MetaMask.
Credentials Access
Все методы, отвечающие за запрос, обновление и получение учётных данных Tenderly API, можно хранить в файле credentials-access.ts. См. исходный код здесь. Наиболее важные методы:fetchCredentials(): эта функция получает учётные данные проекта Tenderly. Если учётные данные не сохранены, она запускаетhandleUpdateTenderlyCredentialsдля запроса новых.handleUpdateTenderlyCredentials(): эта функция обрабатывает процесс обновления учётных данных проекта Tenderly. Она получает новые учётные данные, вызываяrequestNewTenderlyCredentials, а затем сохраняет их с помощью методаsnap_manageStateс операцией'update'.requestNewTenderlyCredentials(): эта функция запрашивает новые учётные данные Tenderly. Она вызываетrequestCredentials, чтобы получить сырые данные учётных записей и проверить их правильность перед возвратом объекта сaccountId,projectIdиaccessToken.
snap_manageState — встроенный метод, позволяющий Snap сохранять до 100 МБ данных
на диск. Узнайте больше здесь.
Simulation
Далее нам нужно создать логику, которая отправляет данные транзакции в Tenderly Simulation API, симулирует их и получает результаты. Для этого мы будем использовать эндпоинт APIsimulate.
Эндпоинт: https://api.tenderly.co/api/v1/account/{accountId}/project/{projectId}/simulate
Чтобы всё было организованно, поместим логику симуляции в файл simulation.ts. См. исходный код здесь.
Чтобы отправить данные транзакции в Tenderly Simulation API, нам нужно создать два ключевых метода:
- simulate(): это основная функция, которая обрабатывает симуляцию транзакции. Она получает учётные данные доступа к API, отправляет данные транзакции в Tenderly Simulation API и обрабатывает любые ошибки, возвращаемые API.
example.tsx
- submitSimulation(): эта функция отправляет запрос в API вместе с данными транзакции для симуляции.
example.tsx
Formatter
После того как API вернёт результаты симуляции, нам нужно распарсить эти данные и отформатировать их в удобном для пользователя виде для отображения в UI MetaMask. Эту логику можно хранить в файле formatter.ts. См. исходный код здесь. Основные методы форматирования:formatResponse(): эта функция получает сырые данные и учётные данные симуляции проекта Tenderly, вызывает индивидуальные функции форматирования для каждого релевантного раздела (например, изменения балансов, выходное значение, изменения активов и т. д.) и возвращает панель со всеми отформатированными выводами.formatBalanceDiff(): эта функция генерирует панель, показывающую изменения балансов для каждого аккаунта, участвующего в транзакции.formatOutputValue(): эта функция создаёт панель, представляющую выходные значения транзакции, если таковые имеются. Также она декодирует вывод, если это возможно.formatAssetChanges(): эта функция форматирует панель для отображения любых изменений активов, различая изменения ERC20, ERC721 и другие.formatStorageChanges(): эта функция создаёт панель, в которой перечислены любые изменения хранилища, произошедшие во время транзакции. Она уникально форматирует адреса и вложенные структуры данных для наглядности.formatEventLogs(): эта функция представляет логи событий, если они существуют, для каждой транзакции. Логи отформатированы для удобства чтения и включают входные значения.formatCallTrace(): эта функция создаёт отформатированную визуальную иерархию трейсов вызовов, рекурсивно показывая вложенные вызовы.formatSimulationUrl(): эта функция возвращает ссылку на полные детали симуляции в Tenderly Dashboard и отдельную ссылку для расшаривания.
Шаг 4. Отображение данных симуляции в UI MetaMask
Монорепозиторий MetaMask Snap предоставляет набор предопределённых UI-элементов и конфигураций макета. Мы будем использовать эти элементы для расширения существующего UI MetaMask и отображения результатов симуляции. Когда вы устанавливаете наш пример для MetaMask, мы показываем, как запускать разные типы симуляций:- Симуляция успешной транзакции с предопределённым payload (успешный трансфер ERC-20 и трансфер NFT)
- Симуляция неудачной транзакции с предопределённым payload
- Симуляция пользовательской транзакции с любым payload
%20(1).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=c6f3c33067b72e0ac097fac8095498b0)
Успешная симуляция с предопределённым payload
Чтобы инициировать симуляцию, мы напишем функцию, которая будет отправлять предопределённые данные транзакции с нашего адреса кошелька и вызывать RPC-методeth_sendTransaction.
example.tsx
eth_sendTransaction запустит обработчик onTransaction, который вызовет нашу пользовательскую функцию simulate, определённую в simulation.ts.
example.tsx
onTransaction функция simulate вызывается с транзакцией и её источником в качестве аргументов.
Функция simulate отвечает за получение учётных данных доступа, отправку данных транзакции в Tenderly API, обработку любых ошибок и форматирование ответа API для вывода.
Результаты симуляции отображаются в UI MetaMask. На изображениях ниже показан успешный трансфер токена ERC20 в 1 USDC на demo.eth. Вывод генерируется функциями, определёнными в файле formatter.ts.
.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=bb92ed11d3534aae5065bb162b2d2a83)
formatAssetChanges().
Вы также получите ссылку на симулированную транзакцию, которую можно открыть в Tenderly и исследовать её далее в Debugger либо ресимулировать с другими значениями.
Эта ссылка генерируется функцией formatSimulationUrl(), определённой в файле formatter.ts.
example.ts
Неудачная транзакция с предопределённым payload
Во втором примере мы симулируем неудачную транзакцию с предопределённым payload. На изображении ниже показан неудачный трансфер токена ERC20 в 1 000 000 USDC наdemo.eth.
.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=aba83c7ebdcd5583f17f53c9b21fe306)
Симуляция с пользовательским payload
Чтобы запустить симуляцию с пользовательским payload, вам нужно добавить объект, соответствующий спецификации транзакций Ethereum..webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=3910b1ef37fc7a16edfc5718e7446df5)
from:DATA, 20 байт — адрес, с которого отправляется транзакция.to:DATA, 20 байт — (опционально при создании нового контракта) адрес, на который направляется транзакция.gas:QUANTITY— (опционально, по умолчанию: 90000) целое число газа, предоставленного для выполнения транзакции. Неиспользованный газ будет возвращён.gasPrice:QUANTITY— (опционально, по умолчанию: To-Be-Determined) целое числоgasPrice, используемого для каждого оплаченного газа.value:QUANTITY— (опционально) целое число значения, отправляемого с этой транзакцией.data:DATA— скомпилированный код контракта ИЛИ хэш вызываемой сигнатуры метода и закодированные параметры.nonce:QUANTITY— (опционально) целое число nonce. Это позволяет перезаписывать ваши собственные ожидающие транзакции, использующие тот же nonce.
.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=6544e62caa22bfd1c5affec7c1f52792)
sendTransaction, что и раньше. Это передаёт пользовательский payload в обработчик onTransaction, который затем запускает функцию simulate для выполнения симуляции.