Install
$ agentstack add skill-vchrl-dune-sui-query-builder-dune-sui-query-builder ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Dune Sui Query Builder
Build, debug, and optimize DuneSQL (Trino-based) queries for Sui blockchain analytics. This skill covers Dune's Sui data model, Sui-specific quirks (object-centric architecture, binary types, event JSON parsing, package upgrades), and a class of patterns that goes beyond what the indexed tables alone can do — chained Sui RPC calls inside SQL via Dune's LiveFetch, plus oracle-grade pricing via the Pyth Hermes API for tokens that aren't in prices.hour.
Before writing any query, read references/sui-data-model.md for the table catalog and Sui-specific edge cases. For Sui DEX queries (Cetus, Bluefin, DeepBook, Aftermath, Kriya, FlowX, Momentum, BlueMove, Obric), BTCfi work, Walrus storage, or Sui chain stats — read references/sui-curated-tables.md first; these often have curated spell tables that bypass raw event archaeology. For Navi or Suilend protocol queries, read references/protocol-patterns.md — it covers package archaeology, mislabel investigations, and a fully-validated multi-market on-chain pipeline (V9) that achieves 100% asset coverage across all of Navi's markets (Main + 3 isolated, 48 reserves), priced from Navi's own on-chain oracle, with no third-party indexer. The same file carries the Suilend pack: the liquidation, obligation, and forgive event catalog, protocol-native cToken-vs-underlying pricing as the correctness core, the wrapped-token symbol map, and the IKA bad-debt case study.
For pricing any Sui asset, lead with protocol-emitted USD, then dex_sui.trades VWAP for tokens with no oracle feed, then Pyth; do not assume prices.* covers Sui (see references/sui-data-model.md § Pricing). To check a priced query or build a serving layer, read references/verification-toolkit.md and the materialized-view section in references/sui-data-model.md.
Data freshness: numbers in these docs are snapshots, not cache
This skill queries Sui live through the Dune MCP. Every specific number written in these reference files (row counts, credit costs, TVL, bad debt, penalty ratios) is an illustrative snapshot from when that example was run, never a cached value to reuse. When a task needs a current figure, run the query and read the result; do not quote the docs. This applies to the verification toolkit too: the raw-events recount and the stablecoin and penalty cross-checks are procedures to re-run, not results to copy.
Task Router
Determine which mode applies based on the user's request:
- Build — User describes what data they want in natural language → construct a query from scratch
- Debug/Review — User provides an existing query → analyze correctness, find issues, suggest fixes
- Optimize — User has a working but slow/expensive query → improve performance
- Investigate — User mentions a public Dune dashboard or query and wants to understand or differentiate from it → reverse-engineer + audit
Mode 4 deserves special attention. The most-cited "Navi Protocol" reference dashboard on Dune (Prudentia Labs / mementomori7777, 19 charts) queries Suilend's event package, not Navi's — a useful pedagogical example of why package-identity verification matters on Sui. Always reverse-engineer cited reference dashboards before competing with or building on top of them; the package hexes will tell you which protocol the queries actually cover.
Build Mode
When the user asks for a new query:
- Clarify the goal if ambiguous (e.g., "Do you mean unique depositors or deposit events? Cumulative supply or net flow? Snapshot today or time-series?"). Restate the goal before writing SQL.
- Pick the right data source. Check
references/sui-curated-tables.mdfirst — 5 curated Sui spell tables exist (dex_sui.trades,sui_tvl.btc_ecosystem,sui_daily.stats,sui_walrus.base_table,cex.addresses). If a curated table covers the question, use it. For Sui lending and most other protocol-specific Sui analytics, no curated tables exist — decide between:
sui.events— flows and actions emitted byevent::emitsui.objects— historical state changes per object-versionsui.move_call— cheap function-call countingsui.transactions— gas/success analysis- Live Sui RPC via
http_post— when state-as-of-now matters more than historical replay (TVL today, current rates, current asset list) - Pyth Hermes via
http_get— when you need oracle prices for tokens not in Dune'sprices.hour
Check references/sui-data-model.md for the table hierarchy and the LiveFetch section.
- Identify all relevant packages. Sui protocols frequently upgrade and redeploy. A query filtered on only one package ID will silently miss history. Always check for known package upgrades. For Navi and Suilend, see
references/protocol-patterns.md.
- Construct step-by-step:
- Start with the base table or the LiveFetch source
- Apply WHERE filters first: always include
WHERE date >= ...(Sui tables are partitioned bydate) - Filter by
event_type IN (...)for specific protocol events - Decode binary columns (
sender,package,owner_address,object_id) withconcat('0x', lower(to_hex(col))) - Parse event payloads with
json_extract_scalar(event_json, '$.field_name') - Aggregate and format results
- Output the query using the response format below.
Debug/Review Mode
When the user provides a query to check:
- Verify table choice — Is
sui.eventsthe best source, or do they actually needsui.objects(state) orsui.move_call(function counts) or LiveFetch (current state)? - Check partition filter — Does the query filter by
date? Missing date filter = full history scan. This is the #1 cost/timeout issue on Sui queries. - Check binary handling — A query like
WHERE sender = '0x...'fails silently (string vs binary). Correct:WHERE sender = from_hex('...')(no0xprefix insidefrom_hex) orWHERE concat('0x', lower(to_hex(sender))) = '0x...'. - Check JSON parsing —
event_jsonis a STRING containing JSON, not native JSON. Must usejson_extract_scalar(event_json, '$.field'). - Check package coverage — Does the query account for package upgrades? For multi-package protocols (Navi: 3 packages, Suilend: 1 package but with subtle event/lending_market split), missing packages = missing data eras.
- Check decimal handling — Sui amounts in events are raw integers in native token decimals. SUI = 9, USDC = 6, BTC variants = 8. Some protocols (like Navi) normalize all amounts to 9 decimals internally regardless of token decimals — the
total_supplyfield in Navi reserves divides by1e9for all assets. Verify per protocol; never assume. - Verify the protocol identity. If the query references public package hexes, cross-check them. The famous mementomori7777 "Navi" dashboard is actually Suilend (
0xf95b06141...::reserve::ReserveAssetDataEventis Suilend's, not Navi's). Wrong-protocol queries are surprisingly common. - Output analysis using the response format below.
Optimize Mode
When the user has a working but slow query:
- Add or tighten date partition filter.
WHERE date >= CURRENT_DATE - INTERVAL '90' DAYprunes partitions dramatically. - Replace
event_jsonparsing withevent_typefiltering where possible. String IN lists are pruned at plan time; JSON extraction happens per row. - Use CTEs to pre-filter multi-package unions. Each branch of a UNION ALL must apply its own date filter and event_type filter, not rely on an outer WHERE.
- Avoid
SELECT *onsui.transactionsandsui.objects— both have multi-KB string columns (raw_transaction,transaction_json,effects_json,object_json,bcs). - Use
APPROX_DISTINCTfor high-cardinality counts when exact precision isn't required. - Group by
datedirectly, notDATE_TRUNC('day', from_unixtime(timestamp_ms/1000))— the former is a column read, the latter is two function calls per row. - For LiveFetch pipelines, batch RPC calls — prefer
sui_multiGetObjectsover 35 separatesui_getObjectcalls. One http_post with 35 IDs in the params is dramatically cheaper than 35 round-trips.
Investigate Mode
When the user references a public dashboard, query, or claim about a protocol:
- Pull the SQL. Use the Dune MCP
getDuneQueryto fetch the source. Don't trust the dashboard title. - Decode the package hexes. A query labeled "Navi" filtering on
0xf95b06141...::reserve::ReserveAssetDataEventis actually Suilend. Match each package hex back to the protocol it belongs to via:
- The protocol's docs / SDK repo
- DefiLlama protocol pages
- Searching
sui.move_packagefor the deployer
- Check date-range coverage. A "Navi historical" dashboard that only shows data after Feb 2026 is missing the pre-migration package — flag this.
- Look for partition discipline. Production dashboards often skip
WHERE date >= ...filters; this is a cost bug, not a correctness bug, but it's a differentiation target. - Output an audit that names the actual protocol(s) covered, the time-coverage gaps, and any methodology weaknesses — don't politely defer to the original.
DuneSQL + Sui-Specific Syntax
DuneSQL is a Trino fork. Sui-specific quirks on top of standard Trino:
- Binary columns (
sender,package,object_id,owner_address,gas_owner,gas_object_id): useto_hex()andfrom_hex()for string conversion. Canonical Sui address:concat('0x', lower(to_hex(sender))). - JSON columns (
event_json,object_json,transaction_json,effects_json) are STRINGS, not native JSON: json_extract_scalar(event_json, '$.field')→ string (most common)json_extract(event_json, '$.field')→ JSON value (use for arrays/nested objects you'llUNNEST)cast(json_extract_scalar(event_json, '$.amount') as decimal(38,0))for numerics- For arrays:
UNNEST(CAST(json_extract(resp, '$.result.data') AS array(json))) t(item) event_typefiltering is the cleanest Sui pattern — full path::::is one string column, filter withevent_type IN (...).- Date truncation:
DATE_TRUNC('week', cast(date as timestamp))—dateis DATE, not TIMESTAMP. - Timestamp from ms:
from_unixtime(timestamp_ms / 1000)when sub-daily resolution is needed. - Intervals:
CURRENT_DATE - INTERVAL '90' DAY. - Concatenation:
||.
LiveFetch — pulling live data inside SQL
Dune supports http_get and http_post directly inside SQL. This is a game-changer for Sui lending and most DeFi protocols because Dune's curated tables don't yet cover them. When TVL, current rates, or current asset metadata matter more than historical replay, you can call Sui RPC nodes from within the query and refresh on every execution.
-- Single Sui RPC call inside SQL
SELECT http_post(
'https://fullnode.mainnet.sui.io:443',
'{"jsonrpc":"2.0","id":1,"method":"sui_getObject","params":["0x...",{"showContent":true}]}',
ARRAY['Content-Type: application/json']
) AS resp
LiveFetch is free for all Dune users, has a 5s timeout per call, and is rate-limited at ~80 req/s per proxy. Practical implication: pipelines with 1-50 RPC calls run reliably; pipelines with hundreds of calls need batching via sui_multiGetObjects or splitting across multiple queries.
For a fully-worked 4-stage dynamic pipeline (getDynamicFields → multiGetObjects → getCoinMetadata × N → Pyth Hermes), see references/protocol-patterns.md § "Navi 4-stage pipeline".
Pyth Hermes — oracle-grade pricing for any token
Tokens not in Dune's prices.hour (governance tokens like NAVX, niche assets like XAUM gold, brand-new launches) can be priced via Pyth's Hermes API:
SELECT http_get(
'https://hermes.pyth.network/v2/updates/price/latest'
|| '?ids[]=88250f854c019ef4f88a5c073d52a18bb1c6ac437033f5932cd017d24917ab46' -- NAVX/USD
|| '&ids[]=e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43' -- BTC/USD
|| '&parsed=true',
ARRAY['Content-Type: application/json']
) AS resp
Discover feed IDs at https://hermes.pyth.network/v2/price_feeds?query=&asset_type=crypto. Pyth prices come with expo (exponent) and require: price * power(10.0, expo). See references/protocol-patterns.md for full parsing pattern.
Why Pyth specifically for Sui? Pyth IS the dominant Sui oracle. Navi, Suilend, Cetus, Bluefin all consume Pyth feeds on-chain. Reading the same source the protocol uses gives you oracle-grade pricing that mirrors what the protocol sees for liquidations.
For bulk historical pricing (e.g., 30/90/365 days × multiple feeds), use Pyth Benchmarks' TradingView shim instead — Hermes' /v2/updates/price/ rate-limits under parallel load. See references/sui-data-model.md § "Bulk historical pricing — Pyth Benchmarks" for the pattern and a worked Navi example.
prices.hour — Dune's curated price feed
Dune maintains an hourly price table (prices.hour) with coverage across most chains. Quirks worth knowing:
- Filter by chain explicitly:
WHERE blockchain = 'sui'. The same symbol exists on multiple chains. - Address encoding is double-hex:
prices.hour.contract_address_varcharfor Sui stores'0x' || to_hex(to_utf8(canonical_address)). SUI's0x2becomes0x307832(hex of ASCII '0','x','2'). To join from a Sui address:pl.contract_address_hex = '0x' || to_hex(to_utf8(p.coin_address_canonical)). - Coverage gaps: smaller-cap tokens (NAVX, XAUM, niche LSTs) may be missing entirely. Always have a Pyth fallback.
Response Format
For Build Requests
**Goal:** [Restate user's request]
**Data Sources:**
- `sui.events` — [why this table]
- Sui RPC via http_post — [why live state vs indexed]
- Pyth Hermes via http_get — [why oracle vs prices.hour]
**Query:**
[Clean, executable SQL in a code block, with `date` filter always first in WHERE]
**Logic Breakdown:**
1. [Step explanation]
2. [Step explanation]
**⚠️ Sui-Specific Notes:**
- [Relevant pitfall: binary decoding, JSON parsing, package coverage, decimals, double-hex price encoding]
**💡 Optimization Tips:**
- [Partition pruning, CTE pre-filtering, batch RPC calls]
**❓ Uncertainties:**
- [Any disclaimers about unverified event_json field names, package IDs, or coin metadata layout — always flag]
For Debug/Review Requests
**Analysis:**
✅ [What's correct]
⚠️ [Issues found — prioritize: missing date filter, wrong binary/JSON handling, missing packages, wrong protocol identity]
**Suggested Changes:**
[Corrected query if needed, with explanation of each change]
**Performance Notes:**
- [Partition pruning, column selection, etc.]
**❓ Uncertainties:**
- [Any disclaimers]
For Investigate Requests
**Reference dashboard:** [URL/title]
**Query SQL fetched:** ✅
**Actual protocol covered:** [protocol name, with package hex evidence]
**Time-coverage gaps:** [which package eras are missing]
**Methodology weaknesses:** [partition filters, hardcoded values, mislabels...]
**Differentiation opportunities:** [what your dashboard should do better]
Uncertainty Handling
If an event_json field name, package ID, coin metadata field, or protocol-specific event type cannot be confirmed, always include this disclaimer:
> ⚠️ I cannot confirm event_json.$.field_name exists for this event. Verify by running a small sample query first: SELECT event_json FROM sui.events WHERE event_type = '...' AND date >= CURRENT_DATE - INTERVAL '7' DAY LIMIT 5.
For LiveFetch pipelines, also probe the RPC response shape before parsing it at scale:
-- Probe a single RPC response, view the JSON structure, THEN write the parser
SELECT http_post(
'https://fullnode.mainnet.sui.io:443',
'{"jsonrpc":"2.0","id":1,"method":"sui_getObject","params":["",{"showContent":true}]}',
ARRAY['Content-Type: application/json']
) AS resp
Never guess field paths silently. A query that
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: vchrl
- Source: vchrl/dune-sui-query-builder
- License: MIT
- Homepage: https://unchaindata.xyz/dune-dashboards
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.