Solidity & Smart Contracts
Write secure, gas-efficient Solidity contracts using OpenZeppelin, Hardhat testing, and common patterns like Ownable, ERC-20, and ERC-721.
Solidity is the primary language for Ethereum smart contracts. Contracts are immutable once deployed and handle real financial value-security and gas efficiency are non-negotiable. Every vulnerability is a potential exploit.
Security first. Use audited OpenZeppelin contracts over rolling your own. Test extensively with Hardhat before deploying. Understand gas costs. Follow checks-effects-interactions pattern religiously to prevent reentrancy.
Workflow
- Set up Hardhat development environmentHardhat provides local Ethereum node, testing with ethers.js/chai, and deployment scripts all in one.
- Write contracts with OpenZeppelin base classesOpenZeppelin contracts are battle-tested, audited, and community-reviewed-building on them eliminates reinventing proven patterns.
- Apply checks-effects-interactions patternReentrancy attacks drain contracts by re-entering before state updates. The DAO hack ($60M) exploited this.
- Optimize for gasGas costs real money. Inefficient contracts can become unusable when gas prices spike.
- Test thoroughly with Hardhat and ChaiBugs in deployed contracts can't be patched-they can only be mitigated. Comprehensive tests are the last line of defense before audit.
Output Format
Solidity contracts with OpenZeppelin base, Hardhat test suite at 100% branch coverage, gas benchmarks, deployment scripts, Slither report.
Examples
ERC-20 token: `contract MyToken is ERC20, Ownable { constructor() ERC20("MyToken", "MTK") Ownable(msg.sender) { _mint(msg.sender, 1000000 * 10**18); } function mint(address to, uint256 amount) external onlyOwner { _mint(to, amount); } }`Checks-effects-interactions: `function withdraw(uint256 amount) external nonReentrant { require(balances[msg.sender] >= amount, "Insufficient"); balances[msg.sender] -= amount; (bool ok, ) = msg.sender.call{value: amount}(""); require(ok, "Transfer failed"); }`Gas optimization: pack variables: `uint128 price; uint128 quantity;` → one storage slot vs two separate uint256sEdge Cases & Gotchas
- Integer overflow: Solidity 0.8+ throws on overflow by default; use unchecked{} only when you've mathematically proven no overflow is possible
- Block.timestamp manipulation: miners can adjust by ~15 seconds; don't use it for precise timing or as a randomness source
- Proxy patterns for upgradeable contracts: use OpenZeppelin TransparentUpgradeableProxy; avoid storage collision between proxy and implementation
When to Break These Rules
- For non-financial contracts (NFT metadata, governance voting), audit requirements can be relaxed but testing and event emission remain essential.
Reference Files
OpenZeppelin Contracts: https://docs.openzeppelin.com/contracts/Hardhat: https://hardhat.org/docsSWC Registry (vulnerabilities): https://swcregistry.io/Slither static analyzer: https://github.com/crytic/slither