dune-to-allium
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDune → Allium Query Conversion Skill
Dune 转 Allium 查询转换技能
Convert Dune Analytics (Trino) SQL queries to Allium (Snowflake) SQL. SQL dialect conversions apply to all chains. Comprehensive Solana and EVM chain mappings included.
将Dune Analytics(Trino)SQL查询转换为Allium(Snowflake)SQL。SQL方言转换适用于所有区块链网络,同时包含完整的Solana和EVM链映射关系。
Prerequisites
前置条件
- Allium API key in :
~/.allium/credentialsGet your key at https://app.allium.so/settings/api-keys. IfAPI_KEY=allium_... QUERY_ID=...is missing, theQUERY_IDscript creates one automatically.allium_query.py - (Optional) in project
DUNE_API_KEYfile for automated result fetching via.env. Alternatively, run the original query in the Dune app and export results manually.dune_query.py
- Allium API密钥需配置在中:
~/.allium/credentials可在https://app.allium.so/settings/api-keys获取密钥。如果缺少`QUERY_ID`,`allium_query.py`脚本会自动创建一个。 -(可选)在项目API_KEY=allium_... QUERY_ID=...文件中配置.env,以便通过DUNE_API_KEY自动获取结果。或者,也可以在Dune应用中运行原始查询并手动导出结果。dune_query.py
Conversion Workflow
转换流程
Step 1: Accept Dune SQL
步骤1:获取Dune SQL
Get the Dune query via one of:
- Pasted SQL: User pastes Dune SQL directly
- Saved query ID: Fetch results via Dune API for comparison:
bash
uv run ~/.claude/skills/dune-to-allium/scripts/dune_query.py QUERY_ID --json > dune_results.json
Note: Dune API free tier only supports fetching results of saved queries by ID. It does NOT support executing arbitrary SQL.
通过以下方式之一获取Dune查询:
- 粘贴SQL:用户直接粘贴Dune SQL代码
- 已保存的查询ID:通过Dune API获取结果用于对比:
bash
uv run ~/.claude/skills/dune-to-allium/scripts/dune_query.py QUERY_ID --json > dune_results.json
注意:Dune API免费版仅支持通过ID获取已保存查询的结果,不支持执行任意SQL。
Step 2: Identify Dune-Specific Tables and Syntax
步骤2:识别Dune特定表与语法
Scan the query for:
- Dune tables — Look up each in SOLANA_MAPPINGS.md table mappings section
- Dune column names — Map using the column mappings section
- Trino-specific SQL — Identify array functions, date syntax, unnest patterns
- Dune parameters — syntax needs replacement
{{param}}
Common Dune tables and their Allium equivalents:
| Dune Table | Allium Table | Special Handling |
|---|---|---|
| | Always UNION both |
| | Different approach entirely |
| | Amount is pre-normalized |
| | Different granularity! |
| | Different column names |
| |
扫描查询内容,找出:
- Dune表 — 在SOLANA_MAPPINGS.md的表映射章节中查找对应关系
- Dune列名 — 使用列映射章节进行转换
- Trino特定SQL — 识别数组函数、日期语法、unnest用法
- Dune参数 — 语法需要替换
{{param}}
常见Dune表及其Allium等价表:
| Dune表 | Allium表 | 特殊处理 |
|---|---|---|
| | 必须同时联合两个表 |
| | 处理方式完全不同 |
| | 金额已预先标准化 |
| | 粒度不同! |
| | 列名不同 |
| |
Step 3: Apply Table Mappings
步骤3:应用表映射
For each Dune table, apply the conversion from SOLANA_MAPPINGS.md:
为每个Dune表应用SOLANA_MAPPINGS.md中的转换规则:
Instructions (CRITICAL — most common conversion)
指令(关键转换——最常见场景)
sql
-- Dune: single table
FROM solana.instruction_calls
WHERE executing_account = '{program}' AND tx_success = true
-- Allium: UNION outer + inner, use parent_tx_success
WITH all_instructions AS (
SELECT * FROM solana.raw.instructions
WHERE program_id = '{program}' AND parent_tx_success = true
AND block_timestamp >= '{start}' AND block_timestamp < '{end}'
UNION ALL
SELECT * FROM solana.raw.inner_instructions
WHERE program_id = '{program}' AND parent_tx_success = true
AND block_timestamp >= '{start}' AND block_timestamp < '{end}'
)sql
-- Dune: 单表
FROM solana.instruction_calls
WHERE executing_account = '{program}' AND tx_success = true
-- Allium: 联合外部和内部指令,使用parent_tx_success
WITH all_instructions AS (
SELECT * FROM solana.raw.instructions
WHERE program_id = '{program}' AND parent_tx_success = true
AND block_timestamp >= '{start}' AND block_timestamp < '{end}'
UNION ALL
SELECT * FROM solana.raw.inner_instructions
WHERE program_id = '{program}' AND parent_tx_success = true
AND block_timestamp >= '{start}' AND block_timestamp < '{end}'
)Account Activity → Transfers
账户活动 → 转账记录
sql
-- Dune: balance changes
FROM solana.account_activity
WHERE address = '{addr}' AND tx_success = true
-- Allium: use transfers table (do NOT use balances with LAG)
FROM solana.assets.transfers
WHERE to_address = '{addr}'
AND transfer_type IN ('spl_token_transfer', 'sol_transfer')sql
-- Dune: 余额变化
FROM solana.account_activity
WHERE address = '{addr}' AND tx_success = true
-- Allium: 使用转账表(不要用LAG函数处理余额)
FROM solana.assets.transfers
WHERE to_address = '{addr}'
AND transfer_type IN ('spl_token_transfer', 'sol_transfer')Step 4: Apply SQL Dialect Conversions
步骤4:应用SQL方言转换
Apply these Trino → Snowflake transformations:
| Find | Replace With |
|---|---|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
Full reference: SOLANA_MAPPINGS.md SQL dialect section.
应用以下Trino → Snowflake转换规则:
| 查找内容 | 替换为 |
|---|---|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
完整参考:SOLANA_MAPPINGS.md的SQL方言章节。
Step 5: Handle Structural Differences
步骤5:处理结构差异
Check KNOWN_DIFFERENCES.md for expected deltas:
- Pricing: Allium prices more tokens → ~76% higher
transfers_usd_value - Jupiter swaps: Different granularity (legs vs aggregated swaps)
- Transfer types: Filter to exclude account closures
transfer_type IN ('spl_token_transfer', 'sol_transfer') - Amounts: Allium is pre-normalized — remove any
amountdivision/ pow(10, decimals)
查看KNOWN_DIFFERENCES.md了解预期的结果差异:
- 定价:Allium支持更多代币的价格数据 → 数值约高76%
transfers_usd_value - Jupiter兑换:粒度不同(单腿交易 vs 聚合交易)
- 转账类型:过滤以排除账户关闭操作
transfer_type IN ('spl_token_transfer', 'sol_transfer') - 金额:Allium的字段已预先标准化 — 移除所有
amount除法操作/ pow(10, decimals)
Step 6: Add Timestamp Filters
步骤6:添加时间戳过滤
CRITICAL: Solana tables are massive. Always add tight timestamp filters:
sql
WHERE block_timestamp >= '2024-01-01'::TIMESTAMP
AND block_timestamp < '2024-01-02'::TIMESTAMPQueries without timestamp filters on Solana tables will time out.
关键提示:Solana表数据量极大,务必添加严格的时间戳过滤:
sql
WHERE block_timestamp >= '2024-01-01'::TIMESTAMP
AND block_timestamp < '2024-01-02'::TIMESTAMP未添加时间戳过滤的Solana表查询会超时。
Step 7: Run Converted Query
步骤7:运行转换后的查询
Write the converted SQL to a file in the project directory, then execute via the Allium Explorer API:
.sqlbash
uv run ~/.claude/skills/dune-to-allium/scripts/allium_query.py --file converted_query.sqlOr with inline SQL:
bash
uv run ~/.claude/skills/dune-to-allium/scripts/allium_query.py "SELECT * FROM ethereum.raw.blocks LIMIT 10"Add to get machine-readable output:
--jsonbash
uv run ~/.claude/skills/dune-to-allium/scripts/allium_query.py --file converted_query.sql --json > /tmp/allium_results.json将转换后的SQL写入项目目录下的文件,然后通过Allium Explorer API执行:
.sqlbash
uv run ~/.claude/skills/dune-to-allium/scripts/allium_query.py --file converted_query.sql或直接执行内联SQL:
bash
uv run ~/.claude/skills/dune-to-allium/scripts/allium_query.py "SELECT * FROM ethereum.raw.blocks LIMIT 10"添加参数以获取机器可读格式的输出:
--jsonbash
uv run ~/.claude/skills/dune-to-allium/scripts/allium_query.py --file converted_query.sql --json > /tmp/allium_results.jsonStep 8: Compare Results (Optional)
步骤8:对比结果(可选)
If you have Dune results to compare against:
bash
undefined如果有Dune结果可用于对比:
bash
undefinedFetch Dune results
获取Dune结果
uv run ~/.claude/skills/dune-to-allium/scripts/dune_query.py QUERY_ID --json > /tmp/dune_results.json
uv run ~/.claude/skills/dune-to-allium/scripts/dune_query.py QUERY_ID --json > /tmp/dune_results.json
Run Allium query and save results
运行Allium查询并保存结果
uv run ~/.claude/skills/dune-to-allium/scripts/allium_query.py --file converted_query.sql --json > /tmp/allium_results.json
uv run ~/.claude/skills/dune-to-allium/scripts/allium_query.py --file converted_query.sql --json > /tmp/allium_results.json
Compare
对比结果
uv run ~/.claude/skills/dune-to-allium/scripts/compare_results.py /tmp/dune_results.json /tmp/allium_results.json
The comparison tool auto-maps known column name differences (e.g., `tx_id` ↔ `txn_id`).uv run ~/.claude/skills/dune-to-allium/scripts/compare_results.py /tmp/dune_results.json /tmp/allium_results.json
对比工具会自动映射已知的列名差异(如`tx_id` ↔ `txn_id`)。Investigating Dune Spellbook Filters
排查Dune Spellbook过滤逻辑
When results differ due to Dune spellbook filtering logic (wash trading filters, hardcoded date exclusions, etc.), search the public spellbook repo:
- Search for the table or model name
github.com/duneanalytics/spellbook - Look for clauses, CTEs named
WHERE, or hardcoded address/date exclusionsfilter - ~90% of discrepancies come from spellbook filters, not data differences
当结果差异源于Dune Spellbook过滤逻辑(洗盘交易过滤、硬编码日期排除等)时,可在公开的Spellbook仓库中搜索:
- 在中搜索表或模型名称
github.com/duneanalytics/spellbook - 查找子句、名为
WHERE的CTE,或硬编码的地址/日期排除规则filter - 约90%的差异源于Spellbook过滤逻辑,而非数据本身的差异
Checklist
检查清单
Before finalizing a conversion, verify:
在完成转换前,需验证以下内容:
All Chains
所有区块链通用
- →
block_timeblock_timestamp - →
NOW()CURRENT_TIMESTAMP() - →
INTERVAL '7' DAYINTERVAL '7 days' - →
SUM(...) FILTER (WHERE ...)SUM(CASE WHEN ... THEN ... ELSE 0 END) - →
CROSS JOIN UNNESTLATERAL FLATTEN - →
cardinality()ARRAY_SIZE() - Array indices shifted by -1 (Trino is 1-based, Snowflake is 0-based)
- references identified and inlined or flagged as blocking
query_XXXXX - calls removed (Dune UI function)
get_href() - Dune parameters () replaced with values or Snowflake variables
{{param}}
- →
block_timeblock_timestamp - →
NOW()CURRENT_TIMESTAMP() - →
INTERVAL '7' DAYINTERVAL '7 days' - →
SUM(...) FILTER (WHERE ...)SUM(CASE WHEN ... THEN ... ELSE 0 END) - →
CROSS JOIN UNNESTLATERAL FLATTEN - →
cardinality()ARRAY_SIZE() - 数组索引减1(Trino是1-based索引,Snowflake是0-based索引)
- 识别引用并内联或标记为阻塞项
query_XXXXX - 移除调用(Dune UI专用函数)
get_href() - 将Dune参数()替换为实际值或Snowflake变量
{{param}}
Solana-Specific
Solana专属
- All references use UNION of outer + inner instructions
instruction_calls - →
tx_idtxn_id - Success filter uses (not JOIN)
parent_tx_success = true - filter applied when using
transfer_typesolana.assets.transfers - Removed if using Allium's
/ pow(10, decimals)columnamount
- 所有引用均使用外部+内部指令的联合查询
instruction_calls - →
tx_idtxn_id - 成功状态过滤使用(不要用JOIN)
parent_tx_success = true - 使用时添加
solana.assets.transfers过滤transfer_type - 如果使用Allium的列,移除
amount操作/ pow(10, decimals)
EVM-Specific
EVM专属
- →
{chain}.transactions{chain}.raw.transactions - →
{chain}.logs{chain}.raw.logs - Decoded tables → /
{chain}.decoded.logswith filters{chain}.decoded.traces - Spellbook table dependencies identified (e.g., )
staking_ethereum.info - ERC20 transfers: is pre-normalized — remove
amount/ pow(10, decimals) - DEX queries: combine +
dex.orderflow(exclude overlapping txs)dex.trades - Column names: (not
TRANSACTION_HASH),TX_HASH(notUSD_AMOUNT) inAMOUNT_USDdex.trades - BSC chain prefix: (not
bsc.*orbnb.*)binance.*
- →
{chain}.transactions{chain}.raw.transactions - →
{chain}.logs{chain}.raw.logs - 解码表 → /
{chain}.decoded.logs并添加过滤条件{chain}.decoded.traces - 识别Spellbook表依赖(如)
staking_ethereum.info - ERC20转账:已预先标准化 — 移除
amount操作/ pow(10, decimals) - DEX查询:合并+
dex.orderflow(排除重叠交易)dex.trades - 列名:中使用
dex.trades(而非TRANSACTION_HASH)、TX_HASH(而非USD_AMOUNT)AMOUNT_USD - BSC链前缀:使用(而非
bsc.*或bnb.*)binance.*
Reference Files
参考文件
- SOLANA_MAPPINGS.md — Solana table/column mappings + all SQL dialect conversions (Trino → Snowflake)
- EVM_MAPPINGS.md — EVM chain table/column mappings (Ethereum, Arbitrum, Base, etc.)
- KNOWN_DIFFERENCES.md — Expected result deltas and why they occur
- SOLANA_MAPPINGS.md — Solana表/列映射关系 + 完整SQL方言转换(Trino → Snowflake)
- EVM_MAPPINGS.md — EVM链表/列映射关系(Ethereum、Arbitrum、Base等)
- KNOWN_DIFFERENCES.md — 预期的结果差异及其原因