/oracle-analysis
Trigger Pattern ORACLE flag (required) - Inject Into Breadth agents, depth-external, depth-edge-case
$ npx -y skills add PlamenTSV/plamen --skill oracle-analysis --agent claude-codeHow 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.mdname: "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
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
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.
Repo: PlamenTSV/plamen
Other skills on plamen.
- /ability-analysis
Trigger Pattern Always (Aptos Move) - foundational security check - Inject Into Breadth agents, depth agents
Open skill - /bit-shift-safety
Trigger Pattern Always (Aptos Move) - Move VM aborts on shift = bit width - Inject Into Breadth agents, depth-edge-case
Open skill - /centralization-risk
Trigger Protocol has privileged roles (admin, operator, governance, resource account owner) - Covers Single points of failure, privilege escalation, external governance dependen...
Open skill - /cross-chain-timing
Trigger Pattern wormhole|layerzero|ccip|bridge|cross_chain|vaa|guardian|emitter|relay|remote_chain|payload|nonce.sequence - Inject Into Breadth agents, depth-external
Open skill - /dependency-audit
Trigger EXTERNAL_LIB flag detected (protocol uses third-party Move dependencies) - Used by Breadth agents, depth-external
Open skill - /economic-design-audit
Trigger Pattern MONETARY_PARAMETER flag (required) - Inject Into Breadth agents (merged via M4 hierarchy)
Open skill

