All skills
duneanalytics avatar

/dune

@bb0c9fc
by Duneduneanalytics/skills53 stars
11

Dune CLI for querying blockchain and on-chain data via DuneSQL, searching decoded contract tables, managing saved queries, managing visualizations, managing dashboards, and monitoring credit usage on Dune. Use when user asks about blockchain data, on-chain analytics, token transfers, DEX trades, smart contract events, wallet balances, Ethereum/EVM chain queries, DuneSQL, visualizations, charts, dashboards, or says "query Dune", "search Dune datasets", "run a Dune query", "create a dashboard", or "manage dashboard".

Use this Skill: https://skilld.dev/gh/duneanalytics/skills/dune

This session only. Nothing lands on disk.

referencesdunesql-cheatsheet.md

≈2.4k tokens on demand. Your agent reads this file only when SKILL.md points to it.

DuneSQL Cheatsheet

Prerequisite: Read the main skill for authentication, global flags, and key concepts.

Quick reference for DuneSQL -- the Trino-based query engine used by Dune. Use this when writing, debugging, or optimizing queries.


Blockchain Data Types

DuneSQL extends standard SQL with types specific to on-chain data:

Type Description Example
varbinary Raw byte sequences. Used for addresses, transaction hashes, block hashes, calldata. 0xd8da6bf26964af9d7eed9e03e53415d37aa96045
uint256 Unsigned 256-bit integer. Used for token amounts, balances, gas values. 1000000000000000000 (1 ETH in wei)
int256 Signed 256-bit integer. Used for values that can be negative (e.g. price deltas). -500000000000000000
double 64-bit floating point. Used for USD prices, percentages. 1842.50
timestamp Timestamp with timezone. Used for block_time. 2024-01-15 12:30:00 UTC

Address Handling (Critical)

Addresses in Dune are stored as varbinary, not strings. This is the most common source of errors.

-- WRONG: comparing address to a string
SELECT * FROM ethereum.transactions
WHERE "from" = '0xd8da6bf26964af9d7eed9e03e53415d37aa96045'

-- CORRECT: use 0x prefix without quotes (varbinary literal)
SELECT * FROM ethereum.transactions
WHERE "from" = 0xd8da6bf26964af9d7eed9e03e53415d37aa96045

To convert between formats:

-- varbinary to hex string (for display)
SELECT CAST(address AS varchar) FROM ethereum.transactions LIMIT 1

-- hex string to varbinary (for filtering)
SELECT * FROM ethereum.transactions
WHERE "from" = FROM_HEX('d8da6bf26964af9d7eed9e03e53415d37aa96045')

Note: FROM_HEX() expects the address without the 0x prefix, but the 0x literal syntax includes it.

Token Amount Handling

Token amounts are typically stored as uint256 in raw form (no decimals). To get human-readable values:

-- Convert raw amount to human-readable (e.g. 18-decimal token like ETH/WETH)
SELECT
  CAST(value AS double) / POWER(10, 18) AS amount_eth
FROM ethereum.transactions

-- For tokens with different decimals (e.g. USDC = 6 decimals)
SELECT
  CAST(value AS double) / POWER(10, 6) AS amount_usdc
FROM erc20_ethereum.evt_Transfer
WHERE contract_address = 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48  -- USDC

Partition Columns & Query Performance

Most Dune tables are partitioned by time (typically block_time or block_date). Always filter on partition columns -- this is the single most impactful optimization for query speed and credit cost.

Why It Matters

  • Without a partition filter, Dune scans the entire table across all time
  • With a partition filter, Dune only reads the relevant time range
  • This can reduce scan size by 100-1000x and dramatically cut credit cost

How to Identify Partition Columns

When searching for datasets, always use --include-schema:

dune dataset search --query "ethereum transactions" --include-schema -o json

Look for columns named block_time, block_date, evt_block_time, call_block_time, or dt in the schema output.

Partition Filter Patterns

-- GOOD: filter on block_time (partition column)
SELECT COUNT(*) FROM ethereum.transactions
WHERE block_time >= NOW() - INTERVAL '7' DAY

-- GOOD: filter on block_date for date-level precision
SELECT COUNT(*) FROM ethereum.transactions
WHERE block_date >= DATE '2024-01-01'

-- GOOD: decoded event tables use evt_block_time
SELECT * FROM uniswap_v3_ethereum.evt_Swap
WHERE evt_block_time >= NOW() - INTERVAL '24' HOUR

-- GOOD: decoded call tables use call_block_time
SELECT * FROM uniswap_v3_ethereum.call_swap
WHERE call_block_time >= NOW() - INTERVAL '24' HOUR

-- BAD: no partition filter -- scans entire table history
SELECT COUNT(*) FROM ethereum.transactions

-- BAD: filtering only on non-partition columns
SELECT COUNT(*) FROM ethereum.transactions
WHERE "from" = 0xd8da6bf26964af9d7eed9e03e53415d37aa96045

Rule: Every query should include a WHERE clause on a partition column unless you explicitly need all-time data. Even then, consider whether a reasonable time bound exists.


Common Functions

Date & Time

-- Current time
NOW()

-- Time intervals
NOW() - INTERVAL '7' DAY
NOW() - INTERVAL '24' HOUR
NOW() - INTERVAL '30' MINUTE

-- Truncate to day/hour/week/month
DATE_TRUNC('day', block_time)
DATE_TRUNC('hour', block_time)
DATE_TRUNC('week', block_time)
DATE_TRUNC('month', block_time)

-- Extract components
EXTRACT(YEAR FROM block_time)
EXTRACT(MONTH FROM block_time)

-- Date arithmetic
DATE_ADD('day', 7, block_time)
DATE_DIFF('day', start_time, end_time)

-- Date literal
DATE '2024-01-01'

Aggregation

-- Standard aggregations
COUNT(*), COUNT(DISTINCT column)
SUM(amount), AVG(amount)
MIN(value), MAX(value)

-- Approximate distinct count (faster for large datasets)
APPROX_DISTINCT(address)

-- Percentiles
APPROX_PERCENTILE(gas_price, 0.5)   -- median
APPROX_PERCENTILE(gas_price, 0.95)  -- 95th percentile

-- Array aggregation
ARRAY_AGG(token_address)

String Functions

-- Lowercase (useful for case-insensitive matching)
LOWER(name)

-- Concatenation
CONCAT(first, ' ', last)
first || ' ' || last

-- Substring
SUBSTR(tx_hash_string, 1, 10)

-- Pattern matching
column LIKE '%uniswap%'

Byte / Hex Functions

-- Convert hex string to varbinary
FROM_HEX('d8da6bf26964af9d7eed9e03e53415d37aa96045')

-- Convert varbinary to hex string
TO_HEX(address)

-- Get byte length
LENGTH(data)

-- Substring of bytes
SUBSTR(input_data, 1, 4)   -- first 4 bytes (function selector)

-- Keccak-256 hash
KECCAK256(data)

Conditional & Type Conversion

-- CASE expressions
CASE
  WHEN amount > 1000 THEN 'whale'
  WHEN amount > 100 THEN 'dolphin'
  ELSE 'fish'
END

-- Coalesce (first non-null)
COALESCE(token_symbol, 'UNKNOWN')

-- Type casting
CAST(value AS double)
CAST(value AS varchar)
CAST(block_number AS bigint)
TRY_CAST(value AS double)   -- returns NULL instead of error

Common Query Templates

Daily Transaction Count for a Chain

SELECT
  DATE_TRUNC('day', block_time) AS day,
  COUNT(*) AS tx_count
FROM ethereum.transactions
WHERE block_time >= NOW() - INTERVAL '30' DAY
GROUP BY 1
ORDER BY 1

Top Token Transfers by Value

SELECT
  contract_address AS token,
  "from",
  "to",
  CAST(value AS double) / POWER(10, 18) AS amount
FROM erc20_ethereum.evt_Transfer
WHERE evt_block_time >= NOW() - INTERVAL '24' HOUR
ORDER BY CAST(value AS double) DESC
LIMIT 100

DEX Trade Volume (Spellbook)

SELECT
  DATE_TRUNC('day', block_time) AS day,
  project,
  SUM(amount_usd) AS volume_usd
FROM dex.trades
WHERE block_time >= NOW() - INTERVAL '7' DAY
  AND blockchain = 'ethereum'
GROUP BY 1, 2
ORDER BY 1, 3 DESC

Wallet Activity Summary

SELECT
  COUNT(*) AS tx_count,
  MIN(block_time) AS first_seen,
  MAX(block_time) AS last_seen,
  COUNT(DISTINCT DATE_TRUNC('day', block_time)) AS active_days
FROM ethereum.transactions
WHERE "from" = 0xd8da6bf26964af9d7eed9e03e53415d37aa96045
  AND block_time >= NOW() - INTERVAL '90' DAY

Gas Price Analysis

SELECT
  DATE_TRUNC('hour', block_time) AS hour,
  AVG(CAST(gas_price AS double)) / 1e9 AS avg_gwei,
  APPROX_PERCENTILE(CAST(gas_price AS double) / 1e9, 0.5) AS median_gwei,
  APPROX_PERCENTILE(CAST(gas_price AS double) / 1e9, 0.95) AS p95_gwei
FROM ethereum.transactions
WHERE block_time >= NOW() - INTERVAL '24' HOUR
GROUP BY 1
ORDER BY 1

Contract Event Count

SELECT
  topic0,
  COUNT(*) AS event_count
FROM ethereum.logs
WHERE contract_address = 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984
  AND block_time >= NOW() - INTERVAL '7' DAY
GROUP BY 1
ORDER BY 2 DESC

Common Pitfalls

Pitfall Wrong Right
Comparing addresses as strings WHERE "from" = '0xabc...' WHERE "from" = 0xabc...
Missing partition filter SELECT COUNT(*) FROM ethereum.transactions Add WHERE block_time >= NOW() - INTERVAL '7' DAY
Not quoting reserved words SELECT from, to FROM ... SELECT "from", "to" FROM ...
Raw token amounts as readable SELECT value FROM ... CAST(value AS double) / POWER(10, decimals)
FROM_HEX with 0x prefix FROM_HEX('0xabc...') FROM_HEX('abc...') (no 0x)
Using TIMESTAMP keyword WHERE block_time > TIMESTAMP '2024-01-01' WHERE block_time > CAST('2024-01-01' AS timestamp) or use DATE '2024-01-01'
Forgetting GROUP BY with agg SELECT day, COUNT(*) ... Add GROUP BY 1 or GROUP BY day
Bigint overflow in arithmetic SUM(gas_used * gas_price) SUM(CAST(gas_used AS double) * CAST(gas_price AS double)) — always cast to double before multiplying or summing large integer columns (gas_used, gas_price, value, uint256 fields) to avoid bigint overflow
Inferring identifiers from nearby data Assuming a token ID range belongs to a project because it appeared in the same table Always explicitly resolve identifiers (project IDs, pool addresses, token ID ranges) from a table/column that directly maps names to IDs. If the first table lacks the ID, search for other decoded tables that expose it. Never guess from co-located or positional data.

See Also

Source: SKILL.md on GitHub

1 alert17d5 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    The skill provides a robust interface for the Dune Analytics CLI, enabling blockchain data analysis and dashboard management. It is generally safe, although it possesses an inherent risk of indirect prompt injection as it processes data from blockchain queries. It also follows good security practices for handling API keys, including redaction instructions.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: MEDIUM · 1 issue

  • Runlayer6mo

    4/7 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at bb0c9fc. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 weeks ago.

Activeupdated 5 months ago
What it can do
Runs commands
metadata
{
  "author": "duneanalytics",
  "version": "1.0.0",
  "cli_version": "0.1"
}
All 1 allowed tools
Bash(dune:*) Bash(curl:*) Read
Other metadata
compatibility
Requires network access and the Dune CLI (auto-installed on first use). Works on macOS, Linux, and Windows.

README badge

README badge for duneanalytics/skills