Use when an org role acts as Solidity engineer and must ship gas-efficient, audit-ready EVM contracts: tokens, upgradeable proxies and DeFi on L1 and L2s. Covers checks-effects-interactions, reentrancy guards, OpenZeppelin bases, storage packing and custom errors.
Installs into .claude/skills of the current project.
Are you the author of Solidity Engineer?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/monoes-solidity-engineer)
---
name: solidity-engineer
description: "Use when an org role acts as Solidity engineer and must ship gas-efficient, audit-ready EVM contracts: tokens, upgradeable proxies and DeFi on L1 and L2s. Covers checks-effects-interactions, reentrancy guards, OpenZeppelin bases, storage packing and custom errors."
tags: ["engineering","security","blockchain"]
tools: ["monograph_query","monograph_context","monograph_impact"]
license: Apache-2.0
source: https://github.com/monoes/monomind
---
# Solidity Engineer — Best Practices
## Focus
Writes and ships EVM smart contracts — gas-efficient, security-first, and audit-ready — for token standards, upgradeable proxies, and DeFi protocols across Ethereum and L2 chains.
## Best practices
- Follow checks-effects-interactions on every function that makes an external call; update state before calling out.
- Use `call{value:}("")` with a reentrancy guard instead of `transfer()`/`send()` for ETH transfers.
- Build on OpenZeppelin's audited base contracts rather than reinventing access control, tokens, or proxies.
- Pack struct fields and storage variables to minimize slot usage; cache storage reads in memory inside loops.
- Prefer custom errors over `require` strings — cheaper to deploy and cheaper to revert.
- Mark functions `external` (not `public`) when never called internally; use `immutable`/`constant` for values that never change.
- Emit an event on every state-changing function so off-chain indexers can reconstruct state.
- Plan upgrade paths (UUPS, transparent proxy, or beacon) from day one — never reorder or remove existing storage slots.
## Common pitfalls
- Using `tx.origin` for authorization instead of `msg.sender`.
- Trusting external contract return values or oracle spot prices without staleness/sanity checks.
- Iterating over unbounded on-chain arrays — a DoS vector once the array grows.
- Shipping without a Foundry fuzz/invariant suite, then discovering an edge case in production.
- Leaving `initialize()` unprotected on an upgradeable contract, letting an attacker front-run initialization.
## Tools & techniques
- Foundry for unit, fuzz, and invariant testing; `forge snapshot` for gas regression tracking.
- Slither and Mythril static analysis as a mandatory pre-audit gate — fix or document every finding.
- NatSpec on every public/external function; zero compiler warnings on strict settings.
- Chainlink or TWAP oracles instead of spot AMM reserves for any price-dependent logic.
- CREATE2 for deterministic cross-chain deployment addresses.