Справочник Alerting API
Введение
Tenderly Alert API позволяет создавать как простые, так и сложные оповещения (Alerts). Простое оповещение состоит из одного правила, например,method_call будет срабатывать, когда транзакция вызывает ваш публичный или внешний метод. Сложное оповещение может содержать несколько условий и сработает только когда все они выполняются. Например, оповещение с method_call и state_change сработает, когда транзакция вызовет указанный метод и изменит указанный слот хранилища.
При определении оповещения через API вам необходимо указать следующее:
- каналы доставки (delivery channels), которые получат уведомление при срабатывании правила. Подробнее о каналах доставки (Delivery Channels).
- массив выражений (expressions), которые вызовут срабатывание оповещения, если все условия, представленные отдельными выражениями, будут выполнены.
Каналы доставки email, Discord и Sentry можно создавать через API (
POST /api/v1/account/{accountId}/delivery-channel). Каналы Slack, Telegram и PagerDuty требуют OAuth/бот-подключения и создаются только через Dashboard. Получить все каналы можно через API.Аутентификация
Прежде чем создавать оповещения, вам нужно настроить аутентификацию и идентифицировать ваш проект:- JavaScript
- Shell
- Python
const TENDERLY_API_KEY = 'your_api_key';
const PROJECT_SLUG = 'your_project_slug';
const ACCOUNT_ID = 'me'; // Use 'me' or your specific account ID
// Base configuration for axios
const baseConfig = {
baseURL: 'https://api.tenderly.co/api/v1',
headers: {
'X-Access-Key': TENDERLY_API_KEY,
'Content-Type': 'application/json'
}
};
export TENDERLY_API_KEY="your_api_key"
export PROJECT_SLUG="your_project_slug"
export ACCOUNT_ID="me" # Use 'me' or your specific account ID
import requests
TENDERLY_API_KEY = 'your_api_key'
PROJECT_SLUG = 'your_project_slug'
ACCOUNT_ID = 'me' # Use 'me' or your specific account ID
# Base configuration for requests
base_url = 'https://api.tenderly.co/api/v1'
headers = {
'X-Access-Key': TENDERLY_API_KEY,
'Content-Type': 'application/json'
}
Типы выражений
Для задания правил срабатывания оповещений можно использовать различные типы выражений.| Тип выражения | Мониторинг | Основной сценарий использования | Обязательные аргументы | Необязательные аргументы |
|---|---|---|---|---|
method_call | Определённые вызовы функций в контрактах (прямые или внутренние транзакции) | Отслеживание вызовов важных функций | - address: адрес контракта; signature: объект с function_name и input_types (упорядоченные ABI-типы входов, например ["address", "uint256"]) | - transaction_type: “any” (по умолчанию), “direct”, “source” или “internal”; parameter_conditions: массив условий; not: булево |
whitelisted_caller_addresses | Вызовы от определённых адресов | Контроль доступа по allow-list | - addresses: массив Ethereum-адресов | Нет |
blacklisted_caller_addresses | Вызовы от заблокированных адресов | Контроль доступа по block-list | - addresses: массив Ethereum-адресов | Нет |
contract_address | Взаимодействия с конкретным контрактом | Отслеживание всех взаимодействий с контрактом | - address: адрес контракта | - transaction_type: “direct”, “source” или “internal”; если опущен, совпадают и прямые, и внутренние вызовы |
network | События в определённых сетях | Мультичейн-мониторинг | - network_id: ID сети/цепочки | Нет |
tag | Контракты с определёнными тегами | Мониторинг по группам | - tag: строка тега | - transaction_type: “direct”, “source” или “internal”; если опущен, ведёт себя как “internal” |
tx_status | Успех/неуспех транзакции | Отслеживание неудачных транзакций | Нет | - transaction_success: boolean |
tx_value | Значение транзакции | Отслеживание крупных переводов | - transaction_value: сумма в wei; operator: оператор сравнения | Нет |
emitted_log | События контракта | Отслеживание конкретных событий | - address: адрес контракта; event_name: имя события; event_id: сигнатура события | - match_any: булево (совпадение логов любого контракта); match_non_project_contracts: булево; decode_events: булево; parameter_conditions: массив условий; not: булево |
state_change | Изменения состояния контракта | Отслеживание изменений в хранилище | - address: адрес контракта; parameter_conditions: массив условий | - match_any: булево (изменения состояния любого контракта); match_non_project_contracts: булево; not: булево; опции сравнения (порог, процент) |
view_function | Результаты read-only функций | Отслеживание вычисляемых значений | - address: адрес контракта; input: ABI-закодированные данные функции; network_id: ID сети | - parameter_condition: сравнение значения; not: булево |
eth_balance | Изменения баланса ETH | Отслеживание пороговых значений баланса | - address: адрес контракта; threshold: баланс в wei | - operator: оператор сравнения (по умолчанию <=); not: булево |
erc20_transfer_matcher | Согласованность ERC20-переводов | Проверка корректности переводов | - address: адрес токена; log_name: имя события; balances: имя переменной состояния | Нет |
Примечания
- Это все типы выражений, которые принимает API. Полезная нагрузка с любым другим значением
typeотклоняется с ошибкой400(“Expressions are not in the right format”). - Все выражения внутри оповещения объединяются логикой AND: оповещение срабатывает только тогда, когда каждое выражение совпадает с одной и той же транзакцией. Для мониторинга независимых условий создавайте отдельное оповещение для каждого.
- Для операторов сравнения (
operator) допустимые значения:>,>=,<,<=,==,!=,contains,notContains - Типы параметров (
parameter_type) включают:uint,int,bool,address,string,slice,array,tuple,fixed_bytes,bytes,hash,function - Типы выражений
emitted_log,erc20_transfer_matcher,eth_balance,tx_value,method_call,state_change,tx_statusиview_functionподдерживают необязательное полеnot: true, инвертирующее совпадение eth_balanceсрабатывает только тогда, когда транзакция переводит баланс через порог (из несоответствия в соответствие), а не на каждой транзакции, пока условие выполняется- Все адреса должны быть валидными Ethereum-адресами (с префиксом
0x, 40 hex-символов) - Значения в wei следует передавать в виде строк для работы с большими числами
- ID сети должны соответствовать целевому блокчейну (например, “1” для Ethereum mainnet)
Примеры простых выражений
Рассмотрим примеры настройки простых правил-выражений.1. Мониторинг вызовов методов
Сценарий: отслеживание вызовов определённых функций в вашем смарт-контракте.- JavaScript
- Shell
- Python
const methodCallAlert = {
name: "Critical Function Call Alert",
description: "Monitors calls to critical functions",
enabled: true,
expressions: [{
type: "method_call",
expression: {
address: "0xe592427a0aece92de3edee1f18e0157c05861564",
signature: {
function_name: "unwrapWETH9", // name of the function to match
input_types: ["uint256", "address"] // ordered ABI input types
}
}
},
{
"type": "contract_address",
"expression": {
"address": "0xe592427a0aece92de3edee1f18e0157c05861564"
}
}
],
delivery_channels: [{
id: "your_channel_id",
enabled: true
}]
};
await axios.post(
`/account/${ACCOUNT_ID}/project/${PROJECT_SLUG}/alert`,
methodCallAlert,
baseConfig
);
curl -X POST "https://api.tenderly.co/api/v1/account/${ACCOUNT_ID}/project/${PROJECT_SLUG}/alert" \
--header "Content-Type: application/json" \
--header "X-Access-Key: ${TENDERLY_API_KEY}" \
--data-raw '{
"name": "Critical Function Call Alert",
"description": "Monitors calls to critical functions",
"enabled": true,
"expressions": [
{
"type": "method_call",
"expression": {
"address": "0xe592427a0aece92de3edee1f18e0157c05861564",
"signature": {
"function_name": "unwrapWETH9",
"input_types": ["uint256", "address"]
}
}
},
{
"type": "contract_address",
"expression": {
"address": "0xe592427a0aece92de3edee1f18e0157c05861564"
}
}
],
"delivery_channels": [{
"id": "your_channel_id",
"enabled": true
}]
}'
method_call_alert = {
"name": "Critical Function Call Alert",
"description": "Monitors calls to critical functions",
"enabled": True,
"expressions": [{
"type": "method_call",
"expression": {
"address": "0xe592427a0aece92de3edee1f18e0157c05861564",
"signature": {
"function_name": "unwrapWETH9",
"input_types": ["uint256", "address"]
}
}
},
{
"type": "contract_address",
"expression": {
"address": "0xe592427a0aece92de3edee1f18e0157c05861564"
}
}],
"delivery_channels": [{
"id": "your_channel_id",
"enabled": True
}]
}
response = requests.post(
f"{base_url}/account/{ACCOUNT_ID}/project/{PROJECT_SLUG}/alert",
headers=headers,
json=method_call_alert
)
2. Мониторинг изменений состояния
Сценарий: мониторинг изменений переменных состояния контракта, особенно полезен для отслеживания критичных параметров, таких как состояние паузы или пороговые значения баланса.- JavaScript
- Shell
- Python
const stateChangeAlert = {
name: "Critical State Change Alert",
description: "Monitors important state changes",
enabled: true,
expressions: [{
type: "state_change",
expression: {
address: "0x1234....",
parameter_conditions: [
{
parameter_name: "pause",
parameter_type: "bool",
compare_change: true
},
{
parameter_name: "totalSupply",
parameter_type: "uint",
compare_percentage: true,
comparison_value: "5",
operator: ">="
}
]
}
}],
delivery_channels: [{
id: "your_channel_id",
enabled: true
}]
};
await axios.post(
`/account/${ACCOUNT_ID}/project/${PROJECT_SLUG}/alert`,
stateChangeAlert,
baseConfig
);
curl -X POST "https://api.tenderly.co/api/v1/account/${ACCOUNT_ID}/project/${PROJECT_SLUG}/alert" \
--header "Content-Type: application/json" \
--header "X-Access-Key: ${TENDERLY_API_KEY}" \
--data-raw '{
"name": "Critical State Change Alert",
"description": "Monitors important state changes",
"enabled": true,
"expressions": [{
"type": "state_change",
"expression": {
"address": "0x1234....",
"parameter_conditions": [
{
"parameter_name": "pause",
"parameter_type": "bool",
"compare_change": true
},
{
"parameter_name": "totalSupply",
"parameter_type": "uint",
"compare_percentage": true,
"comparison_value": "5",
"operator": ">="
}
]
}
}],
"delivery_channels": [{
"id": "your_channel_id",
"enabled": true
}]
}'
state_change_alert = {
"name": "Critical State Change Alert",
"description": "Monitors important state changes",
"enabled": True,
"expressions": [{
"type": "state_change",
"expression": {
"address": "0x1234....",
"parameter_conditions": [
{
"parameter_name": "pause",
"parameter_type": "bool",
"compare_change": True
},
{
"parameter_name": "totalSupply",
"parameter_type": "uint",
"compare_percentage": True,
"comparison_value": "5",
"operator": ">="
}
]
}
}],
"delivery_channels": [{
"id": "your_channel_id",
"enabled": True
}]
}
response = requests.post(
f"{base_url}/account/{ACCOUNT_ID}/project/{PROJECT_SLUG}/alert",
headers=headers,
json=state_change_alert
)
3. Мониторинг событий
Сценарий: мониторинг определённых событий, генерируемых вашими контрактами, с фильтрацией по параметрам.- JavaScript
- Shell
- Python
const eventAlert = {
name: "Large Transfer Event Alert",
description: "Monitors large transfer events",
enabled: true,
expressions: [{
type: "emitted_log",
expression: {
address: "0x1234....",
event_name: "Transfer",
event_id: "0x241ea03ca20251805084d27d4440371c34a0b85ff108f6bb5611248f73818b80",
parameter_conditions: [
{
parameter_name: "amount",
parameter_type: "uint",
operator: ">=",
comparison_value: "1000000000000000000" // 1 ETH
}
],
decode_events: true
}
}],
delivery_channels: [{
id: "your_channel_id",
enabled: true
}]
};
await axios.post(
`/account/${ACCOUNT_ID}/project/${PROJECT_SLUG}/alert`,
eventAlert,
baseConfig
);
curl -X POST "https://api.tenderly.co/api/v1/account/${ACCOUNT_ID}/project/${PROJECT_SLUG}/alert" \
--header "Content-Type: application/json" \
--header "X-Access-Key: ${TENDERLY_API_KEY}" \
--data-raw '{
"name": "Large Transfer Event Alert",
"description": "Monitors large transfer events",
"enabled": true,
"expressions": [{
"type": "emitted_log",
"expression": {
"address": "0x1234....",
"event_name": "Transfer",
"event_id": "0x241ea03ca20251805084d27d4440371c34a0b85ff108f6bb5611248f73818b80",
"parameter_conditions": [
{
"parameter_name": "amount",
"parameter_type": "uint",
"operator": ">=",
"comparison_value": "1000000000000000000"
}
],
"decode_events": true
}
}],
"delivery_channels": [{
"id": "your_channel_id",
"enabled": true
}]
}'
event_alert = {
"name": "Large Transfer Event Alert",
"description": "Monitors large transfer events",
"enabled": True,
"expressions": [{
"type": "emitted_log",
"expression": {
"address": "0x1234....",
"event_name": "Transfer",
"event_id": "0x241ea03ca20251805084d27d4440371c34a0b85ff108f6bb5611248f73818b80",
"parameter_conditions": [
{
"parameter_name": "amount",
"parameter_type": "uint",
"operator": ">=",
"comparison_value": "1000000000000000000"
}
],
"decode_events": True
}
}],
"delivery_channels": [{
"id": "your_channel_id",
"enabled": True
}]
}
response = requests.post(
f"{base_url}/account/{ACCOUNT_ID}/project/{PROJECT_SLUG}/alert",
headers=headers,
json=event_alert
)
4. Мониторинг баланса нативного ETH
Сценарий: оповещение о снижении баланса нативного ETH некоторого адреса ниже порогового значения, например, для релеера или операционного кошелька, который должен оставаться пополненным. Ограничьте оповещение сетью и адресом, затем сравните нативный баланс с пороговым значением (в wei).- JavaScript
- Shell
- Python
const balanceAlert = {
name: "Low ETH balance alert",
description: "Alerts when the native ETH balance falls below 0.1 ETH",
enabled: true,
expressions: [
// Scope to a specific network
{
type: "network",
expression: {
network_id: "1" // Ethereum mainnet
}
},
// Scope to the watched address
{
type: "contract_address",
expression: {
address: "0x3b8c2f1a9d7e4605c8a1b2d3e4f5061728394a5b"
}
},
// Trigger when the native balance drops below the threshold
{
type: "eth_balance",
expression: {
address: "0x3b8c2f1a9d7e4605c8a1b2d3e4f5061728394a5b",
threshold: "100000000000000000", // 0.1 ETH in wei
operator: "<"
}
}
],
delivery_channels: [{
id: "your_channel_id",
enabled: true
}]
};
await axios.post(
`/account/${ACCOUNT_ID}/project/${PROJECT_SLUG}/alert`,
balanceAlert,
baseConfig
);
curl -X POST "https://api.tenderly.co/api/v1/account/${ACCOUNT_ID}/project/${PROJECT_SLUG}/alert" \
--header "Content-Type: application/json" \
--header "X-Access-Key: ${TENDERLY_API_KEY}" \
--data-raw '{
"name": "Low ETH balance alert",
"description": "Alerts when the native ETH balance falls below 0.1 ETH",
"enabled": true,
"expressions": [
{
"type": "network",
"expression": {
"network_id": "1"
}
},
{
"type": "contract_address",
"expression": {
"address": "0x3b8c2f1a9d7e4605c8a1b2d3e4f5061728394a5b"
}
},
{
"type": "eth_balance",
"expression": {
"address": "0x3b8c2f1a9d7e4605c8a1b2d3e4f5061728394a5b",
"threshold": "100000000000000000",
"operator": "<"
}
}
],
"delivery_channels": [{
"id": "your_channel_id",
"enabled": true
}]
}'
balance_alert = {
"name": "Low ETH balance alert",
"description": "Alerts when the native ETH balance falls below 0.1 ETH",
"enabled": True,
"expressions": [
{
"type": "network",
"expression": {
"network_id": "1"
}
},
{
"type": "contract_address",
"expression": {
"address": "0x3b8c2f1a9d7e4605c8a1b2d3e4f5061728394a5b"
}
},
{
"type": "eth_balance",
"expression": {
"address": "0x3b8c2f1a9d7e4605c8a1b2d3e4f5061728394a5b",
"threshold": "100000000000000000",
"operator": "<"
}
}
],
"delivery_channels": [{
"id": "your_channel_id",
"enabled": True
}]
}
response = requests.post(
f"{base_url}/account/{ACCOUNT_ID}/project/{PROJECT_SLUG}/alert",
headers=headers,
json=balance_alert
)
Примеры сложных оповещений
Далее приведены примеры сложных правил-выражений. Оповещение сработает, когда каждое выражение в массивеexpressions выполнено.
1. Система мониторинга безопасности
Сценарий: комплексный мониторинг безопасности, объединяющий несколько условий:- Мониторинг вызовов административных функций
- Отслеживание крупных переводов
- Отслеживание адресов из чёрного списка
- Оповещения об изменениях критичных параметров состояния
- JavaScript
- Shell
- Python
const securityAlert = {
name: "Security Monitoring System",
description: "Comprehensive security monitoring for contract",
enabled: true,
expressions: [
{
"type": "contract_address",
"expression": {
"address": "0xe592427a0aece92de3edee1f18e0157c05861564"
}
},
// Admin function monitoring
{
type: "method_call",
expression: {
address: "0xe592427a0aece92de3edee1f18e0157c05861564",
signature: {
function_name: "transferOwnership",
input_types: ["address"]
}
}
},
// Blacklist checking
{
type: "blacklisted_caller_addresses",
expression: {
addresses: [
"0xblacklisted1...",
"0xblacklisted2..."
]
}
},
// Large value transfers
{
type: "tx_value",
expression: {
transaction_value: "100000000000000000000", // 100 ETH
operator: ">"
}
},
// Critical state changes
{
type: "state_change",
expression: {
address: "0x1234....",
parameter_conditions: [
{
parameter_name: "pause",
parameter_type: "bool",
compare_change: true
},
{
parameter_name: "owner",
parameter_type: "address",
compare_change: true
}
]
}
}
],
delivery_channels: [{
id: "your_channel_id",
enabled: true
}]
};
await axios.post(
`/account/${ACCOUNT_ID}/project/${PROJECT_SLUG}/alert`,
securityAlert,
baseConfig
);
curl -X POST "https://api.tenderly.co/api/v1/account/${ACCOUNT_ID}/project/${PROJECT_SLUG}/alert" \
--header "Content-Type: application/json" \
--header "X-Access-Key: ${TENDERLY_API_KEY}" \
--data-raw '{
"name": "Security Monitoring System",
"description": "Comprehensive security monitoring for contract",
"enabled": true,
"expressions": [
{
"type": "contract_address",
"expression": {
"address": "0xe592427a0aece92de3edee1f18e0157c05861564"
}
},
{
"type": "method_call",
"expression": {
"address": "0xe592427a0aece92de3edee1f18e0157c05861564",
"signature": {
"function_name": "transferOwnership",
"input_types": ["address"]
}
}
},
{
"type": "blacklisted_caller_addresses",
"expression": {
"addresses": [
"0xblacklisted1...",
"0xblacklisted2..."
]
}
},
{
"type": "tx_value",
"expression": {
"transaction_value": "100000000000000000000",
"operator": ">"
}
},
{
"type": "state_change",
"expression": {
"address": "0x1234....",
"parameter_conditions": [
{
"parameter_name": "pause",
"parameter_type": "bool",
"compare_change": true
},
{
"parameter_name": "owner",
"parameter_type": "address",
"compare_change": true
}
]
}
}
],
"delivery_channels": [{
"id": "your_channel_id",
"enabled": true
}]
}'
security_alert = {
"name": "Security Monitoring System",
"description": "Comprehensive security monitoring for contract",
"enabled": True,
"expressions": [
{
"type": "contract_address",
"expression": {
"address": "0xe592427a0aece92de3edee1f18e0157c05861564"
}
},
{
"type": "method_call",
"expression": {
"address": "0xe592427a0aece92de3edee1f18e0157c05861564",
"signature": {
"function_name": "transferOwnership",
"input_types": ["address"]
}
}
},
{
"type": "blacklisted_caller_addresses",
"expression": {
"addresses": [
"0xblacklisted1...",
"0xblacklisted2..."
]
}
},
{
"type": "tx_value",
"expression": {
"transaction_value": "100000000000000000000",
"operator": ">"
}
},
{
"type": "state_change",
"expression": {
"address": "0x1234....",
"parameter_conditions": [
{
"parameter_name": "pause",
"parameter_type": "bool",
"compare_change": True
},
{
"parameter_name": "owner",
"parameter_type": "address",
"compare_change": True
}
]
}
}
],
"delivery_channels": [{
"id": "your_channel_id",
"enabled": True
}]
}
response = requests.post(
f"{base_url}/account/{ACCOUNT_ID}/project/{PROJECT_SLUG}/alert",
headers=headers,
json=security_alert
)
2. Мониторинг DeFi-протокола
Сценарий: мониторинг DeFi-пула для:- Крупных сделок/свопов
- Изменений ликвидности
- Неудачных транзакций
- JavaScript
- Shell
- Python
const defiAlerts = [
// Alert 1: large swaps via events
{
name: "Large Swaps",
description: "Swap events moving 1000+ tokens out of the pool",
enabled: true,
expressions: [{
type: "emitted_log",
expression: {
address: "0xpool_address",
event_name: "Swap",
event_id: "0x...", // Swap event signature
parameter_conditions: [
{
parameter_name: "amountOut",
parameter_type: "uint",
operator: ">=",
comparison_value: "1000000000000000000000" // 1000 tokens
}
],
decode_events: true
}
}],
delivery_channels: [{ id: "your_channel_id", enabled: true }]
},
// Alert 2: liquidity changes
{
name: "Liquidity Shift",
description: "Pool reserves moved by 10% or more",
enabled: true,
expressions: [{
type: "state_change",
expression: {
address: "0xpool_address",
parameter_conditions: [
{
parameter_name: "reserve0",
parameter_type: "uint",
compare_percentage: true,
comparison_value: "10",
operator: ">="
},
{
parameter_name: "reserve1",
parameter_type: "uint",
compare_percentage: true,
comparison_value: "10",
operator: ">="
}
]
}
}],
delivery_channels: [{ id: "your_channel_id", enabled: true }]
},
// Alert 3: failed transactions on the pool
{
name: "Failed Transactions",
description: "Failed transactions involving the pool",
enabled: true,
expressions: [
{
type: "contract_address",
expression: { address: "0xpool_address" }
},
{
type: "tx_status",
expression: { transaction_success: false }
}
],
delivery_channels: [{ id: "your_channel_id", enabled: true }]
}
];
for (const alert of defiAlerts) {
await axios.post(
`/account/${ACCOUNT_ID}/project/${PROJECT_SLUG}/alert`,
alert,
baseConfig
);
}
# Alert 1: large swaps via events
curl -X POST "https://api.tenderly.co/api/v1/account/${ACCOUNT_ID}/project/${PROJECT_SLUG}/alert" \
--header "Content-Type: application/json" \
--header "X-Access-Key: ${TENDERLY_API_KEY}" \
--data-raw '{
"name": "Large Swaps",
"description": "Swap events moving 1000+ tokens out of the pool",
"enabled": true,
"expressions": [{
"type": "emitted_log",
"expression": {
"address": "0xpool_address",
"event_name": "Swap",
"event_id": "0x...",
"parameter_conditions": [
{
"parameter_name": "amountOut",
"parameter_type": "uint",
"operator": ">=",
"comparison_value": "1000000000000000000000"
}
],
"decode_events": true
}
}],
"delivery_channels": [{ "id": "your_channel_id", "enabled": true }]
}'
# Alert 2: liquidity changes
curl -X POST "https://api.tenderly.co/api/v1/account/${ACCOUNT_ID}/project/${PROJECT_SLUG}/alert" \
--header "Content-Type: application/json" \
--header "X-Access-Key: ${TENDERLY_API_KEY}" \
--data-raw '{
"name": "Liquidity Shift",
"description": "Pool reserves moved by 10% or more",
"enabled": true,
"expressions": [{
"type": "state_change",
"expression": {
"address": "0xpool_address",
"parameter_conditions": [
{
"parameter_name": "reserve0",
"parameter_type": "uint",
"compare_percentage": true,
"comparison_value": "10",
"operator": ">="
},
{
"parameter_name": "reserve1",
"parameter_type": "uint",
"compare_percentage": true,
"comparison_value": "10",
"operator": ">="
}
]
}
}],
"delivery_channels": [{ "id": "your_channel_id", "enabled": true }]
}'
# Alert 3: failed transactions on the pool
curl -X POST "https://api.tenderly.co/api/v1/account/${ACCOUNT_ID}/project/${PROJECT_SLUG}/alert" \
--header "Content-Type: application/json" \
--header "X-Access-Key: ${TENDERLY_API_KEY}" \
--data-raw '{
"name": "Failed Transactions",
"description": "Failed transactions involving the pool",
"enabled": true,
"expressions": [
{
"type": "contract_address",
"expression": { "address": "0xpool_address" }
},
{
"type": "tx_status",
"expression": { "transaction_success": false }
}
],
"delivery_channels": [{ "id": "your_channel_id", "enabled": true }]
}'
defi_alerts = [
# Alert 1: large swaps via events
{
"name": "Large Swaps",
"description": "Swap events moving 1000+ tokens out of the pool",
"enabled": True,
"expressions": [{
"type": "emitted_log",
"expression": {
"address": "0xpool_address",
"event_name": "Swap",
"event_id": "0x...",
"parameter_conditions": [
{
"parameter_name": "amountOut",
"parameter_type": "uint",
"operator": ">=",
"comparison_value": "1000000000000000000000"
}
],
"decode_events": True
}
}],
"delivery_channels": [{"id": "your_channel_id", "enabled": True}]
},
# Alert 2: liquidity changes
{
"name": "Liquidity Shift",
"description": "Pool reserves moved by 10% or more",
"enabled": True,
"expressions": [{
"type": "state_change",
"expression": {
"address": "0xpool_address",
"parameter_conditions": [
{
"parameter_name": "reserve0",
"parameter_type": "uint",
"compare_percentage": True,
"comparison_value": "10",
"operator": ">="
},
{
"parameter_name": "reserve1",
"parameter_type": "uint",
"compare_percentage": True,
"comparison_value": "10",
"operator": ">="
}
]
}
}],
"delivery_channels": [{"id": "your_channel_id", "enabled": True}]
},
# Alert 3: failed transactions on the pool
{
"name": "Failed Transactions",
"description": "Failed transactions involving the pool",
"enabled": True,
"expressions": [
{
"type": "contract_address",
"expression": {"address": "0xpool_address"}
},
{
"type": "tx_status",
"expression": {"transaction_success": False}
}
],
"delivery_channels": [{"id": "your_channel_id", "enabled": True}]
}
]
for alert in defi_alerts:
response = requests.post(
f"{base_url}/account/{ACCOUNT_ID}/project/{PROJECT_SLUG}/alert",
headers=headers,
json=alert
)
3. Мониторинг ERC20-токена
Сценарий: мониторинг токена, включающий:- Проверки согласованности Transfer
- Мониторинг крупных переводов
- Изменения totalSupply
- JavaScript
- Shell
- Python
const tokenAlerts = [
// Alert 1: Transfer event consistency
{
name: "Transfer Consistency",
description: "Transfer events inconsistent with balance changes",
enabled: true,
expressions: [{
type: "erc20_transfer_matcher",
expression: {
address: "0xtoken_address",
log_name: "Transfer",
balances: "balances"
}
}],
delivery_channels: [{ id: "your_channel_id", enabled: true }]
},
// Alert 2: large transfers
{
name: "Large Transfers",
description: "Transfers of 1000+ tokens",
enabled: true,
expressions: [{
type: "emitted_log",
expression: {
address: "0xtoken_address",
event_name: "Transfer",
event_id: "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
parameter_conditions: [
{
parameter_name: "value",
parameter_type: "uint",
operator: ">=",
comparison_value: "1000000000000000000000" // 1000 tokens
}
]
}
}],
delivery_channels: [{ id: "your_channel_id", enabled: true }]
},
// Alert 3: total supply changes
{
name: "Supply Change",
description: "totalSupply moved by 1% or more",
enabled: true,
expressions: [{
type: "state_change",
expression: {
address: "0xtoken_address",
parameter_conditions: [
{
parameter_name: "totalSupply",
parameter_type: "uint",
compare_percentage: true,
comparison_value: "1",
operator: ">="
}
]
}
}],
delivery_channels: [{ id: "your_channel_id", enabled: true }]
}
];
for (const alert of tokenAlerts) {
await axios.post(
`/account/${ACCOUNT_ID}/project/${PROJECT_SLUG}/alert`,
alert,
baseConfig
);
}
# Alert 1: Transfer event consistency
curl -X POST "https://api.tenderly.co/api/v1/account/${ACCOUNT_ID}/project/${PROJECT_SLUG}/alert" \
--header "Content-Type: application/json" \
--header "X-Access-Key: ${TENDERLY_API_KEY}" \
--data-raw '{
"name": "Transfer Consistency",
"description": "Transfer events inconsistent with balance changes",
"enabled": true,
"expressions": [{
"type": "erc20_transfer_matcher",
"expression": {
"address": "0xtoken_address",
"log_name": "Transfer",
"balances": "balances"
}
}],
"delivery_channels": [{ "id": "your_channel_id", "enabled": true }]
}'
# Alert 2: large transfers
curl -X POST "https://api.tenderly.co/api/v1/account/${ACCOUNT_ID}/project/${PROJECT_SLUG}/alert" \
--header "Content-Type: application/json" \
--header "X-Access-Key: ${TENDERLY_API_KEY}" \
--data-raw '{
"name": "Large Transfers",
"description": "Transfers of 1000+ tokens",
"enabled": true,
"expressions": [{
"type": "emitted_log",
"expression": {
"address": "0xtoken_address",
"event_name": "Transfer",
"event_id": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"parameter_conditions": [
{
"parameter_name": "value",
"parameter_type": "uint",
"operator": ">=",
"comparison_value": "1000000000000000000000"
}
]
}
}],
"delivery_channels": [{ "id": "your_channel_id", "enabled": true }]
}'
# Alert 3: total supply changes
curl -X POST "https://api.tenderly.co/api/v1/account/${ACCOUNT_ID}/project/${PROJECT_SLUG}/alert" \
--header "Content-Type: application/json" \
--header "X-Access-Key: ${TENDERLY_API_KEY}" \
--data-raw '{
"name": "Supply Change",
"description": "totalSupply moved by 1% or more",
"enabled": true,
"expressions": [{
"type": "state_change",
"expression": {
"address": "0xtoken_address",
"parameter_conditions": [
{
"parameter_name": "totalSupply",
"parameter_type": "uint",
"compare_percentage": true,
"comparison_value": "1",
"operator": ">="
}
]
}
}],
"delivery_channels": [{ "id": "your_channel_id", "enabled": true }]
}'
token_alerts = [
# Alert 1: Transfer event consistency
{
"name": "Transfer Consistency",
"description": "Transfer events inconsistent with balance changes",
"enabled": True,
"expressions": [{
"type": "erc20_transfer_matcher",
"expression": {
"address": "0xtoken_address",
"log_name": "Transfer",
"balances": "balances"
}
}],
"delivery_channels": [{"id": "your_channel_id", "enabled": True}]
},
# Alert 2: large transfers
{
"name": "Large Transfers",
"description": "Transfers of 1000+ tokens",
"enabled": True,
"expressions": [{
"type": "emitted_log",
"expression": {
"address": "0xtoken_address",
"event_name": "Transfer",
"event_id": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"parameter_conditions": [
{
"parameter_name": "value",
"parameter_type": "uint",
"operator": ">=",
"comparison_value": "1000000000000000000000"
}
]
}
}],
"delivery_channels": [{"id": "your_channel_id", "enabled": True}]
},
# Alert 3: total supply changes
{
"name": "Supply Change",
"description": "totalSupply moved by 1% or more",
"enabled": True,
"expressions": [{
"type": "state_change",
"expression": {
"address": "0xtoken_address",
"parameter_conditions": [
{
"parameter_name": "totalSupply",
"parameter_type": "uint",
"compare_percentage": True,
"comparison_value": "1",
"operator": ">="
}
]
}
}],
"delivery_channels": [{"id": "your_channel_id", "enabled": True}]
}
]
for alert in token_alerts:
response = requests.post(
f"{base_url}/account/{ACCOUNT_ID}/project/{PROJECT_SLUG}/alert",
headers=headers,
json=alert
)