Skill v1.0.0
Trusted Publisher100/100version: "1.0.0" name: tres-tx-story description: > Analyze a blockchain transaction by its hash using TRES Finance MCP and generate a visual flow diagram showing all asset movements, followed by a plain-language explanation of what happened. Use this skill whenever the user provides a transaction hash and asks to "analyze", "explain", "visualize", "diagram", "show me what happened in", or "tell the story of" a transaction. Also trigger when the user pastes a tx hash (long hex string starting with 0x) and asks anything about it. Always use this skill for transaction hash analysis — do not attempt to answer from memory alone.
TRES Transaction Story
Fetch a transaction by hash from TRES Finance, render a flow diagram of all asset movements, and explain in plain English what happened.
MCP Server
All calls use the TRES Finance MCP server (URL: https://ai.tres.finance/mcp).
Step 1 — Authenticate
Call get_viewer (no arguments) to verify the session.
Step 2 — Fetch the Transaction
Query the transaction using its hash as the identifier:
query GetTransactionByHash($hash: String!, $currency: String) {transaction(identifier: $hash, currency: $currency, limit: 1) {results {ididentifierplatformtimestampsuccessdecodedFunctionNamemethodIdfromAddress { identifier displayName isInternal customAccountName }toAddress { identifier displayName isInternal customAccountName }contract { identifier contractName protocols applications }classification { activity action functionName }ledgerSummaryapplicationsprotocolsinternalAccounts { id name }children {idamountbalanceFactorplatformtypefiatValuenonTaxableTypeisInternalTransferfinancialActionGroupbelongsTo { id name identifier }sender { identifier displayName isInternal customAccountName }recipient { identifier displayName isInternal customAccountName }asset {identifiersymbol: keyassetClass { id symbol verificationStatus }}}}}}
Variables: { "hash": "<user_provided_hash>", "currency": "usd" }
Fallback: Ifidentifierreturns 0 results, retry withidentifier_Containsusing the last 20 characters of the hash. Hashes on some chains may be storedwithout the0xprefix — strip it and retry if still empty.
Step 3 — Parse the Data
From the result, extract:
| Field | Purpose | |
|---|---|---|
identifier | The tx hash | |
platform | Blockchain (ETHEREUM, SOLANA, etc.) | |
timestamp | Date/time | |
success | Did it succeed? | |
decodedFunctionName | What smart-contract function was called | |
fromAddress / toAddress | Top-level sender → receiver | |
contract.contractName | Smart contract involved (if any) | |
classification.activity + .action | TRES classification label | |
children[] | Each sub-transaction (individual token movement) |
For each child sub-transaction, extract:
asset.assetClass.symbol— the token symbol (e.g. ETH, USDC)amount— quantity movedfiatValue— USD equivalentbalanceFactor—1= inflow,-1= outflowbelongsTo.name— which internal wallet this belongs tosender.identifier/recipient.identifier— counterpartiestype— GAS, TOKEN_TRANSFER, etc.
Step 4 — Render the Diagram
Use the show_widget tool (Visualizer) to render an HTML widget containing an inline SVG diagram.
PRE-RENDER CHECKLIST — do this before writing a single SVG element
A. Prepare all label strings first
For every arrow label (token amount + symbol), apply these formatting rules:
- Format the amount:
- amount ≥ 1,000,000 →
"1.2M"style (1 decimal) - amount ≥ 1,000 →
"264K"or"12,233"(comma-separated integer) - amount ≥ 1 → round to 2 decimal places max
- amount < 1 → keep up to 4 significant figures (e.g.
"0.033")
- Truncate the symbol:
- symbol ≤ 6 chars → use as-is (ETH, USDC, DAI, CRV)
- symbol 7–10 chars → use as-is only if the full label fits (see step 3)
- symbol > 10 chars OR contains
+OR is a compound LP token → replace with"LP tokens"
- Measure the full label:
label = amount + " " + symbol. Count characters. Multiply by 7. That's the pixel width. - The available space for a label = the arrow's x-span minus 20px safety margin.
- Left gap (wallet→contract): x goes from 136 to 248 → span = 112px → max label = 13 chars
- Right gap (contract→wallet): x goes from 408 to 504 → span = 96px → max label = 11 chars
- If
label_px_width > available_space, shorten further: abbreviate amount to 1 sig fig, or use symbol-only if still too wide.
B. Count the arrows and calculate SVG height
- Count non-gas arrows (outflows + inflows). Call this
N. - Each arrow row occupies 34px of vertical space.
- Base node centre Y = 50 + (N × 34) / 2 (so arrows fan symmetrically around the node centre).
- Gas arrow hangs 60px below the bottom of the left wallet circle.
- SVG height = node_centre_y + node_radius + 80 (gas arrow + label + padding).
- Minimum SVG height = 230px.
C. Lay out arrow Y positions
- Space arrows evenly, 34px apart, centred on
node_centre_y. - First arrow y = node_centre_y - ((N-1) × 34) / 2
- Each subsequent arrow y += 34
- Outflow arrows (wallet → contract) use left half of diagram.
- Inflow arrows (contract → wallet) use right half.
- If there is exactly 1 inflow and multiple outflows, centre the inflow arrow at
node_centre_y.
Fixed node positions (do not change these)
ViewBox width: 640Left wallet circle: cx=90, cy=node_centre_y, r=46Contract rect: x=248, y=node_centre_y-55, width=160, height=110, rx=12Right wallet circle: cx=550, cy=node_centre_y, r=46Arrow x coordinates:Outflow (left→centre): x1=136, x2=246 midpoint_x=191Inflow (centre→right): x1=410, x2=504 midpoint_x=457Gas (downward): x1=x2=90, y1=node_centre_y+46
These x values are derived from the node edges and must not be adjusted. They guarantee labels always fall in the clear gap between nodes.
Arrow label placement rules (no exceptions)
Label x = midpoint_x of arrow (191 for outflows, 457 for inflows)Label y = arrow_y - 12text-anchor = "middle"font-size = 10.5pxfont-weight = 500
Never place a label at the same y as another label. If two arrows are only 34px apart, their labels (at y-12) are 34px apart — that is sufficient. Never stack two labels at the same y coordinate.
Never use text-anchor="start" for labels that fall near node edges — always "middle" anchored at the midpoint x.
Node internal text rules
Wallet circle (r=46, so usable text band = ±36px from centre):
Line 1 (name): y = cy - 8, font-size=11, font-weight=500Line 2 (address): y = cy + 7, font-size=9.5, font-family=monospaceLine 3 (role): y = cy + 21, font-size=9
Three lines maximum. Each line must fit within the circle width (chord at that y ≈ 80px = ~11 chars at 9px, ~9 chars at 10px). Truncate wallet names longer than 10 chars.
Contract rect (width=160, height=110):
Line 1 (name): y = rect_top + 28, font-size=11, font-weight=500Line 2 (subname): y = rect_top + 44, font-size=10Line 3 (function): y = rect_top + 60, font-size=9.5Line 4 (address): y = rect_top + 76, font-size=9, font-family=monospaceLine 5 (type): y = rect_top + 92, font-size=9
Maximum 5 lines. Each line centred at x=328. Lines must fit within 152px (160 - 8px padding each side) → max ~21 chars at 9px. Truncate anything longer.
Gas arrow rules
- Always vertical, pointing down from the bottom of the left wallet circle.
- x1 = x2 = 90 (same as wallet cx)
- y1 = node_centre_y + 46 + 2 (2px gap below circle edge)
- y2 = y1 + 55
- Label: placed to the RIGHT of the line —
x=98, y=(y1+y2)/2, text-anchor="start" - Below the arrow tip, add a small pill: rect with label "network fee", centred at x=90.
- Gas label max length:
"0.033 ETH gas"= 13 chars. Always fits.
Color coding
| Element | Fill | Stroke/Color | |
|---|---|---|---|
| Internal wallet (sender) | #EAF3DE | #639922 | |
| Internal wallet (receiver) | #dcfce7 | #16a34a | |
| Smart contract | #EEEDFE | #7F77DD | |
| Outflow arrow | — | #dc2626 | |
| Inflow arrow | — | #16a34a | |
| Gas arrow | — | #ea580c | |
| Outflow label text | — | #dc2626 | |
| Inflow label text | — | #16a34a | |
| Gas label text | — | #ea580c |
Animation
@keyframes flowDash { to { stroke-dashoffset: -40; } }@keyframes fadeUp { from { opacity:0; transform:translateY(14px); } to { opacity:1; transform:translateY(0); } }Outflow arrows: stroke-dasharray:8 5; animation: flowDash 1.1s linear infinite;Inflow arrows: stroke-dasharray:8 5; animation: flowDash 1.1s linear infinite;Gas arrow: stroke-dasharray:4 4; animation: flowDash 1.7s linear infinite;Cards/sections: opacity:0; animation: fadeUp .5s ease forwards; (staggered delays)
Header
Single line of plain text, no pill badges:
[hash-pill: 0xABCD...1234] Chain · Date · function() · ✓ success
Hash pill style: monospace, 11px, bg-secondary, border, border-radius 6px, padding 4px 10px. Everything else: 12px, color-text-secondary. Success mark: color-text-success, font-weight 500.
Stat cards (below diagram)
3-column grid, one card per: total sent (red), total received (green), gas paid (orange). Format values as: −$272,910 / 264K LP / 0.127 ETH. Keep under 12 chars. Sublabel: 11px, muted, shows token breakdown if multiple assets.
Footer route card
[function() badge] via ContractName · [protocol tag] [protocol tag] [Explain X ↗ button] Function badge: yellow bg #FEF9C3, text #854d0e, border-radius 6px. Protocol tags: bg-secondary, border, border-radius 4px, 11px. Button: calls sendPrompt('How does [ContractName/protocol] work?')
Step 5 — Plain-Language Explanation
After the diagram, write a short explanation (3–6 sentences) in simple, non-technical language. Cover:
- What happened: The core action (swap, transfer, deposit, stake, etc.)
- Who was involved: Wallets and contracts in plain terms
- What moved: Which assets changed hands and in what direction
- Net result: What the org's wallets ended up with / paid out
Tone: Imagine explaining to someone who understands crypto but not accounting. Avoid jargon like "balanceFactor", "sub-transaction", "FIFO". Say "sent", "received", "paid as gas", "swapped X for Y", etc.
Example:
This was a token swap on Uniswap. Your wallet (Main Treasury) sent 1,000 USDC tothe Uniswap V3 router contract, which in turn sent back 0.412 ETH (worth ~$1,020).You also paid 0.003 ETH (~$7.40) in gas fees to the Ethereum network.Net result: you traded stablecoins for ETH at roughly $2,476 per ETH.
Error Handling
| Situation | Action | |
|---|---|---|
| Transaction not found | Tell user the hash wasn't found in TRES. Ask if they want to check the hash or try a different one. | |
| No children (empty sub-txs) | Show header only; note "No asset movements recorded — the tx may be a failed or contract-only interaction." | |
| Missing fiat values | Show amounts without USD; note "USD value unavailable for some assets." | |
| Auth failure | Tell user to check TRES connection and re-authenticate. |