一键导入
generating-dependency-graphs
Procedure for authoring contract dependency graph YAML files (reports/graph/<slug>.yaml) from a completed risk assessment report.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Procedure for authoring contract dependency graph YAML files (reports/graph/<slug>.yaml) from a completed risk assessment report.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
List of actions, guidelines and tools used for generating risk assessment reports for protocols and assets.
Focused procedure for refreshing existing risk reports by validating mutable on-chain roles, proxy implementations, TVL, strategy allocations, and other current-state data without rewriting the full assessment.
Documentation and capabilities reference for Etherscan
| name | generating-dependency-graphs |
| description | Procedure for authoring contract dependency graph YAML files (reports/graph/<slug>.yaml) from a completed risk assessment report. |
| allowed-tools | Read Write Edit Grep Glob Bash(npm:*) Bash(git:*) |
Each risk report in reports/report/ documents a protocol's contracts and their relationships in prose. A dependency-graph YAML in reports/graph/ makes those relationships visual at /graph/<slug>/ on the website (linked from /report/<slug>/ automatically when a YAML exists).
This skill turns a finished risk report into the corresponding YAML.
Follow the project workflow in CLAUDE.md: pull latest master before starting and open a draft PR when the graph task is ready.
reports/report/<slug>.md is finalized and the next natural step is to publish its graph.reports/graph/<slug>.yaml already exists — unless explicitly updating it (e.g. after a reassessment changed the strategy mix).The corresponding reports/report/<slug>.md. The sections worth mining:
You should not need to make new onchain calls or open Etherscan — the report has already verified everything.
reports/graph/<slug>.yaml..md file. The URL /graph/<slug>/ is generated by src/pages/graph/[slug].astro via getStaticPaths().hasGraph(slug) returns true — no code change needed.The schema is enforced at build time by the validator in src/lib/graph.ts. Authoritative field list (mirror of the TypeScript types in that file):
| Top-level | Required | Type | Notes |
|---|---|---|---|
slug | yes | string | Must match the filename and the report slug. |
title | no | string | Shown in the page header. Defaults to the slug. |
chain | yes | string | Default chain for nodes. ethereum, polygon, base, arbitrum, sonic, katana, hyperevm. |
categories | yes | list | Subset of the fixed 5 categories below. Only declare what the graph uses. |
nodes | yes | list | See node fields. |
edges | yes | list | See edge fields. |
Node fields:
| Field | Required | Type | Notes |
|---|---|---|---|
id | yes | string | Unique within the file. Slug-style, e.g. susds-lender. |
label | yes | string | Card title. Keep ≤ ~40 chars; it wraps to 2 lines. |
category | yes | enum | One of the 5 below. |
address | no | string | EVM address. Used to build the Etherscan link on click. |
chain | no | string | Per-node chain override; falls back to top-level chain. |
note | no | string | Free-form context shown in tooltips (future use); useful when address is absent. |
Edge fields:
| Field | Required | Type | Notes |
|---|---|---|---|
from | yes | string | Must match a node id. |
to | yes | string | Must match a node id. |
kind | yes | enum | One of the 10 below — drives edge color/style and legend grouping. |
label | no | string | Optional inline label. Only allocates-to always carries one (the % share); other kinds carry labels only when the value adds information. |
Minimal example (from reports/graph/yearn-yvusdc.yaml):
slug: yearn-yvusdc
title: yvUSDC-1 — Contract Dependency Graph
chain: ethereum
categories:
- { id: vault, label: Vault }
- { id: strategy, label: Strategy }
- { id: dependency, label: External Dependency }
nodes:
- id: yvUSDC
label: yvUSDC-1
address: "0xBe53A109B494E5c9f97b9Cd39Fe969BE68BF6204"
category: vault
- id: susds-lender
label: USDC → sUSDS Lender (97.15%)
address: "0x7130570BCEfCedBe9d15B5b11A33006156460f8f"
category: strategy
- id: sky-susds
label: Sky / sUSDS (Savings Rate)
address: "0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD"
category: dependency
edges:
- { from: yvUSDC, to: susds-lender, kind: allocates-to, label: "97.15%" }
- { from: susds-lender, to: sky-susds, kind: deposits-into, label: "USDS → sUSDS" }
These enums are fixed — extending them requires coordinated styling changes in src/pages/graph/[slug].astro (the .cat-* CSS rules and the flow/role/gov sets in the client script). Don't invent new values ad-hoc.
id | Use for |
|---|---|
vault | The user-facing vault token(s) and the receipt/share tokens. The "what the user holds" layer. |
strategy | An active investment leg — Yearn V3 strategies, InfiniFi farms, looper positions. |
governance | Multisigs, timelocks, access-control root contracts, role-managers, governance tokens with control rights. |
infra | Internal protocol machinery that isn't itself governance — mint/redeem controllers, debt allocators, keepers, accountants the graph still benefits from showing. |
dependency | External protocols the strategies sit on top of — Sky/sUSDS, Spark, Morpho vaults, Maple pools, Midas tokens, escrow counterparties. |
Grouped by the visual style they get (this matches the legend on the rendered page). Three of them — allocates-to, deposits-into, routes-through — are flow kinds, which have extra effects (see "Flow kinds" below the tables).
Money flow — solid teal lines, prominent:
kind | Meaning | Label renders on page? |
|---|---|---|
allocates-to | Vault → strategy. The vault holds debt in this strategy. | Yes — always set it to the % share. |
deposits-into | Strategy → underlying protocol. The strategy parks USDC into this venue. | Yes — optional but useful (e.g. "USDC → aUSDC"). |
Mint authority — red dashed lines, highest-trust signal:
kind | Meaning | Label renders on page? |
|---|---|---|
mints | Account/contract holds privileged authority to create new supply of the target token. Direction: minter → token. Pair the minter with a node (typically infra for protocol contracts, governance if a multisig holds the mint role directly). One mints edge per role-holder per token. The absence of mints edges in a graph is itself meaningful — it means mint is permissionless (e.g. open ERC-4626) or gated only by collateral deposit. | No (documentation-only). Use the label to record the role name (e.g. RECEIPT_TOKEN_MINTER, MINTER_ROLE). |
Role / control — amber dashed lines:
kind | Meaning | Label renders on page? |
|---|---|---|
holds-role | An account holds a specific privileged role on the target. | No (documentation-only). Still write the role name in YAML — it helps reviewers reading the file. |
controls | One contract administers another (e.g. timelock → access-control root). | No (documentation-only). |
manages | A registry/factory manages the target contract. | No (documentation-only). |
Governance signaling — violet dotted lines:
kind | Meaning | Label renders on page? |
|---|---|---|
proposes-on | Multisig → timelock (PROPOSER role). | No (documentation-only). |
cancels-on | Multisig → timelock (CANCELLER only, no proposer). | No (documentation-only). |
Incidental wiring — thin gray lines:
kind | Meaning | Label renders on page? |
|---|---|---|
routes-through | A → B, where B is a hop in the flow (PSM, exchanger, hook). | No (documentation-only). |
routes-fees-to | Vault → accountant → fee recipient. | No (documentation-only). |
deploys | Factory → deployed contract. | No (documentation-only). |
Heads-up on labels: only
allocates-toanddeposits-intorender theirlabelon the canvas. For every other kind, the label is captured in the YAML for the reviewer who reads the file — but it won't appear on the rendered graph. Use labels generously in YAML (they document intent), but don't expect them on screen for non-flow kinds.
allocates-to, deposits-into, and routes-through form the flow set. Three behaviors depend on it:
The corollary: don't use manages or routes-through interchangeably. routes-through participates in flow; manages doesn't.
Most reports have 20–40 contracts; a readable graph has 15–30 nodes. The rules below say which to keep and which to drop.
siUSD + iUSD + the locking position. For yvUSDC, just the vault itself.InfiniFiCore, Yearn RoleManager).address (e.g. "Spark Lend USDC Market" in yvUSDC).activation = 0). Mention them in the report; don't draw them.When two contracts function as a single dependency, represent them as one node with a note. Examples:
RWA Escrow Counterparty node with note: "EOA receiver + rate manager".routes-through to the destination, not two routes-through edges through the intermediaries (unless either intermediary is itself a risk surface worth showing).ids, address from the report, label kept short (≤40 chars including any percentage suffix).% label.npm run dev
(Astro 6 needs Node ≥ 22.12. If nvm defaults to an older version, prefix the command with the right PATH.)http://localhost:4321/graph/<slug>/. Confirm:
% labels are visible on the vault → strategy edges.http://localhost:4321/report/<slug>/. Confirm the "View dependency graph →" link appears next to the GitHub link.npm run build — confirms the validator (getGraphBySlug in src/lib/graph.ts) accepts the file. The build will fail with a clear error if any edge endpoint doesn't match a node id or any node uses an unknown category.reports/graph/yearn-yvusdc.yaml — single-vault, single-token, hierarchical governance. The cleanest starting point when copying.reports/graph/infinifi.yaml — multi-token (siUSD / iUSD / liUSD), 9-strategy fan-out, dual timelock, includes an offchain EOA counterparty node. Reference this when the protocol has more than one user-facing token or a long farm list.When a node's address matches a non-dependency node in another graph (i.e. that contract is the vault / strategy / governance / infra of another graph), three things happen automatically at build time. No new YAML fields are needed — matching is purely address-based, computed in getGraphIndex() in src/lib/graph.ts.
scoreColor() from src/lib/colors.ts). Low-risk dependencies show light green; high-risk would show orange/red. A reviewer reading the host graph sees risk at a glance without leaving the page.Final Score and tier ("2.4 · Low") sits next to the truncated address./graph/<linked-slug>/ instead of opening the block explorer. A tiny ↗ icon in the corner keeps the explorer reachable for that specific case.allocates-to → deposits-into → routes-through) are pulled into the host graph at build time. They appear at ~78 % opacity to mark the boundary, and they keep their original categories. Their IDs are namespaced (<linked-slug>::<original-id>) so they never collide with native IDs.Example. InfiniFi's dep-stcusd node and Cap's stcUSD node both carry 0x88887bE…D8888. On the InfiniFi page:
/graph/cap-stcusd/.If your graph references protocol X, and protocol X's graph references protocol Y, only X's downstream is inlined — Y's is not. This is intentional; recursive expansion would make every graph balloon to the sum of all linked graphs. Visit /graph/X/ if you need to drill further.
allocates-to / deposits-into / routes-through) you draw are what shows up inlined in those graphs. Keep your flow chain clean and complete — governance edges won't make it across, but a missing deposits-into will leave a dependency invisible.Omit address from the node. Without an address the matcher can't fire — the card behaves as a plain leaf. Useful when you want a dependency to open Etherscan instead of navigating away (rare).
Hovering any card walks the backward money-flow chain from that node — recursively, following only flow kinds (allocates-to, deposits-into, routes-through) — and highlights every edge and ancestor card in blue. Governance edges (holds-role, controls, manages, proposes-on, cancels-on) and incidental edges (routes-fees-to, deploys) are not traversed.
Example on InfiniFi: hovering the inlined cUSD (Cap Stablecoin) lights up:
cUSD ← stcUSD ← (CapFarm + SwapFarm) ← iUSD ← (siUSD + LockingController)
— the full backward chain. Mint/Redeem controllers connect to iUSD via manages edges, so they stay un-highlighted; that's correct — the chain is for capital movement.
id — build fails with [graph:<slug>] duplicate node id '...'.[graph:<slug>] edge.from '...' does not match any node (or .to). Most common cause: typo in an id or an edge to a contract you decided to skip.[graph:<slug>] node '...' has unknown category '...'. Stick to the 5-category enum.[graph:<slug>] edge '<from>' → '<to>' has unknown kind '<kind>'. The error lists all allowed kinds. Validated against ALLOWED_EDGE_KINDS in src/lib/graph.ts, which is the canonical source of truth for the 10-key enum in the Edge kinds table above.address doesn't match the linked graph's vault address exactly (case-insensitive, but every digit must be right), the cross-link and downstream expansion just don't happen — no build error, no warning. When in doubt, copy the address from the source graph or the report's contract-addresses table verbatim.manages or holds-role edge that should have been allocates-to will still render, but it won't participate in the hover chain or in cross-graph downstream expansion. Use flow kinds for anything that represents capital movement.allocates-to and deposits-into. Labels on other kinds are documentation-only (visible in YAML, not on canvas) — fine to include for reviewer context, but don't expect them on screen.infra (internal machinery) or dependency (external). Don't add a new category without updating src/pages/graph/[slug].astro too.