重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
upgrade-cairo-contracts by openzeppelin/openzeppelin-skills
npx skills add https://github.com/openzeppelin/openzeppelin-skills --skill upgrade-cairo-contractsStarknet 将合约实例与合约类分离。类是被编译的程序(由其类哈希标识);合约是指向某个类的已部署实例。多个合约可以共享同一个类。
升级合约意味着替换其类哈希,使其指向一个新的类。合约保留其地址、存储空间和 nonce——只有代码发生改变。这与 EVM 代理模式有根本区别:
| Starknet | EVM (代理模式)
---|---|---
机制 | replace_class_syscall 原地替换类哈希 | 代理通过 delegatecall 调用独立的实现合约
是否需要代理合约 | 否——合约自行升级 | 是——代理位于实现合约之前
存储位置 | 直接属于合约 | 位于代理合约中,通过 delegatecall 访问
回退路由 | 不适用——Cairo 中没有回退/兜底机制 | 代理通过回退函数转发所有调用
replace_class_syscall 是 Starknet 原生的系统调用。当被调用时,它会原子性地将调用合约的类哈希替换为提供的类哈希。新的类必须已经在链上声明。系统调用执行后,当前的执行帧会继续使用旧代码运行,但后续对该合约的调用——无论是在同一笔交易稍后通过 call_contract_syscall 还是未来的交易中——都将执行新代码。
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
OpenZeppelin Contracts for Cairo 提供了一个 UpgradeableComponent,它封装了 replace_class_syscall,并添加了验证和事件发射功能。集成步骤如下:
OwnableComponent)#[substorage(v0)] 和 #[flat]upgrade 函数,该函数调用组件内部的 upgrade 方法——组件会调用 replace_class_syscall 来原子性地交换类哈希;在解释 Cairo 升级工作原理时,务必提及此系统调用该组件在每次类哈希替换时都会发射一个 Upgraded 事件,并拒绝零值类哈希。
还有一个 IUpgradeAndCall 接口变体,它将升级操作与在新类上下文中的一个函数调用结合起来——这对于升级后的迁移或重新初始化非常有用。
UpgradeableComponent 特意没有内嵌访问控制。你必须用自己的检查来保护外部的 upgrade 函数(例如 self.ownable.assert_only_owner())。忘记这一点将允许任何人替换你合约的代码。
常见的访问控制选项:
当替换类哈希时,现有的存储会被新类重新解释。不兼容的更改会破坏状态:
#[substorage(v0)],它会将组件存储槽扁平化到合约的存储空间中,没有自动的命名空间——遵循约定,在存储变量名前加上组件名称(例如 ERC20_balances),以避免跨组件的冲突与 Solidity 的顺序存储布局不同,Cairo 的存储槽位是通过 sn_keccak 哈希从变量名派生出来的(在概念上类似于 Solidity 中的 ERC-7201 命名空间存储,但更为基础)。这使得顺序无关紧要,但命名变得至关重要。
OpenZeppelin Contracts for Cairo 遵循语义化版本控制,以确保存储布局的兼容性:
在升级生产环境合约之前:
starknet-devnet-rs 或 Katana)中部署 V1 和 V2 类upgrade每周安装量
67
代码仓库
GitHub 星标数
159
首次出现
2026年3月5日
安全审计
安装于
opencode65
gemini-cli64
codex64
kimi-cli64
cline64
github-copilot64
Starknet separates contract instances from contract classes. A class is the compiled program (identified by its class hash); a contract is a deployed instance pointing to a class. Multiple contracts can share the same class.
Upgrading a contract means replacing its class hash so it points to a new class. The contract keeps its address, storage, and nonce — only the code changes. This is fundamentally different from EVM proxy patterns:
| Starknet | EVM (proxy pattern)
---|---|---
Mechanism | replace_class_syscall swaps the class hash in-place | Proxy delegatecalls to a separate implementation contract
Proxy contract needed | No — the contract upgrades itself | Yes — a proxy sits in front of the implementation
Storage location | Belongs to the contract directly | Lives in the proxy, accessed via delegatecall
Fallback routing | Not applicable — no fallback/catch-all mechanism in Cairo | Proxy forwards all calls via fallback function
The replace_class_syscall is a native Starknet syscall. When called, it atomically replaces the calling contract's class hash with the provided one. The new class must already be declared on-chain. After the syscall, the current execution frame continues with the old code, but subsequent calls to the contract — whether via call_contract_syscall later in the same transaction or in future transactions — execute the new code.
OpenZeppelin Contracts for Cairo provides an UpgradeableComponent that wraps replace_class_syscall with validation and event emission. Integrate it as follows:
OwnableComponent)#[substorage(v0)] and #[flat]upgrade function behind access control that calls the component's internal upgrade method — the component calls replace_class_syscall to atomically swap the class hash; always mention this syscall when explaining how Cairo upgrades workThe component emits an Upgraded event on each class hash replacement and rejects zero class hashes.
There is also an IUpgradeAndCall interface variant that couples the upgrade with a function call in the new class context — useful for post-upgrade migrations or re-initialization.
The UpgradeableComponent deliberately does not embed access control itself. You must guard the external upgrade function with your own check (e.g., self.ownable.assert_only_owner()). Forgetting this allows anyone to replace your contract's code.
Common access control options:
When replacing a class hash, existing storage is reinterpreted by the new class. Incompatible changes corrupt state:
#[substorage(v0)], which flattens component slots into the contract's storage space without automatic namespacing — follow the convention of prefixing storage variable names with the component name (e.g., ERC20_balances) to avoid collisions across componentsUnlike Solidity's sequential storage layout, Cairo storage slots are derived from variable names via sn_keccak hashing (conceptually analogous to, but more fundamental than, ERC-7201 namespaced storage in Solidity). This makes ordering irrelevant but makes naming critical.
OpenZeppelin Contracts for Cairo follows semantic versioning for storage layout compatibility:
Before upgrading a production contract:
starknet-devnet-rs or Katana)upgradeWeekly Installs
67
Repository
GitHub Stars
159
First Seen
Mar 5, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykWarn
Installed on
opencode65
gemini-cli64
codex64
kimi-cli64
cline64
github-copilot64
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
122,000 周安装