Интеграция с Dune Analytics API
Dune давно перестал быть только инструментом для ручного анализа в браузере. С выходом Dune API появилась возможность встраивать on-chain аналитику напрямую в продукт: дашборды, отчёты, алерты — без поднятия собственного индексера и без написания SQL с нуля.
Что реально делает Dune API
API предоставляет два основных сценария: выполнение запроса по его ID (POST /execute/{queryId}) и получение результатов последнего выполнения (GET /results/{queryId}). Второй вариант существенно дешевле по credits — если данные достаточно свежие, незачем запускать новое выполнение.
import requests, time
DUNE_API_KEY = "your_api_key"
QUERY_ID = 3540604 # пример: Uniswap V3 pool stats
def get_query_results(query_id: int, params: dict = None) -> list[dict]:
headers = {"X-Dune-API-Key": DUNE_API_KEY}
# Запускаем выполнение с параметрами
execute_resp = requests.post(
f"https://api.dune.com/api/v1/query/{query_id}/execute",
headers=headers,
json={"query_parameters": params or {}}
)
execution_id = execute_resp.json()["execution_id"]
# Ждём завершения
while True:
status_resp = requests.get(
f"https://api.dune.com/api/v1/execution/{execution_id}/status",
headers=headers
)
state = status_resp.json()["state"]
if state == "QUERY_STATE_COMPLETED":
break
if state == "QUERY_STATE_FAILED":
raise RuntimeError(f"Query failed: {status_resp.json()}")
time.sleep(2)
results = requests.get(
f"https://api.dune.com/api/v1/execution/{execution_id}/results",
headers=headers
)
return results.json()["result"]["rows"]
Типичное время выполнения запроса: от 5 секунд до нескольких минут. Для production систем это неприемлемо как синхронный вызов — нужны либо кешированные результаты, либо фоновое обновление.
Параметризованные запросы и кеширование
Сильная сторона Dune API — параметризация. Запрос в браузере можно сделать универсальным через {{param}} синтаксис, и передавать значения через API. Это позволяет одним SQL покрывать, например, любой ERC-20 адрес:
SELECT
date_trunc('day', block_time) AS day,
sum(amount / 1e18) AS volume
FROM erc20_ethereum.evt_Transfer
WHERE contract_address = {{token_address}}
AND block_time >= now() - interval '{{days}}' day
GROUP BY 1
ORDER BY 1 DESC
Вызов с параметрами:
results = get_query_results(
query_id=MY_QUERY_ID,
params={"token_address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "days": "30"}
)
Кеширование — обязательно. Credits расходуются за каждое выполнение, не за чтение. Схема для большинства дашбордов:
- Данные за последние 24 часа: обновление раз в час через cron
- Исторические данные (>7 дней): обновление раз в сутки
- Результаты хранятся в Redis или PostgreSQL с TTL
Dune также отдаёт result_metadata.execution_started_at — используйте это как timestamp кеша, чтобы показывать пользователю актуальность данных.
Ограничения и обходные пути
Rate limits: на бесплатном плане — 40 запросов в месяц, на Plus — 2000, на Premium — 15000+. Для production с несколькими пользователями — Plus минимум.
Размер ответа: по умолчанию возвращается до 25000 строк. Для больших датасетов — пагинация через offset и limit параметры в запросе к результатам.
Латентность: GET /results/{queryId} без перезапуска (cached results) возвращает мгновенно. Используйте этот endpoint для read-heavy интеграций и запускайте новое выполнение только по расписанию.
Интеграция от нуля до работающего дашборда с кешированием — 1–2 дня.







