Полный код доступен в этом Github-репозитории.
Обзор проекта
Цель этого проекта — научить вас создавать Web3 Action, который получает данные из Web2 API всякий раз, когда смарт-контракт делает запрос данных через on-chain событие. Эти данные затем отправляются в контракт, запросивший их. Вот краткое описание процесса проекта.- Создаём Consumer — смарт-контракт, запрашивающий цену ETH у Oracle Contract.
- Oracle Contract запрашивает новую цену монеты у CoinGecko API с помощью события
RequestCoinPrice. - Как только запрос цены обнаружен, вызывается Web3 Action для получения значения.
- Значение цены отправляется обратно в Oracle Contract.

SimpleConsumer принимает coinPrice только от того CoinOracle, который был ему назначен при развёртывании. Кроме того, CoinOracle принимает обновления только если они подписаны тем же кошельком, который его развернул (owner).
План
Вот список шагов, которые нам нужно предпринять для построения нашего оракула:- Развернуть смарт-контракты
CoinOracleиSimpleCoinConsumer. - Получить ключ API и другую информацию, необходимую для использования одного из провайдеров Ethereum. Эти данные мы сохраним в Web3 Actions Secrets (нужно для взаимодействия 5).
- Получить приватный ключ аккаунта, развернувшего Oracle Contract (
owner), и сохранить его в Web3 Actions Secrets (нужно для подписи транзакций во взаимодействии 5). - Инициализировать каталог Web3 Actions Tenderly в вашей среде разработки и добавить npm-зависимости.
- Создать Web3 Action, который будет отправлять обновления цен в оракул.
1: Разверните смарт-контракты
Оба контракта,CoinOracle и SimpleCoinConsumer, хранятся в одном файле: CoinOracle.sol. Ознакомьтесь с исходным кодом в нашем GitHub-репозитории.
Контракт CoinOracle должен быть развёрнут первым, до контракта SimpleCoinConsumer, желательно с другого кошелька. Обязательно передайте адрес CoinOracle как параметр конструктора.
Для целей этого туториала мы развернём контракт в тестовой сети Ropsten (ID 3), но вы можете использовать любую другую.
2: Инициализация Web3 Actions
Установите Tenderly CLI (следуйте этому руководству по установке). С установленным на машине Tenderly CLI создайте новый каталогtdly-actions и перейдите в него (cd), чтобы инициализировать ваши Web3 Actions командой tenderly actions init.
example
example
3: Создайте свой Web3 Action
Прежде чем двигаться дальше, скопируйте файлCoinOracleContract.json в каталог actions. Вы можете найти этот JSON-файл в Remix или в этом GitHub-репозитории.
Задайте переменной CONTRACT_ADDRESS адрес развёрнутого Oracle:
example.ts
getPrice. Полученный от API результат — это цена в центах. Эти данные мы отправим обратно в наш смарт-контракт.
Однако прежде чем двигаться дальше, нам нужно позаботиться о некоторых технических деталях.
Побочная задача: разберитесь с Typescript. Если TypeScript выдаёт ошибку, добавьте следующие две строки в ваш файл tsconfig.json в блок compilerOptions. Это заставит TypeScript не ругаться на импорт JSON-файла как ES-модуля.
example.json
CoinOracleContract.json позволяет создать экземпляр Interface, который Ethers использует для кодирования и декодирования данных при взаимодействии со смарт-контрактами. Мы передаём часть abi всего JSON-файла.
Получите данные события. Используйте только что созданный Interface (ifc), чтобы вызвать decodeEventLog. Мы знаем, что первая запись лога (logs[0]) соответствует событию RequestCoinPrice, поэтому именно её мы хотим декодировать. В более сложных взаимодействиях, возможно, потребуется делать это динамически, как мы сделали здесь.
Необходимая Web3-обвязка, или шаблонный код. Для взаимодействия с нашим Oracle Contract нужно сделать некоторую обвязку. У контракта есть ограничение — обновления могут отправляться только owner. Это значит, что нам нужно отправлять транзакции с адреса, который его развернул. Обвязка выполняется в функции oracleContract, и вот разбор шагов.
Обвязка: настройте объект Provider. Мы можем получить провайдер, используя ethers.getDefaultProvider для работы с сетью 3 (ID Ropsten). Также передаём второй аргумент — объект конфигурации, содержащий ключ API. Обратитесь к документации ethers для получения информации о том, как настраивать других провайдеров и использовать альтернативы вроде JsonRpcProvider.
Обвязка: создайте Wallet. Нужно создать Wallet, чтобы каждая транзакция, исходящая от нашего оракула, была подписана и оплачена тем же адресом, который развернул контракт. Поскольку приватный ключ кошелька — чувствительная информация, мы читаем его из Secrets:
await context.secrets.get("w3_oracle.oracle_address_private_key")
Обвязка: создайте Contract. На этом шаге мы собираем всё созданное вместе:
- Экземпляр
ContractпередачейCONTRACT_ADDRESS. contractInterfaceдля кодирования данных, которые мы хотим отправить в сеть.oracleWalletдля подписания транзакции.
receiveWeatherUpdate и отправляет прогноз, полученный нашим оракулом. Этот участок отправляет транзакцию в наш смарт-контракт.
4: Укажите, когда выполнять ваш Web3 Action
Мы хотим выполнять транзакцию каждый раз, когдаOracleContract в сети Ropsten генерирует событие RequestCoinPrice. Хотим делать это только после того, как транзакция была заминирована.
Замените YOUR_USERNAME и YOUR_PROJECT_SLUG на ваше имя пользователя Tenderly и slug вашего проекта. Их можно скопировать из URL-адреса Dashboard:
https://dashboard.tenderly.co/{YOUR_USERNAME}/{YOUR_PROJECT_SLUG}/transactions
Также замените CONTRACT_ADDRESS на адрес развёрнутого Oracle Contract:
example.yaml
5: Создайте Secrets для Web3 Action
Чтобы Web3 Actions выполняли операции с развёрнутымOracleContract, нам нужен способ обращения к контракту. Вы можете выбрать любую сервис-провайдера (Infura, QuickNode, Alchemy, Etherscan и т. д.). Проверьте документацию Ethers по Default Provider, чтобы узнать, что нужно для установления доступа.
Так как мы используем Etherscan как провайдер, нам нужен только API-ключ. Ключ будет храниться в Web3 Actions Secrets.
Secrets. Перейдите в Tenderly Dashboard, чтобы разместить скопированный приватный ключ в Web3 Actions Secrets. На боковой панели перейдите в «Actions», нажмите «Secrets», а затем «Add New». Назовите секрет oracle.providerApiKey и вставьте токен API, а также любую другую необходимую чувствительную информацию.

OracleContract спроектирован так, чтобы принимать только те обновления, которые подписаны адресом, который его развернул.
Если вы используете MetaMask, выберите аккаунт, с которого вы развернули смарт-контракт, и скопируйте его приватный ключ согласно этому руководству MetaMask.
В Tenderly Dashboard создайте новый Secret под именем w3_oracle.oracle_address_private_key и вставьте приватный ключ.
6: Разверните ваш Web3 Action
Перейдите в корень вашего проекта (папка, содержащая файлtenderly.yaml) и выполните следующую команду:
example
7: Запустите проект
Чтобы проверить, работает ли то, что мы создали, вернитесь в Remix и вызовите функциюdoSomethingSmart контракта SimpleCoinConsumer.
Через некоторое время вы увидите выполнение во вкладке Execution в вашем Tenderly Dashboard. Также вы увидите новую транзакцию, отправленную с адреса оракула вашим Web3 Action, вызывающую функцию update контракта OracleContract. 🎉