Skip to main content
solidity-guide Solidity/Ethereum guardrails, patterns, and best practices for AI-assisted development.
Use when working with Solidity files (.sol), or when the user mentions Solidity/Ethereum/smart contracts.
Provides gas optimization patterns, reentrancy prevention, upgradeable contract guidelines,
and testing standards specific to this project's coding standards.
跳到安装 Skills Marketplace 发现并探索由社区构建的 Agent Skills
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/ar4mirez/samuel --skill solidity-guide命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
下载 Zip 下载中... name solidity-guide description Solidity/Ethereum guardrails, patterns, and best practices for AI-assisted development.
Use when working with Solidity files (.sol), or when the user mentions Solidity/Ethereum/smart contracts.
Provides gas optimization patterns, reentrancy prevention, upgradeable contract guidelines,
and testing standards specific to this project's coding standards.
license MIT metadata {"author":"samuel","version":"1.0","category":"language","language":"solidity","extensions":".sol"}
Solidity Guide
Applies to: Solidity 0.8.20+, Ethereum, EVM-compatible chains, DeFi, NFTs
Core Principles
Security First : Every function is a potential attack surface. Assume adversarial callers.
Gas Efficiency : On-chain computation is expensive. Optimize storage access and minimize state changes.
Explicit Over Implicit : Use explicit visibility, explicit types, and named return values.
Immutability by Default : Prefer immutable and constant for values that do not change after deployment.
Standards Compliance : Use OpenZeppelin for ERC standards. Do not roll your own token logic.
Guardrails
Compiler Version
ALWAYS specify pragma version range: pragma solidity ^0.8.20;
Do NOT use floating pragmas in production (e.g., >=0.8.0). Pin to a minor range.
Enable the optimizer with at least 200 runs for production deployments.
Security
NEVER use tx.origin for authorization. Use msg.sender.
NEVER use selfdestruct in new contracts (deprecated in Dencun).
ALWAYS use ReentrancyGuard from OpenZeppelin for functions that make external calls.
ALWAYS validate external inputs: check zero addresses, bounds, and array lengths.
Use SafeERC20 for token transfers (handles non-standard return values).
Emit events for every state-changing operation (required for off-chain indexing).
Gas Optimization
Pack storage variables: group uint128, uint64, bool into single 256-bit slots.
Use calldata instead of memory for read-only external function parameters.
Use custom errors instead of require strings (saves ~50 bytes per error site).
Cache storage reads in local variables when accessed more than once.
Use unchecked blocks for arithmetic that provably cannot overflow.
Prefer mapping over array for large datasets (O(1) vs O(n) lookups).
Access Control
Use OpenZeppelin AccessControl or Ownable2Step (not plain Ownable).
Separate admin roles: deployer, upgrader, pauser, minter. No single god key.
Consider a timelock for sensitive admin operations (TimelockController).
Upgradability
Use UUPS proxy pattern (preferred) or Transparent proxy when upgradability is required.
NEVER change storage layout ordering in upgraded implementations.
Use @openzeppelin/contracts-upgradeable with initializer instead of constructors.
ALWAYS include a storage gap: uint256[50] private __gap;
Disable initializers in the constructor: _disableInitializers();
Key Patterns
Checks-Effects-Interactions (CEI) Prevents reentrancy by ordering operations: validate, update state, then call externally.
function withdraw(uint256 amount) external nonReentrant {
// 1. CHECKS
if (amount == 0) revert ZeroAmount();
if (balances[msg.sender] < amount) revert InsufficientBalance();
// 2. EFFECTS: update state BEFORE external calls
balances[msg.sender] -= amount;
// 3. INTERACTIONS: external calls last
(bool success, ) = msg.sender.call{value: amount}("");
if (!success) revert TransferFailed();
emit Withdrawn(msg.sender, amount);
}
Pull Over Push Let users withdraw funds instead of pushing payments to them.
mapping(address => uint256) public pendingWithdrawals;
function claimPayment() external nonReentrant {
uint256 amount = pendingWithdrawals[msg.sender];
if (amount == 0) revert NothingToClaim();
pendingWithdrawals[msg.sender] = 0;
(bool success, ) = msg.sender.call{value: amount}("");
if (!success) revert TransferFailed();
emit PaymentClaimed(msg.sender, amount);
}
Guard Checks with Custom Errors Custom errors are cheaper than require strings and support typed parameters.
error Unauthorized(address caller);
error InsufficientBalance(uint256 requested, uint256 available);
error ZeroAddress();
function transfer(address to, uint256 amount) external {
if (to == address(0)) revert ZeroAddress();
if (balances[msg.sender] < amount) {
revert InsufficientBalance(amount, balances[msg.sender]);
}
balances[msg.sender] -= amount;
balances[to] += amount;
emit Transfer(msg.sender, to, amount);
}
UUPS Proxy Pattern import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
contract MyProtocol is UUPSUpgradeable, OwnableUpgradeable {
uint256 public protocolFee;
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() { _disableInitializers(); }
function initialize(address owner, uint256 fee) external initializer {
__Ownable_init(owner);
__UUPSUpgradeable_init();
protocolFee = fee;
}
function _authorizeUpgrade(address) internal override onlyOwner {}
uint256[49] private __gap;
}
Security Checklist
Reentrancy : Apply nonReentrant to external-call functions. Follow CEI even with the guard. Watch for cross-function reentrancy on shared state.
Integer Safety : Solidity 0.8+ has overflow checks. Use unchecked only when provably safe.
Front-Running : Use commit-reveal for auctions/voting. Add deadline params to swaps. Use block.timestamp, not block.number.
Access Control : Never rely on tx.origin. Use Pausable for emergency stops.
Testing
Foundry (forge) -- Recommended // test/Vault.t.sol
pragma solidity ^0.8.20;
import {Test} from "forge-std/Test.sol";
import {Vault} from "../src/Vault.sol";
contract VaultTest is Test {
Vault public vault;
address public alice = makeAddr("alice");
function setUp() public {
vault = new Vault();
vm.deal(alice, 10 ether);
}
function test_deposit_updates_balance() public {
vm.prank(alice);
vault.deposit{value: 1 ether}();
assertEq(vault.balances(alice), 1 ether);
}
function test_withdraw_reverts_on_insufficient_balance() public {
vm.prank(alice);
vm.expectRevert(Vault.InsufficientBalance.selector);
vault.withdraw(1 ether);
}
// Fuzz testing: forge generates random inputs automatically
function testFuzz_deposit_and_withdraw(uint96 amount) public {
vm.assume(amount > 0 && amount <= 10 ether);
vm.startPrank(alice);
vault.deposit{value: amount}();
vault.withdraw(amount);
vm.stopPrank();
assertEq(vault.balances(alice), 0);
}
}
Hardhat (alternative) Use npx hardhat test with Chai matchers and ethers.js for JS/TS projects.
Tooling forge build && forge test
forge test -vvvv
forge test --fuzz-runs 10000
forge coverage
forge fmt
forge snapshot
slither .
myth analyze src/Contract.sol
npx hardhat compile && npx hardhat test
Pre-Deployment Checklist
References
External References