Agent skill
contract-patterns
Common Solidity design patterns and implementations for secure smart contract development. Use when implementing standard functionality like access control, upgradeability, or token standards.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/development/contract-patterns-ivantorresedge-molcajete-ai
SKILL.md
Contract Patterns Skill
This skill provides battle-tested patterns and examples for common smart contract functionality.
When to Use
Use this skill when:
- Implementing access control mechanisms
- Creating upgradeable contracts
- Building token contracts (ERC20, ERC721, ERC1155)
- Adding pausability to contracts
- Protecting against reentrancy attacks
- Following established security patterns
Pattern Categories
1. Access Control Patterns
See ./patterns/access-control.md for detailed documentation.
Common patterns:
- Ownable - Single owner with privileged access
- AccessControl - Role-based access control (RBAC)
- Multisig - Multiple signatures required for actions
- Timelock - Delayed execution for critical functions
When to use:
- Ownable: Simple contracts with single admin
- AccessControl: Complex permissions with multiple roles
- Multisig: High-value contracts requiring consensus
- Timelock: Governance and critical upgrades
2. Upgradeable Contract Patterns
See ./patterns/upgradeable-contracts.md for detailed documentation.
Common patterns:
- Transparent Proxy - Separate admin and user logic
- UUPS (Universal Upgradeable Proxy Standard) - Upgrade logic in implementation
- Beacon Proxy - Multiple proxies sharing same implementation
- Diamond Pattern (EIP-2535) - Multi-facet proxy for large contracts
When to use:
- Transparent: When admin and user separation is critical
- UUPS: Gas-efficient upgrades, upgrade logic in implementation
- Beacon: Deploying many instances of same logic
- Diamond: Large contracts exceeding size limits
3. Pausable Pattern
See ./patterns/pausable.md for detailed documentation.
Purpose: Emergency stop mechanism to pause contract functionality
When to use:
- Contracts handling user funds
- Contracts that may need emergency stops
- Contracts under active development/monitoring
Key features:
- Pause/unpause functionality
- Restricted to authorized roles
- Graceful degradation of functionality
4. Reentrancy Guard
See ./patterns/reentrancy-guard.md for detailed documentation.
Purpose: Prevent reentrancy attacks in functions that make external calls
When to use:
- Functions that transfer ETH
- Functions that call external contracts
- Functions that modify state after external calls
Implementation:
- Checks-Effects-Interactions pattern
- ReentrancyGuard modifier
- Mutex locks
5. Token Standards
See ./patterns/token-standards.md for detailed documentation.
ERC20 - Fungible tokens
- Standard interface for tokens like USDC, DAI
- Transfer, approve, transferFrom functionality
- See
./examples/ERC20-example.sol
ERC721 - Non-fungible tokens (NFTs)
- Unique tokens with individual ownership
- Metadata support
- See
./examples/ERC721-example.sol
ERC1155 - Multi-token standard
- Batch operations for fungible and non-fungible tokens
- Gas-efficient for multiple token types
- See
./examples/ERC1155-example.sol
Integration with Code Principles
These patterns follow the code-principles from the foundation plugin:
- DRY: Inherit from OpenZeppelin contracts instead of reimplementing
- SOLID: Single responsibility for each pattern/module
- KISS: Use simplest pattern that meets requirements
- Security First: Battle-tested implementations over custom code
Note: Solidity-specific security concerns take precedence over general software principles.
OpenZeppelin Contracts
Most patterns are best implemented using OpenZeppelin contracts:
# Install OpenZeppelin
forge install OpenZeppelin/openzeppelin-contracts
# or
npm install @openzeppelin/contracts
Available contracts:
@openzeppelin/contracts/access/Ownable.sol@openzeppelin/contracts/access/AccessControl.sol@openzeppelin/contracts/security/Pausable.sol@openzeppelin/contracts/security/ReentrancyGuard.sol@openzeppelin/contracts/token/ERC20/ERC20.sol@openzeppelin/contracts/token/ERC721/ERC721.sol@openzeppelin/contracts/token/ERC1155/ERC1155.sol@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol
Pattern Selection Guide
| Need | Pattern | Complexity | Gas Cost | Security |
|---|---|---|---|---|
| Single admin | Ownable | Low | Low | Medium |
| Multiple roles | AccessControl | Medium | Medium | High |
| Emergency stop | Pausable | Low | Low | High |
| Prevent reentrancy | ReentrancyGuard | Low | Low | Critical |
| Fungible tokens | ERC20 | Low | Low | High |
| NFTs | ERC721 | Medium | Medium | High |
| Multi-token | ERC1155 | High | Low | High |
| Simple upgrades | UUPS | Medium | Low | High |
| Admin separation | Transparent Proxy | Medium | Medium | High |
| Multiple instances | Beacon Proxy | High | Low | High |
| Large contracts | Diamond | Very High | Medium | Medium |
Best Practices
- Prefer OpenZeppelin - Use audited implementations over custom code
- Combine patterns carefully - Test interactions between patterns
- Follow initialization patterns - Use proper constructor/initializer for upgradeable contracts
- Test thoroughly - Each pattern has unique security considerations
- Document deviations - If customizing standard patterns, document why
- Keep it simple - Use simplest pattern that meets requirements
- Security over gas optimization - Prioritize security when patterns conflict
Common Combinations
Pausable + AccessControl
contract MyContract is Pausable, AccessControl {
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
function pause() public onlyRole(PAUSER_ROLE) {
_pause();
}
function unpause() public onlyRole(PAUSER_ROLE) {
_unpause();
}
function criticalFunction() public whenNotPaused {
// Function logic
}
}
ERC20 + Ownable + Pausable
contract MyToken is ERC20, Ownable, Pausable {
constructor() ERC20("MyToken", "MTK") Ownable(msg.sender) {}
function pause() public onlyOwner {
_pause();
}
function _update(address from, address to, uint256 value)
internal
override
whenNotPaused
{
super._update(from, to, value);
}
}
UUPS + AccessControl + ReentrancyGuard
contract MyUpgradeableContract is
UUPSUpgradeable,
AccessControlUpgradeable,
ReentrancyGuardUpgradeable
{
bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");
function _authorizeUpgrade(address newImplementation)
internal
override
onlyRole(UPGRADER_ROLE)
{}
}
Anti-Patterns to Avoid
- Custom access control - Use OpenZeppelin instead
- Manual reentrancy protection - Use ReentrancyGuard
- Incorrect upgrade patterns - Follow OpenZeppelin upgrade guides
- Mixing storage layouts - Be careful with inheritance order
- Skipping initialization - Always initialize upgradeable contracts
- Ignoring token standards - Follow ERC specifications exactly
Pattern Files
This skill provides the following pattern documentation:
./patterns/upgradeable-contracts.md- Proxy patterns./patterns/access-control.md- Permission patterns./patterns/pausable.md- Emergency stop pattern./patterns/reentrancy-guard.md- Reentrancy protection./patterns/token-standards.md- ERC20/721/1155 standards
Example Contracts
This skill provides the following examples:
./examples/ERC20-example.sol- Fungible token implementation./examples/ERC721-example.sol- NFT implementation./examples/ERC1155-example.sol- Multi-token implementation./examples/upgradeable-example.sol- UUPS upgradeable contract
Quick Reference
// Access Control
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
// Security
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
// Tokens
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
// Upgradeability
import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
Remember: Always prefer battle-tested OpenZeppelin implementations over custom patterns. Security > Gas optimization > Code elegance.
Didn't find tool you were looking for?