develop-secure-contrac…
Develop secure smart contracts using OpenZeppelin Contracts libraries. Use when users need to integrate OpenZeppelin library…
Upgrade Stylus smart contracts using OpenZeppelin proxy patterns on Arbitrum. Use when users need to: (1) make Stylus Rust contracts upgradeable with UUPS or Beacon proxies, (2) understand Stylus-specific proxy mechanics (logic_flag, WASM reactivation), (3) integrate
Claude Code
$ npx -y skills add OpenZeppelin/openzeppelin-skills --skill upgrade-stylus-contracts --agent claude-code
Codex
$ npx skills add OpenZeppelin/openzeppelin-skills --skill upgrade-stylus-contracts -a codex -y
Cursor
$ npx skills add OpenZeppelin/openzeppelin-skills --skill upgrade-stylus-contracts -a cursor -y
Gemini CLI
$ npx skills add OpenZeppelin/openzeppelin-skills --skill upgrade-stylus-contracts -a gemini-cli -y
GitHub Copilot
$ npx skills add OpenZeppelin/openzeppelin-skills --skill upgrade-stylus-contracts -a github-copilot -y
OpenCode
$ npx skills add OpenZeppelin/openzeppelin-skills --skill upgrade-stylus-contracts -a opencode -y
Windsurf
$ npx skills add OpenZeppelin/openzeppelin-skills --skill upgrade-stylus-contracts -a windsurf -y
name: upgrade-stylus-contracts description: "Upgrade Stylus smart contracts using OpenZeppelin proxy patterns on Arbitrum. Use when users need to: (1) make Stylus Rust contracts upgradeable with UUPS or Beacon proxies, (2) understand Stylus-specific proxy mechanics (logic_flag, WASM reactivation), (3) integrate UUPSUpgradeable with access control, (4) ensure storage compatibility across upgrades, or (5) test upgrade paths for Stylus contracts." license: AGPL-3.0-only metadata: author: OpenZeppelin
Stylus contracts run on Arbitrum as WebAssembly (WASM) programs alongside the EVM. They share the same state trie, storage model, and account system as Solidity contracts. Because of this, **EVM proxy patterns work identically** for Stylus — a Solidity proxy can delegate to a Stylus implementation and vice versa.
| | Stylus | Solidity | |---|---|---| | **Proxy mechanism** | Same — `delegatecall` to implementation contract | `delegatecall` to implementation contract | | **Storage layout** | `#[storage]` fields map to the same EVM slots as equivalent Solidity structs | Sequential slot allocation per Solidity rules | | **EIP standards** | ERC-1967 storage slots, ERC-1822 proxiable UUID | Same | | **Context detection** | `logic_flag` boolean in a unique storage slot (no `immutable` support) | `address(this)` stored as `immutable` | | **Initialization** | Two-step: constructor sets `logic_flag`, then `set_version()` via proxy | Constructor + initializer via proxy | | **Reactivation** | WASM contracts must be reactivated every 365 days or after a Stylus protocol upgrade | Not applicable |
Existing Solidity contracts can upgrade to a Stylus (Rust) implementation via proxy patterns. The `#[storage]` macro lays out fields in the EVM state trie identically to Solidity, so storage slots line up when type definitions match.
OpenZeppelin Contracts for Stylus provides three proxy patterns:
| Pattern | Key types | Best for | |---------|----------|----------| | **UUPS** | `UUPSUpgradeable`, `IErc1822Proxiable`, `Erc1967Proxy` | Most projects — upgrade logic in the implementation, lighter proxy | | **Beacon** | `BeaconProxy`, `UpgradeableBeacon` | Multiple proxies sharing one implementation — updating the beacon upgrades all proxies atomically | | **Basic Proxy** | `Erc1967Proxy`, `Erc1967Utils` | Low-level building block for custom proxy patterns |
The implementation contract composes `UUPSUpgradeable` in its `#[storage]` struct alongside access control (e.g., `Ownable`). Integration requires:
1. Add `UUPSUpgradeable` (and access control) as fields in the `#[storage]` struct 2. Call `self.uups.constructor()` and initialize access control in the constructor 3. Expose `initialize` calling `self.uups.set_version()` — invoked via proxy after deployment 4. Implement `IUUPSUpgradeable` — `upgrade_to_and_call` guarded by access control, `upgrade_interface_version` delegating to `self.uups` 5. Implement `IErc1822Proxiable` — `proxiable_uuid` delegating to `self.uups`
The proxy contract is a thin `Erc1967Proxy` with a constructor that takes the implementation address and initialization data, and a `#[fallback]` handler that delegates all calls.
Deploy the proxy with `set_version` as the initialization call data. Use `cargo stylus deploy` or a deployer contract. The initialization data is the ABI-encoded `setVersion` call:
let data = MyContractAbi::setVersionCall {}.abi_encode();
// Pass `data` as the proxy constructor's second argument at deployment time.Multiple `BeaconProxy` contracts point to a single `UpgradeableBeacon` that stores the current implementation address. Updating the beacon upgrades all proxies in one transaction.
Stylus does not support the `immutable` keyword. Instead of storing `__self = address(this)`, `UUPSUpgradeable` uses a `logic_flag` boolean in a unique storage slot:
`only_proxy()` also verifies that the ERC-1967 implementation slot is non-zero and that the proxy-stored version matches the implementation's `VERSION_NUMBER`.
> **Examples:** See the `examples/` directory of the [rust-contracts-stylus repository](https://github.com/OpenZeppelin/rust-contracts-stylus) for full working integration examples of UUPS, Beacon, and related patterns.
Upgrade functions must be guarded with access control. OpenZeppelin's Stylus contracts do **not** embed access control into the upgrade logic itself — you must add it in `upgrade_to_and_call`:
fn upgrade_to_and_call(&mut self, new_implementation: Address, data: Bytes) -> Result<(), Vec<u8>> {
self.ownable.only_owner()?; // or any access control check
self.uups.upgrade_to_and_call(new_implementation, data)?;
Ok(())
}Common options:
Stylus `#[storage]` fields are laid out in the EVM state trie identically to Solidity. The same storage layout rules apply when upgrading:
Agent skills for secure smart contract development with OpenZeppelin Contracts libraries and migration of Defender workflows.
Develop secure smart contracts using OpenZeppelin Contracts libraries. Use when users need to integrate OpenZeppelin library…
Migrate OpenZeppelin Defender Actions, Autotasks, Monitors and scheduled or Relayer-backed workflows to Chainlink CRE. Use when…
Review Sui Move code that integrates OpenZeppelin Contracts for Sui against the library's own patterns and conventions. Use this…
Set up a Cairo smart contract project with OpenZeppelin Contracts for Cairo on Starknet. Use when users need to: (1) create a new…
Set up a Solidity smart contract project with OpenZeppelin Contracts. Use when users need to: (1) create a new Hardhat or Foundry…
Set up a Stellar/Soroban smart contract project with OpenZeppelin Contracts for Stellar. Use when users need to: (1) install…
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
Ask which skill or flow fits your situation. A router over the skills in this repo.