Skip to content

/develop-secure-contracts

Develop secure smart contracts using OpenZeppelin Contracts libraries. Use when users need to integrate OpenZeppelin library components — including token standards (ERC20, ERC721, ERC1155), access control (Ownable, AccessControl, AccessManager), security primitives (Pausable,

From plugin
openzeppelin-skills
22012 skills

Claude Code

$ npx -y skills add OpenZeppelin/openzeppelin-skills --skill develop-secure-contracts --agent claude-code

SKILL.md

develop-secure-contracts.SKILL.md
name: develop-secure-contracts
description: "Develop secure smart contracts using OpenZeppelin Contracts libraries. Use when users need to integrate OpenZeppelin library components — including token standards (ERC20, ERC721, ERC1155), access control (Ownable, AccessControl, AccessManager), security primitives (Pausable, ReentrancyGuard), governance (Governor, timelocks), or accounts (multisig, account abstraction) — into existing or new contracts. Covers pattern discovery from library source, CLI contract generators, and library-first integration. Supports Solidity, Cairo, Stylus, Stellar, and Sui Move."
license: AGPL-3.0-only
metadata:
  author: OpenZeppelin

Develop Secure Smart Contracts with OpenZeppelin

Core Workflow

Understand the Request Before Responding

For conceptual questions ("How does Ownable work?"), explain without generating code. For implementation requests, proceed with the workflow below.

CRITICAL: Always Read the Project First

Before generating code or suggesting changes:

1. **Search the user's project** for existing contracts (`Glob` for `**/*.sol`, `**/*.cairo`, `**/*.rs`, `**/*.move`, etc.) 2. **Read the relevant contract files** to understand what already exists 3. **Default to integration, not replacement** — when users say "add pausability" or "make it upgradeable", they mean modify their existing code, not generate something new. Only replace if explicitly requested ("start fresh", "replace this").

If a file cannot be read, surface the failure explicitly — report the path attempted and the reason. Ask whether the path is correct. Never silently fall back to a generic response as if the file does not exist.

Fundamental Rule: Prefer Library Components Over Custom Code

Before writing ANY logic, search the OpenZeppelin library for an existing component:

1. **Exact match exists?** Import and use it directly — inherit, implement its trait, compose with it. Done. 2. **Close match exists?** Import and extend it — override only functions the library marks as overridable (virtual, hooks, configurable parameters). 3. **No match exists?** Only then write custom logic. Confirm by browsing the library's directory structure first.

**NEVER copy or embed library source code into the user's contract.** Always import from the dependency so the project receives security updates. Never hand-write what the library already provides:

  • Never write a custom `paused` modifier when `Pausable` or `ERC20Pausable` exists
  • Never write `require(msg.sender == owner)` when `Ownable` exists
  • Never implement ERC165 logic when the library's base contracts already handle it

Methodology

The primary workflow is **pattern discovery from library source code**:

1. Inspect what the user's project already imports 2. Read the dependency source and docs in the project's installed packages 3. Identify what functions, modifiers, hooks, and storage the dependency requires 4. Apply those requirements to the user's contract

See [Pattern Discovery and Integration](#pattern-discovery-and-integration) below for the full step-by-step procedure.

CLI Generators as Reference

Use `npx @openzeppelin/contracts-cli` to generate reference implementations for pattern discovery: generate a baseline to a file, generate with a feature enabled to another file, diff them, and apply the changes to the user's code. The CLI output is the canonical correct integration — use it as the source of truth for what imports, inheritance, storage, and overrides a feature requires.

See [CLI Generators](#cli-generators) for details on the generate-compare-apply workflow.

If no CLI command exists for what's needed, use the generic pattern discovery methodology from [Pattern Discovery and Integration](#pattern-discovery-and-integration). The absence of a CLI command does not mean the library lacks support — it only means there is no generator.

Pattern Discovery and Integration

Procedural guide for discovering and applying OpenZeppelin contract integration patterns by reading dependency source code. Works for any ecosystem and any library version.

**Prerequisite:** Always follow the library-first decision tree above (prefer library components over custom code, never copy/embed source).

Step 1: Identify Dependencies and Search the Library

1. Search the project for contract files: `Glob` for `**/*.sol`, `**/*.cairo`, `**/*.rs`, `**/*.move`, or the relevant extension from the lookup table below. 2. Read import/use statements in existing contracts to identify which OpenZeppelin components are already in use. 3. Locate the installed dependency in the project's dependency tree:

  • Solidity: `node_modules/@openzeppelin/contracts/` (Hardhat/npm) or

`lib/openzeppelin-contracts/` (Foundry/forge)

  • Cairo: resolve from `Scarb.toml` dependencies — source cached by Scarb
  • Stylus: resolve from `Cargo.toml` — source in `target/` or the cargo registry cache

(`~/.cargo/registry/src/`)

  • Stellar: resolve from `Cargo.toml` — same cargo cache locations as Stylus
  • Sui Move: resolve from `Move.toml` — after a build, the MVR source is cached under `~/.move/`

and mirrored per-dependency in `build/<project_package>/sources/dependencies/<move_package_name>/` 4. Browse the dependency's directory listing to discover available components. Use `Glob` patterns against the installed source (e.g., `node_modules/@openzeppelin/contracts/**/*.sol`). Do not assume knowledge of the library's contents — always verify by listing directories. 5. If the dependency is not installed locally, clone or browse the canonical repository (see lookup table below).

Step 2: Read the Dependency Source and Documentation

1. Read the source file of the component relevant to the user's request. 2. Look for documentation within the source: NatSpec comments (`///`, `/** */`) in Solidity, doc comments (`///`) in Rust and Cairo, and README files in the component's directory. 3. Determine th

Read more
@openzeppelin
Ships withopenzeppelin-skills

Agent skills for secure smart contract development with OpenZeppelin Contracts libraries and migration of Defender workflows.

Stars on GitHub

Momentum

stars in total
220
Star history of OpenZeppelin/openzeppelin-skills on GitHub, a chart by star-history.com

Other skills on openzeppelin-skills.

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills11d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc13d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react2d252k
@facebook@facebookInstall Skill

Questions about develop-secure-contracts.

Which coding agents can use develop-secure-contracts?
develop-secure-contracts installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.