Налаштування Tenderly Web3 Actions
On-chain події вимагають реакції — іноді негайної. Якщо ціна активу впала нижче порогу ліквідації, якщо до контракту надійшов великий депозит, якщо oracle повернув застарілу цінність — все це потрібно обробити за секунди, не за години. Класичний підхід: cron-скрипт на сервері, який щохвилини опитує RPC. Це надійно приблизно до першого збою сервера або RPC-таймауту.
Tenderly Web3 Actions — це event-driven функції, які запускаються безпосередньо від on-chain подій. Інфраструктура Tenderly моніторить ноди, ви пишете логіку.
Як це працює
Web3 Action — це TypeScript функція, яка виконується в управляємому середовищі Tenderly при спрацюванні тригера. Тригери бувають трьох типів:
Transaction triggers — реакція на транзакцію до певного контракту або від певної адреси. Можна фільтрувати за статусом (success/failed), функцією (за selector), або параметрами події.
Block triggers — виконання на кожному блоці (або кожні N блоків). Використовується для моніторингу стану без очікування конкретних подій: перевірка health factor у lending протоколі, оновлення off-chain індексів.
Webhook triggers — виклик Action через HTTP з зовнішньої системи. Корисно для тестування та інтеграції з off-chain системами.
Alert triggers — реакція на алерти з Tenderly Alerting (поріг газу, велика транзакція, зміна стану контракту).
Налаштування та деплой
Робочий процес через Tenderly CLI:
npm install -g @tenderly/cli
tenderly login
tenderly init
Структура проекту:
tenderly.yaml
actions/
src/
index.ts # точки входу для Actions
package.json
Приклад Action, який реагує на подію LargeDeposit і відправляє сповіщення в Slack:
// actions/src/index.ts
import { ActionFn, Context, Event, TransactionEvent } from "@tenderly/actions";
import { ethers } from "ethers";
const THRESHOLD = ethers.parseEther("100"); // 100 ETH
export const onLargeDeposit: ActionFn = async (context: Context, event: Event) => {
const txEvent = event as TransactionEvent;
// Парсимо logs транзакції
const iface = new ethers.Interface([
"event Deposit(address indexed user, uint256 amount)"
]);
for (const log of txEvent.logs) {
try {
const parsed = iface.parseLog(log);
if (parsed?.name === "Deposit" && parsed.args.amount > THRESHOLD) {
const webhookUrl = await context.secrets.get("SLACK_WEBHOOK_URL");
await fetch(webhookUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text: `Large deposit: ${ethers.formatEther(parsed.args.amount)} ETH from ${parsed.args.user}\nTx: ${txEvent.hash}`
})
});
}
} catch {
// Log не належить нашому контракту — пропускаємо
}
}
};
Конфігурація у tenderly.yaml:
account_id: "my-account"
project_slug: "my-project"
actions:
my-project/on-large-deposit:
runtime: v2
sources: actions/src
entrypoint: index:onLargeDeposit
trigger:
type: transaction
transaction:
status:
- mined
filters:
- network: 1
eventEmitted:
contract:
address: "0xYourContractAddress"
name: Deposit
Деплой:
tenderly actions deploy
Секрети та змінні окружень
API ключи, webhook URLs, приватні ключі — все через Tenderly Secrets, не хардкодимо в код:
const apiKey = await context.secrets.get("MY_API_KEY");
const rpcUrl = await context.secrets.get("ALCHEMY_RPC_URL");
Секрети управляються через Dashboard або CLI:
tenderly actions secret set MY_API_KEY "value"
Storage між викликами
Actions stateless за замовчуванням, але Tenderly надає простий key-value store для persistence між викликами:
// Зберігаємо останній оброблений блок
await context.storage.putNumber("lastProcessedBlock", blockNumber);
// Читаємо при наступному виклику
const lastBlock = await context.storage.getNumber("lastProcessedBlock");
Storage використовується для: дедупліації сповіщень (не відправляти другий раз за ту саму подію), накопичення статистики, збереження стану між викликами block trigger.
Практичні сценарії
Автоматичне поповнення Chainlink subscription. Action стежить за балансом LINK subscription. Якщо баланс падає нижче мінімуму — викликає функцію topUp() через приватний ключ з Secrets.
Моніторинг health factor у lending. Block trigger кожні 10 блоків читає health factor всіх відкритих позицій. Якщо позиція близька до ліквідації — сповіщення користувачу через push або email.
Синхронізація з off-chain базою даних. Трансакційний тригер на подіях Transfer/Mint/Burn — оновлення PostgreSQL через REST API або пряме підключення.
Автоматичний rebalancing. Якщо дисбаланс в treasury перевищив поріг — Action збирає й відправляє транзакцію через Tenderly Simulation спочатку, потім live.
Обмеження
Максимальний час виконання Action — 25 секунд. Для довгих задач (агрегація даних, складні розрахунки) потрібен webhook до зовнішнього сервісу або черга завдань. Runtime — Node.js v20, підтримується більшість npm пакетів, але важкі native bindings не підтримуються.
Налаштування Tenderly Web3 Actions займає 1-3 робочих дні залежно від кількості сценаріїв та інтеграцій. Вартість розраховується індивідуально.







