Skip to content
Security
Skill

/oracle-analysis

Trigger Pattern ORACLE flag (required) - Inject Into Breadth agents, depth-external, depth-edge-case

From plugin
plamen
276160 skills12 agents4 commands
Install
$ npx -y skills add PlamenTSV/plamen --skill oracle-analysis --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/oracle-analysis

Context preview

The summary Claude sees to decide when to auto-load this skill.

Trigger Pattern ORACLE flag (required) - Inject Into Breadth agents, depth-external, depth-edge-case

SKILL.md

oracle-analysis.SKILL.md
name: "oracle-analysis"
description: "Trigger Pattern ORACLE flag (required) - Inject Into Breadth agents, depth-external, depth-edge-case"

ORACLE_ANALYSIS Skill

> **Trigger Pattern**: ORACLE flag (required) > **Inject Into**: Breadth agents, depth-external, depth-edge-case > **Purpose**: Analyze all oracle integrations in Aptos Move protocols for staleness, decimal errors, zero/negative prices, confidence intervals, multi-oracle aggregation, and failure modes

For every oracle the protocol consumes:

**STEP PRIORITY**: Steps 6 (Failure Modes) and 5c (Deviation Reference) are where HIGH/CRITICAL severity findings most commonly hide. Do NOT rush these steps. If constrained, skip conditional sections (4a-4d, 5a) before skipping 5c or 6.

1. Oracle Inventory

Enumerate ALL oracle data sources the protocol reads:

| Oracle | Type | Module Path | Functions Called | Consumers (protocol functions) | Update Frequency | Freshness Guarantee | |--------|------|-------------|-----------------|-------------------------------|-----------------|---------------------| | {name} | Pyth / Switchboard / Custom / On-chain TWAP | {module::path} | {get_price / get_result / etc.} | {list all} | {expected} | {documented or UNKNOWN} |

**Aptos oracle landscape**:

  • **Pyth Network**: `pyth::price_feed` module, returns `Price { price: I64, conf: u64, expo: I64, publish_time: u64 }`
  • **Switchboard**: `switchboard::aggregator` module, returns aggregator results with `mantissa` and `scale`
  • **Custom price feeds**: Protocol-specific oracles using `Table` or `SmartTable` for price storage
  • **On-chain TWAP**: DEX-derived time-weighted prices (Thala, LiquidSwap, Pontem)

**For each oracle**: What decision does the protocol make based on this data? (pricing, liquidation threshold, reward rate, rebase trigger, collateral valuation, etc.)

**Hardcoded stablecoin pricing**: Does the protocol skip oracle lookup for any asset and hardcode its price (e.g., USDC = 1e8)? All assets require dynamic oracle pricing — stablecoins depeg.

2. Staleness Analysis

For each oracle identified in Step 1:

2a. Staleness Checks Present?

| Oracle | Timestamp Checked? | Max Staleness Enforced? | Staleness Threshold | Appropriate? | |--------|-------------------|------------------------|--------------------:|-------------| | {name} | YES/NO | YES/NO | {seconds or NONE} | {analysis} |

**Pyth-specific**: Is `price.publish_time` compared against `timestamp::now_seconds()`? What max age is enforced? **Switchboard-specific**: Is the aggregator's `latest_confirmed_round.round_open_timestamp` validated?

**Chained feed deviation**: If derived prices require multiple feeds (e.g., token_A/USD via token_A/APT + APT/USD), sum individual deviation thresholds to compute total worst-case deviation. If total exceeds LTV buffer → FINDING.

**If NO staleness check**: What happens when the oracle returns stale data?

  • [ ] Protocol uses stale price for liquidations -- unfair liquidations
  • [ ] Protocol uses stale price for minting -- mispriced assets
  • [ ] Protocol uses stale price for swaps -- arbitrage opportunity
  • [ ] Protocol uses stale rate for rewards -- incorrect distribution

2b. Stale Data Impact Trace

For each consumer function, trace the impact of receiving data that is {freshness_guarantee x 2} old:

| Consumer Function | Data Used | If Stale By {X}: Impact | Severity | |-------------------|-----------|------------------------|----------| | {function} | {price/rate} | {specific impact} | {H/M/L} |

2c. Pyth-Specific Checks

| Check | Code Reference | Status | |-------|---------------|--------| | `get_price()` or `get_price_no_older_than()` used? | {location} | {which} | | `price.publish_time` freshness validated? | {location} | YES/NO | | `price.price` (I64) sign checked (> 0)? | {location} | YES/NO | | `price.conf` confidence interval checked? | {location} | YES/NO | | `price.expo` (negative exponent) handled correctly? | {location} | YES/NO | | Price feed ID hardcoded or configurable? | {location} | {which} |

2d. Switchboard-Specific Checks

| Check | Code Reference | Status | |-------|---------------|--------| | Aggregator authority validated? | {location} | YES/NO | | Result staleness checked? | {location} | YES/NO | | Min/max response thresholds enforced? | {location} | YES/NO | | Aggregator config (min oracle results, variance threshold) appropriate? | {location} | YES/NO |

3. Decimal Normalization Audit

For each oracle data flow:

| Oracle | Oracle Decimals/Exponent | Consumer Expects | Normalization Applied? | Correct? | |--------|------------------------|-----------------|----------------------|----------| | {name} | {expo or scale} | {expected by math} | YES/NO | {analysis} |

**Pyth decimal handling**: Pyth uses `expo` field (typically negative, e.g., `expo = -8` means 8 decimal places). The actual price = `price.price * 10^expo`. Common errors:

  • Treating `expo` as positive when it is negative
  • Not converting I64 exponent to unsigned for power calculation
  • Mixing Pyth's expo-based decimals with token decimals (Aptos Coin typically uses 8 decimals, but FungibleAsset varies)

**Switchboard decimal handling**: Uses `mantissa` and `scale` (or `decimals`). Actual value = `mantissa * 10^(-scale)`.

**MANDATORY GREP**: Search all oracle consumer files for hardcoded decimal constants: `100000000`, `1e8`, `10_000_000`, `DECIMAL`, `PRECISION`. For each hit: (1) Is this a decimal normalization constant? (2) Does it match the ACTUAL oracle's decimal format? (3) If the oracle feed changes or is swapped, does this constant break?

**Decimal chain trace**: For each arithmetic operation using oracle data, trace the full decimal chain: `oracle_output_decimals` -> `normalization_step` -> `consumer_expected_decimals`. If any step uses a hardcoded constant rather than reading decimals dynamically -> FINDING.

**Common decimal mismatches on Aptos**:

  • Pyth USD feeds: `expo = -8` (8 decimals), but protocol assumes
Read more
Ships withplamen

Autonomous Web3 security auditor for Claude Code and OpenAI Codex CLI. Orchestrates 18-100 AI agents across 40+ phases to produce audit reports with verified PoC exploits — for smart contracts and L1 node-client infrastructure.

Get the whole plugin