stylus-rustlisted
Install: claude install-skill iktok90-design/ai-smart-contract-auditor
# Stylus (Rust) detection
## When this applies
- Any `.rs` file importing `stylus_sdk` (`use stylus_sdk::{...}`)
- Macros `#[entrypoint]`, `#[storage]`, `sol_storage!`, `#[public]`, `#[payable]`
- Host-IO calls: `evm::`, `msg::`, `block::`, `contract::`, `call::` (`Call::new`, `transfer_eth`, `RawCall`)
- Stylus types `StorageU256`, `StorageMap`, `StorageVec`, `alloy_primitives::U256`/`Address`
- A `Cargo.toml` declaring `stylus-sdk` with `crate-type = ["lib", "cdylib"]`
Stylus runs the SAME EVM state and shares the SAME external-call surface as Solidity. Rust safety does NOT remove EVM-level footguns — it adds new ones (panics, wrapping arithmetic, aliasing).
## Detection patterns
### Storage aliasing / stale local copy of EVM state (HIGH)
```rust
let mut bal = self.balances.get(from); // ← copies value out of storage
do_external_call(); // callee may mutate self.balances
self.balances.insert(from, bal - amount); // ← writes back STALE value
```
**Signal:** a `.get()` cached in a local, an intervening call/host-IO, then a `.set()`/`.insert()` of the stale local. Stylus storage reads are snapshots, not live references — re-read after any external call.
### Reentrancy via external call before state finalization (CRITICAL)
```rust
pub fn withdraw(&mut self) -> Result<(), Vec<u8>> {
let amt = self.balance.get(msg::sender());
call::transfer_eth(msg::sender(), amt)?; // ← control leaves contract
self.balance.setter(msg::sender