Get the FREE Ultimate OpenClaw Setup Guide →

solidity-coding

Scanned
npx machina-cli add skill 0xlayerghost/solidity-agent-kit/solidity-coding --openclaw
Files (1)
SKILL.md
8.5 KB

Solidity Coding Standards

Language Rule

  • Always respond in the same language the user is using. If the user asks in Chinese, respond in Chinese. If in English, respond in English.

Coding Principles

  • Pragma: Use pragma solidity ^0.8.19; — keep consistent across all files in the project
  • Dependencies: OpenZeppelin Contracts 4.9.x, manage imports via remappings.txt
  • Error Handling: Prefer custom errors over require strings — saves gas and is more expressive
    • Define: error InsufficientBalance(uint256 available, uint256 required);
    • Use: if (balance < amount) revert InsufficientBalance(balance, amount);
  • Documentation: All public / external functions must have NatSpec (@notice, @param, @return)
  • Event Indexing: Only add indexed to address type parameters — add comment if indexing other types
  • Special Keywords: immutable / constant / unchecked / assembly must have inline comment explaining why

Naming Conventions

ElementConventionExample
Contract / LibraryPascalCaseMyToken, StakingPool
InterfaceI + PascalCaseIMyToken, IStakingPool
State variable / FunctionlowerCamelCasetotalSupply, claimDividend
Constant / ImmutableUPPER_SNAKE_CASEMAX_SUPPLY, ROUTER_ADDRESS
EventPascalCase (past tense)TokenTransferred, PoolCreated
Custom ErrorPascalCaseInsufficientBalance, Unauthorized
Function parameterprefix _ for setterfunction setFee(uint256 _fee)
  • Forbidden: Pinyin names, single-letter variables (except i/j/k in loops), excessive abbreviations

Code Organization Rules

SituationRule
Cross-contract constantsPlace in src/common/Const.sol
Interface definitionsPlace in src/interfaces/I<Name>.sol, separate from implementation
Simple on-chain queriesUse Foundry cast CLI (call / send)
Complex multi-step operationsUse Foundry script (*.s.sol)
Import styleUse named imports: import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

Project Directory Structure

src/              — Contract source code
  interfaces/     — Interface definitions (I*.sol)
  common/         — Shared constants, types, errors (Const.sol, Types.sol)
test/             — Test files (*.t.sol)
script/           — Deployment & interaction scripts (*.s.sol)
config/           — Network config, parameters (*.json)
deployments/      — Deployment records (latest.env)
docs/             — Documentation, changelogs
lib/              — Dependencies (managed by Foundry)

Configuration Management

  • config/*.json — network RPC URLs, contract addresses, business parameters
  • deployments/latest.env — latest deployed contract addresses, must update after each deployment
  • foundry.toml — compiler version, optimizer settings, remappings
  • Important config changes must be documented in the PR description

OpenZeppelin Library Selection Standards

When writing Solidity contracts, prioritize using battle-tested OpenZeppelin libraries over custom implementations. Select the appropriate library based on the scenario:

Access Control

ScenarioLibraryImport Path
Single owner managementOwnable@openzeppelin/contracts/access/Ownable.sol
Owner transfer needs safetyOwnable2Step@openzeppelin/contracts/access/Ownable2Step.sol
Multi-role permission (admin/operator/minter)AccessControl@openzeppelin/contracts/access/AccessControl.sol
Need to enumerate role membersAccessControlEnumerable@openzeppelin/contracts/access/AccessControlEnumerable.sol
Governance with timelock delayTimelockController@openzeppelin/contracts/governance/TimelockController.sol

Rule: Single owner → Ownable2Step; 2+ roles → AccessControl; governance/DAO → TimelockController

Security Protection

ScenarioLibraryUsage
External call / token transferReentrancyGuardAdd nonReentrant modifier
Emergency pause neededPausableAdd whenNotPaused to user-facing functions; keep admin functions unpaused
ERC20 token interactionSafeERC20Use safeTransfer / safeTransferFrom / safeApprove instead of raw calls

Rule: Any contract that transfers tokens or ETH MUST use ReentrancyGuard + SafeERC20

Token Standards

ScenarioLibraryNotes
Fungible tokenERC20Base standard
Token with burn mechanismERC20BurnableAdds burn() and burnFrom()
Token with max supply capERC20CappedEnforces totalSupply <= cap
Gasless approval (EIP-2612)ERC20PermitSaves users approve tx gas
Governance voting tokenERC20VotesSnapshot-based voting power
NFTERC721Base NFT standard
NFT with enumerationERC721EnumerableSupports tokenOfOwnerByIndex queries
Multi-token (FT + NFT mixed)ERC1155Game items, batch operations

Utility Libraries

ScenarioLibraryUsage
Whitelist / airdrop verificationMerkleProofGas-efficient Merkle tree verification
Signature verificationECDSA + EIP712Off-chain sign + on-chain verify
Auto-increment IDsCountersToken ID, order ID generation
Batch function callsMulticallMultiple operations in one tx
Address set / uint setEnumerableSetIterable sets with O(1) add/remove/contains
Revenue sharingPaymentSplitterSplit ETH/token payments by shares
Standardized yield vaultERC4626DeFi vault standard

Contract Upgrade

ScenarioLibraryNotes
Upgradeable contract (gas efficient)UUPSUpgradeableUpgrade logic in implementation contract
Upgradeable contract (admin separated)TransparentUpgradeableProxyUpgrade logic in proxy, higher gas
Initializer (replace constructor)InitializableUse initializer modifier instead of constructor

Rule: New projects prefer UUPSUpgradeable; always use Initializable for upgradeable contracts

Oracle and Off-Chain Services

ScenarioLibraryNotes
Token price dataAggregatorV3InterfaceOnly for tokens with supported oracle data feeds
Verifiable randomness (lottery/NFT)VRFConsumerBaseV2On-chain provably fair random numbers
Automated execution (cron jobs)AutomationCompatibleReplace centralized keepers
Cross-chain messagingCCIPCross-chain token/message transfer

Library Selection Decision Flow

Does contract handle user funds/tokens?
├── YES → Add ReentrancyGuard + SafeERC20
│         Does it need emergency stop?
│         ├── YES → Add Pausable
│         └── NO  → Skip
└── NO  → Skip

How many admin roles needed?
├── 1 role  → Ownable2Step
├── 2+ roles → AccessControl
└── DAO/governance → TimelockController

Does contract need price data?
├── Token has oracle feed → AggregatorV3Interface
├── No oracle feed → Custom TWAP with min-liquidity check
└── No price needed → Skip

Will contract need upgrades?
├── YES → UUPSUpgradeable + Initializable
└── NO  → Standard deployment (immutable)

Anti-Patterns (Do NOT)

  • Do NOT write custom transfer wrappers — use SafeERC20
  • Do NOT write custom access control modifiers — use Ownable / AccessControl
  • Do NOT write custom pause logic — use Pausable
  • Do NOT use SafeMath on Solidity >= 0.8.0 — overflow checks are built-in
  • Do NOT use require(token.transfer(...)) — use token.safeTransfer(...) via SafeERC20
  • Do NOT use tx.origin for auth — use msg.sender with Ownable / AccessControl

Foundry Quick Reference

OperationCommand
Create new projectforge init <project-name>
Install dependencyforge install openzeppelin-contracts
Build contractsforge build
Format codeforge fmt
Update remappingsforge remappings

Source

git clone https://github.com/0xlayerghost/solidity-agent-kit/blob/main/skills/solidity-coding/SKILL.mdView on GitHub

Overview

This skill defines the mandatory baseline for editing or creating Solidity (.sol) files before implementation. It enforces a consistent pragma, naming conventions, project layout, and OpenZeppelin usage, while guiding oracle integration and anti-pattern avoidance. Following it helps teams produce maintainable, gas-efficient contracts.

How This Skill Works

Teams follow a centralized checklist and template patterns defined in SKILL.md: a project-wide pragma ^0.8.19, OpenZeppelin 4.9.x imports via remappings, and custom errors for failure paths. Public APIs must have NatSpec, and events should index only address types unless a clear justification exists. The rules also define code organization, config management, and standard library selection.

When to Use It

  • Starting a new Solidity contract with Foundry or similar tooling
  • Editing or reviewing an existing .sol file for security, gas or consistency
  • Adding or upgrading OpenZeppelin libraries (Ownable, AccessControl, etc)
  • Ensuring project structure and config alignment (src/, test/, script/, foundry.toml, remappings)
  • Integrating oracle data or external data sources into contracts

Quick Start

  1. Step 1: Initialize project with Foundry and set foundry.toml and remappings, matching OpenZeppelin 4.9.x
  2. Step 2: Create a new contract in src/ with pragma solidity ^0.8.19 and a proper src/interfaces/ structure, using named imports
  3. Step 3: Add NatSpec, custom errors, and OpenZeppelin imports; run tests and lint to verify

Best Practices

  • Enforce pragma solidity ^0.8.19; across all files
  • Prefer custom errors (e.g., InsufficientBalance) over require strings
  • Annotate all public/external functions with NatSpec (@notice, @param, @return)
  • Index only address-typed event parameters, with inline comments if indexing other types
  • Use named imports for OpenZeppelin and organize code in src/interfaces, src/common, and test/script folders

Example Use Cases

  • Token contract using Ownable and Ownable2Step for upgrades and safety
  • Role-based access with AccessControl for admin/operator/minter
  • A contract emitting InsufficientBalance(balance, amount) on failure
  • A Foundry script (*.s.sol) performing multi-step deployment and interaction
  • Consistent config and remappings in foundry.toml and config/*.json for network deployments

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers