agents/skills/evm/token-flow-tracing/SKILL.md
Performs comprehensive token flow analysis by tracing all token entry and exit paths, verifying accounting consistency, detecting unsolicited transfer vectors, and identifying risks such as donation attacks, balance desynchronization, token type confusion, and side-effect-driven state changes.
npx skillsauth add plamentsv/plamen token-flow-tracingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Trigger Pattern:
transfer\|transferFrom\|safeTransfer\|mint\|burn\|balanceOf.*thisInject Into: Lifecycle, External-Env agents
For every token the protocol handles:
Where can tokens enter?
deposit() / stake() functions - standard entry pointstransfer() to contract address (bypasses deposit logic)onERC721Received, onERC1155Received, onERC1155BatchReceivedreceive() / fallback() for native ETHFor each callback handler the protocol IMPLEMENTS (not calls): verify access control (can anyone trigger it?), verify what state it modifies and whether that state is iterated elsewhere.
For each entry point:
balanceOf(address(this)) used directly? → Donation attack vectorRed flags:
balanceOf(address(this)) directlyWhere can tokens leave?
withdraw() / unstake() functionsFor each exit: does the tracked balance decrease BEFORE or AFTER the actual transfer? For each transfer call: can the source address be underfunded at execution time? (funds deployed externally, locked, or lent out → transfer reverts)
For each transfer function: can the sender and recipient be the same address? If YES: does a self-transfer update accounting state (fees credited, rewards claimed, snapshots updated, share ratios changed) without net token movement? Flag as FINDING.
For protocols handling multiple token types:
Check: If function A handles TokenX and function B handles TokenY, can TokenX reach function B's logic? Also: within a single function, if some code paths branch on token type (e.g., input handling), do ALL code paths branch consistently (e.g., refund, fee, return)?
Can tokens be sent to the contract without calling deposit()?
If YES:
If NO:
For EVERY external token type the protocol holds, queries, or receives as side effects - not just the protocol's primary token:
| Token Type | Can Transfer To Protocol? | Changes Protocol Accounting? | Blocks Operations? | Triggers Side Effects? | |------------|--------------------------|-----------------------------|--------------------|----------------------| | {token_a} | YES/NO | YES/NO | YES/NO | YES/NO |
RULE: If ANY token type is transferable to the protocol AND affects state → analyze each consequence:
For each token identified:
| Token | Entry Points | Exit Points | Tracking Var | balanceOf(this) Used? | Unsolicited Possible? | |-------|--------------|-------------|--------------|----------------------|----------------------| | [Name] | deposit, receive | withdraw, claim | totalDeposited | YES/NO | YES/NO |
For protocols with multiple tokens:
For every external call that returns tokens or values:
Common mismatches:
Check: interface.function() returns (TokenA) - verify TokenA is what's actually returned, not TokenB
For every transfer() / transferFrom() call to external contracts:
| Token | On Transfer Side Effect | Impact on Protocol | |-------|------------------------|-------------------| | [Token] | Claims pending rewards | Unexpected balance increase | | [Token] | Updates delegation state | Accounting mismatch | | [Token] | Triggers rebase | Exchange rate affected |
Example: Transferring staking receipt tokens (e.g., stETH, aTokens) may trigger rebases or reward claims as a side effect
For each documented side effect that produces or claims tokens:
| External Call / Event | Side Effect | Token Type Produced | Protocol Handles This Type? | Mismatch? | |-----------------------|-------------|--------------------|-----------------------------|-----------| | {call_or_event} | {side_effect} | {token_type_or_UNKNOWN} | YES/NO | YES/NO |
RULE: If side effect token type != protocol's expected token type → FINDING (stranded tokens of wrong type) RULE: If side effect token type is UNKNOWN → CONTESTED (assume adversarial per Rule 4) RULE: Check BOTH direct calls AND unsolicited transfers for side effect token types
// RED FLAG: Direct balance usage
uint256 rate = token.balanceOf(address(this)) / totalShares;
// BETTER: Tracked balance
uint256 rate = totalPooledTokens / totalShares;
// But check: is totalPooledTokens updated correctly on ALL entry paths?
When this skill identifies an issue:
**ID**: [LC-N] or [EX-N]
**Severity**: [based on fund impact]
**Step Execution**: ✓1,2,3,4,5,6,7,8,9 | ✗(reasons) | ?(uncertain)
**Location**: Contract.sol:LineN
**Title**: [Token type] can enter/exit via [path] without [expected accounting update]
**Description**: [Trace the token flow and where it diverges from expected]
**Impact**: [What breaks: exchange rates, user balances, protocol insolvency]
CRITICAL: You MUST report completion status for ALL sections. Findings with incomplete sections will be flagged for depth review.
| Section | Required | Completed? | Notes | |---------|----------|------------|-------| | 1. Token Entry Points | YES | ✓/✗/? | | | 2. Token State Tracking | YES | ✓/✗/? | | | 3. Token Exit Points | YES | ✓/✗/? | | | 4. Token Type Separation | IF multi-token | ✓/✗(N/A)/? | | | 5. Unsolicited Transfer Analysis | YES | ✓/✗/? | | | 5b. Unsolicited Transfer Matrix (All Types) | YES | ✓/✗/? | MANDATORY - never skip | | 6. Token Flow Checklist | YES | ✓/✗/? | | | 7. Cross-Token Interactions | IF multi-token | ✓/✗(N/A)/? | | | 8. External Call Return Type | YES | ✓/✗/? | MANDATORY - never skip | | 9. Transfer Side Effects | YES | ✓/✗/? | MANDATORY - never skip | | 9d. Side Effect Token Type | YES | ✓/✗/? | MANDATORY - never skip |
After Section 5 (Unsolicited Transfer Analysis):
After Section 8 (External Call Return Type):
STAKING_RECEIPT_TOKENS.md Section 8 for on-transfer side effectsAfter Section 9 (Transfer Side Effects):
For Sections 8 and 9, you MUST produce output even if uncertain:
Section 8 Output (always required):
### 8. External Call Return Type Verification
| External Call | Expected Return | Verified Production Return | Match? |
|--------------|-----------------|---------------------------|--------|
| [call] | [expected] | [verified/UNVERIFIED] | ✓/✗/? |
**If UNVERIFIED**: Finding verdict cannot be REFUTED. Use CONTESTED.
Section 9 Output (always required):
### 9. Transfer Side Effects Analysis
| Token | On Transfer Side Effect | Verified? | Assumed Impact |
|-------|------------------------|-----------|----------------|
| [token] | [effect or UNKNOWN] | YES/NO | [impact trace] |
**Adversarial Default Applied**: [list assumptions made]
development
Prepare Solidity projects for a security audit — test coverage, test quality, NatSpec docs, code hygiene, dependency health, best-practice enforcement, deployment readiness, and project documentation checks. Generates a scored Audit Readiness Report and optionally runs static analysis. Trigger on: "prepare for audit", "audit readiness", "pre-audit check", "audit prep", "NatSpec check", or any request to review a Solidity codebase before a security review.
development
Launch the Plamen deterministic Web3 security audit pipeline
development
Run the Plamen smart-contract audit wizard in Codex
testing
Launch the Plamen deterministic L1 infrastructure audit pipeline