feat: add vyper selector detection via symbolic execution#684
Closed
Jon-Becker wants to merge 3 commits intomainfrom
Closed
feat: add vyper selector detection via symbolic execution#684Jon-Becker wants to merge 3 commits intomainfrom
Jon-Becker wants to merge 3 commits intomainfrom
Conversation
Implements Vyper-specific selector detection that traces calldata flow through the dispatcher using symbolic execution. Converts selectors.rs to a directory module and adds vyper.rs with: - Calldata flow tracking through CALLDATALOAD + SHR/DIV operations - Dense/sparse selector section detection via EQ comparisons - Hash bucket dispatch detection via MOD/AND operations with forking - Binary search dispatch support via GT/LT branch forking - Fallback from Solidity to Vyper detection when few selectors found - Enhanced resolve_entry_point to support Vyper's msg.data[0x00] format Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests 5 live Vyper contracts on Ethereum mainnet covering: - Dense selector dispatch (Curve 3Pool Zap) - Dense selector section pattern (Curve Vyper 2) - Sparse selector section pattern (Curve Vyper 1) - Hash bucket dispatch (Curve General) - Different Vyper version (Lido Curve Pool) Plus a regression test for Solidity (WETH). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove DIV, GT, LT, SHR opcode constants that were imported but not directly referenced in the vyper selector detection code. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| let has_calldata = instruction | ||
| .input_operations | ||
| .iter() | ||
| .any(|op| involves_calldata_wrapped(op)); |
Contributor
There was a problem hiding this comment.
warning: redundant closure
--> crates/vm/src/ext/selectors/vyper.rs:141:22
|
141 | .any(|op| involves_calldata_wrapped(op));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `involves_calldata_wrapped`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.91.0/index.html#redundant_closure
= note: `#[warn(clippy::redundant_closure)]` on by default
| // Pattern 3: Check if the condition solidifies to something with msg.data and == | ||
| // This catches cases where the WrappedOpcode tree doesn't exactly match the above patterns | ||
| let solidified = condition.solidify(); | ||
| if solidified.contains("msg.data") { |
Contributor
There was a problem hiding this comment.
warning: this `if` statement can be collapsed
--> crates/vm/src/ext/selectors/vyper.rs:204:5
|
204 | / if solidified.contains("msg.data") {
205 | | if solidified.contains("==") || solidified.contains("^ ") {
206 | | return extract_selector_from_solidified(&solidified);
207 | | }
208 | | }
| |_____^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.91.0/index.html#collapsible_if
= note: `#[warn(clippy::collapsible_if)]` on by default
help: collapse nested if block
|
204 ~ if solidified.contains("msg.data")
205 ~ && (solidified.contains("==") || solidified.contains("^ ")) {
206 | return extract_selector_from_solidified(&solidified);
207 ~ }
|
|
|
||
| let hex_len = hex_end - hex_start; | ||
| // Selectors are 1-8 hex chars (1 to 4 bytes) | ||
| if hex_len >= 1 && hex_len <= 8 { |
Contributor
There was a problem hiding this comment.
warning: manual `RangeInclusive::contains` implementation
--> crates/vm/src/ext/selectors/vyper.rs:323:16
|
323 | if hex_len >= 1 && hex_len <= 8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `(1..=8).contains(&hex_len)`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.91.0/index.html#manual_range_contains
= note: `#[warn(clippy::manual_range_contains)]` on by default
Contributor
❌ Eval Report for b3c1385
|
Contributor
Benchmark for b3c1385Click to view benchmark
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed? Why?
added support for detecting function selectors in vyper-compiled contracts. vyper uses a different dispatching mechanism than solidity (branching logic instead of jump tables), so we needed a symbolic execution approach to extract selectors.
the implementation:
Notes to reviewers
key files:
crates/vm/src/ext/selectors/vyper.rs- new vyper symbolic execution logiccrates/vm/src/ext/selectors/mod.rs- refactored to support both solidity and vypercrates/core/tests/test_vyper_selectors.rs- integration tests with live contractsHow has it been tested?
tested with
cargo runagainst 5 live vyper contracts from etherscan: