develop-secure-contrac…
Develop secure smart contracts using OpenZeppelin Contracts libraries. Use when users need to integrate OpenZeppelin library components — including token…
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
$ npx -y skills add OpenZeppelin/openzeppelin-skills --skill upgrade-stylus-contracts --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/upgrade-stylus-contractsContext preview
The summary Claude sees to decide when to auto-load this skill.
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
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.
Develop secure smart contracts using OpenZeppelin Contracts libraries. Use when users need to integrate OpenZeppelin library components — including token…
Review Sui Move code that integrates OpenZeppelin Contracts for Sui against the library's own patterns and conventions. Use this when a developer wants their…
Set up a Cairo smart contract project with OpenZeppelin Contracts for Cairo on Starknet. Use when users need to: (1) create a new Scarb/Starknet project, (2)…
Set up a Solidity smart contract project with OpenZeppelin Contracts. Use when users need to: (1) create a new Hardhat or Foundry project, (2) install…
Set up a Stellar/Soroban smart contract project with OpenZeppelin Contracts for Stellar. Use when users need to: (1) install Stellar CLI and Rust toolchain for…
Set up a Stylus smart contract project with OpenZeppelin Contracts for Stylus on Arbitrum. Use when users need to: (1) install Rust toolchain and WASM target…