vyper-specific
Skill36 starsChanged 5 months agoMITView on GitHub
Detect Vyper-specific bug classes — compiler-version reentrancy bugs, raw_call return-value handling, send/raw_call gas defaults, immutables vs constants, default-bytes scope, msg.sender-based auth corner cases. Activate on any `.vy` file or `pragma version` directive.
In this repository44 other files it gives its agents.
- access-controlSkill
- approval-issuesSkill
- caching-and-incrementalSkill
- centralization-riskSkill
- confidence-scoringSkill
- cosmwasmSkill
- cross-chain-messagingSkill
- cross-contract-stateSkill
- delegatecall-risksSkill
- diamond-eip2535Skill
- dos-vectorsSkill
- erc1271-contract-signaturesSkill
- erc4337-account-abstractionSkill
- erc4626-inflationSkill
- false-positive-feedback-loopSkill
- fee-on-transferSkill
- flash-loan-attacksSkill
- initializationSkill
- inline-assemblySkill
- integer-issuesSkill
- intents-erc7683Skill
- known-good-comparisonSkill
- liquidation-cascadeSkill
- mev-frontrunningSkill
- mev-pbsSkill
- multi-pass-self-critiqueSkill
- oracle-manipulationSkill
- oracle-redundancySkill
- permit2-patternsSkill
- pragma-and-addressesSkill
- progress-and-streamingSkill
- reentrancySkill
- restaking-eigenlayerSkill
- selfdestruct-eip6780Skill
- signature-malleabilitySkill
- signature-replaySkill
- solana-anchorSkill
- storage-layoutSkill
- stylus-rustSkill
- token-compatibilitySkill
- tx-context-misuseSkill
- unchecked-callsSkill
- ve-lock-governanceSkill
- zk-verifier-bugsSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 0 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 37
Default revert_on_failure=True will revert the calling tx on a revert, but the *return data* is silently dropped.
- Very specific: line 47
Use raw_call(addr, b"", value=amount) with explicit gas bounds.
- Very specific: line 98
Use raw_call with explicit max_outsize + check return.
- Very specific: line 100
Use OZ ReentrancyGuard-equivalent only after verifying the compiler version.
- Very specific: line 116
When analyzing Vyper contracts compiled with v0.4+, the @nonreentrant decorator uses a mutex storage slot.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Vyper-specific detection
Why a separate skill
Vyper has different defaults than Solidity. Some patterns that are safe in Solidity are unsafe in Vyper, and vice versa. Vyper has also had compiler-level reentrancy bugs (most famously the 2023 Curve incident). Audit Vyper with Vyper-aware eyes.
When this applies
- Any
.vyfile - Any
# @versionpragma directive - Any contract using
raw_call,send,selfdestruct,create_forwarder_to - LP tokens, AMM pools written in Vyper (Curve and forks)
Detection patterns
Compiler-version reentrancy bug (CRITICAL)
Vyper 0.2.15 / 0.2.16 / 0.3.0 had a broken @nonreentrant lock — the lock was per-key, but the same key was reused across functions, causing locks to fail to engage in some compositions. Caused the Curve / Vyper exploit (July 2023, ~$73M).
Action: any contract pinned to # @version 0.2.15, 0.2.16, or 0.3.0 — treat reentrancy guards as broken. Recommend upgrade to ≥ 0.3.7 (or 0.3.10+ for ongoing support).
# @version 0.2.15 # ← FLAG: known-broken nonreentrantraw_call ignores return data unless max_outsize set (HIGH)
raw_call(target, b"...") # ← return data ignored entirelyDefault revert_on_failure=True will revert the calling tx on a revert, but the return data is silently dropped. If you need to read the return:
ok: bool = raw_call(target, b"...", max_outsize=32, revert_on_failure=False)send forwards 2300 gas (HIGH on L2s)
Same problem as Solidity transfer. Smart-wallet recipients can't receive. On L2s with different base costs (Berachain, etc.), the 2300 gas bound is unreliable.
Use raw_call(addr, b"", value=amount) with explicit gas bounds.
default_value= on storage (MEDIUM)
HashMap[address, uint256] defaults to 0 for unset keys. Vyper devs sometimes assume "exists vs not-exists" semantics that don't apply. Use a paired bool flag if existence matters.
selfdestruct semantics (HIGH on pre-Cancun)
Same EIP-6780 caveats apply ([[selfdestruct-eip6780]]). Vyper code that relies on selfdestruct deleting code is broken post-Cancun on mainnet (March 2024).
create_forwarder_to clones share code (HIGH)
EIP-1167 minimal-proxy clones via create_forwarder_to. Same gotcha as Solidity: per-clone init guard required, or anyone can initialize a fresh clone.
Decimal scaling (MEDIUM-HIGH)
Vyper's decimal type is fixed-point with limited range. Mixing uint256 and decimal for price math invites overflow or precision loss. Most modern Vyper code avoids decimal; if present, audit carefully.
external vs internal and visibility (MEDIUM)
Vyper enforces explicit visibility (@external, @internal, @view, @pure). Functions without visibility are syntax errors — but @external + missing access checks are still a foot-gun (same as Solidity).
msg.sender == self patterns (MEDIUM)
Vyper allows msg.sender == self checks — used to gate "callable only from internal call". Easy to typo msg.sender == self.owner vs == self. Check the intent.
assert vs raise (LOW)
assert and raise both revert. assert <cond> reverts if false; raise "reason" always reverts. Mix-up on devs coming from Solidity. Both are safe; just consistency.
Storage layout — Vyper has no __gap convention (HIGH for upgradeable)
Vyper isn't typically used for upgradeable contracts (no equivalent of OZ Upgradeable plugin). If you find a Vyper proxy implementation, audit storage layout very carefully — reserved slots aren't a Vyper convention.
Severity rubric
| Pattern | Severity |
Vyper 0.2.15/0.2.16/0.3.0 with @nonreentrant | Critical (known-broken) |
raw_call to user-supplied target | High |
send (2300 gas) to dynamic recipient on L2 | High |
selfdestruct for state cleanup post-Cancun | High |
create_forwarder_to without per-clone init guard | High |
| Decimal scaling errors in price math | High |
| Storage layout in Vyper proxy without explicit reservation | High |
default_value semantics misuse | Medium |
assert vs raise inconsistency | Low |
Remediation patterns
- Upgrade to Vyper ≥ 0.3.10 to get fixed
@nonreentrant. - Use
raw_callwith explicitmax_outsize+ check return. - Replace
sendwithraw_call(addr, b"", value=amt)and explicit gas budget. - Use OZ
ReentrancyGuard-equivalent only after verifying the compiler version. - For Curve forks specifically: pin compiler, audit the lock implementation against the Curve patch commits.
False-positive notes
- Vyper test fixtures often use
@version 0.2.xfor legacy compatibility — verify deployment compiler differs. - Curve LP tokens and pools have been re-audited extensively; current Curve deploys use post-fix Vyper.
Related
- [[reentrancy]] — base reentrancy patterns
- [[selfdestruct-eip6780]] — EIP-6780 implications
- [[unchecked-calls]] — raw_call analog of low-level call
Compiler-Specific Notes (v0.4+)
When analyzing Vyper contracts compiled with v0.4+, the @nonreentrant decorator uses
a mutex storage slot. Reentrancy guards that rely on storage checks between external
calls MUST account for Vyper's 0-indexed mutex storage layout (sload(0) vs sload(keccak256)).
Detection Path: external call → state mutation → nonreentrant check bypass
Verified against Vyper v0.4.0 compiler output for CurveStableSwap pattern.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

