upgrade-cairo-contracts
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCairo Upgrades
Cairo 合约升级
Contents
目录
Starknet Upgrade Model
Starknet 升级模型
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 | | Proxy |
| 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 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 later in the same transaction or in future transactions — execute the new code.
replace_class_syscallcall_contract_syscallStarknet 将合约实例与合约类分离。类是编译后的程序(通过类哈希标识);合约是指向某个类的已部署实例。多个合约可以共享同一个类。
升级合约意味着替换其类哈希,使其指向新的类。合约会保留其地址、存储和随机数——只有代码会改变。这与EVM代理模式有着本质区别:
| Starknet | EVM(代理模式) | |
|---|---|---|
| 实现机制 | | 代理通过 |
| 是否需要代理合约 | 不需要——合约自行完成升级 | 需要——代理合约位于实现合约前端 |
| 存储位置 | 直接属于合约本身 | 存储在代理中,通过delegatecall访问 |
| 回退路由 | 不适用——Cairo中没有回退/兜底机制 | 代理通过回退函数转发所有调用 |
replace_class_syscallcall_contract_syscallUsing the OpenZeppelin Upgradeable Component
使用 OpenZeppelin 可升级组件
OpenZeppelin Contracts for Cairo provides an that wraps with validation and event emission. Integrate it as follows:
UpgradeableComponentreplace_class_syscall- Declare the component alongside an access control component (e.g., )
OwnableComponent - Add both to storage and events using and
#[substorage(v0)]#[flat] - Expose an function behind access control that calls the component's internal
upgrademethod — the component callsupgradeto atomically swap the class hash; always mention this syscall when explaining how Cairo upgrades workreplace_class_syscall - Initialize access control in the constructor
The component emits an event on each class hash replacement and rejects zero class hashes.
UpgradedThere is also an interface variant that couples the upgrade with a function call in the new class context — useful for post-upgrade migrations or re-initialization.
IUpgradeAndCallOpenZeppelin Contracts for Cairo 提供了,它封装了并添加了验证和事件发射功能。集成步骤如下:
UpgradeableComponentreplace_class_syscall- 声明组件,同时声明访问控制组件(如)
OwnableComponent - 使用和
#[substorage(v0)]将两者添加到存储和事件中#[flat] - 暴露函数,并通过访问控制进行保护,该函数会调用组件的内部
upgrade方法——组件会调用upgrade来原子性地交换类哈希;在解释Cairo合约升级原理时,务必提及此系统调用replace_class_syscall - 在构造函数中初始化访问控制
该组件会在每次类哈希替换时发射事件,并拒绝零值类哈希。
Upgraded还有一个接口变体,可将升级操作与新类上下文下的函数调用结合——适用于升级后的迁移或重新初始化操作。
IUpgradeAndCallAccess control
访问控制
The deliberately does not embed access control itself. You must guard the external function with your own check (e.g., ). Forgetting this allows anyone to replace your contract's code.
UpgradeableComponentupgradeself.ownable.assert_only_owner()Common access control options:
- Ownable — single owner, simplest pattern
- AccessControl / RBAC — role-based, finer granularity
- Multisig or governance — for production contracts managing significant value
UpgradeableComponentupgradeself.ownable.assert_only_owner()常见的访问控制选项:
- Ownable —— 单所有者,最简单的模式
- AccessControl / RBAC —— 基于角色,粒度更细
- 多签或治理 —— 适用于管理大额资产的生产级合约
Upgrade Safety
升级安全性
Storage compatibility
存储兼容性
When replacing a class hash, existing storage is reinterpreted by the new class. Incompatible changes corrupt state:
- Do not rename or remove existing storage variables — the slot is derived from the variable name, so renaming makes old data inaccessible
- Do not change the type of existing storage variables
- Adding new storage variables is safe
- Component storage uses , 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.,
#[substorage(v0)]) to avoid collisions across componentsERC20_balances
Unlike Solidity's sequential storage layout, Cairo storage slots are derived from variable names via hashing (conceptually analogous to, but more fundamental than, ERC-7201 namespaced storage in Solidity). This makes ordering irrelevant but makes naming critical.
sn_keccak替换类哈希时,现有存储会被新类重新解析。不兼容的更改会导致状态损坏:
- 请勿重命名或删除现有存储变量——存储槽由变量名派生而来,重命名会导致旧数据无法访问
- 请勿更改现有存储变量的类型
- 添加新的存储变量是安全的
- 组件存储使用,它会将组件的存储槽扁平化到合约的存储空间中,且没有自动命名空间——请遵循组件名前缀的约定(例如
#[substorage(v0)]),以避免跨组件的存储冲突ERC20_balances
与Solidity的顺序存储布局不同,Cairo的存储槽是通过哈希从变量名派生而来(概念上类似于但比Solidity中的ERC-7201命名空间存储更基础)。这意味着存储顺序无关紧要,但变量命名至关重要。
sn_keccakOpenZeppelin version upgrades
OpenZeppelin 版本升级
OpenZeppelin Contracts for Cairo follows semantic versioning for storage layout compatibility:
- Patch updates always preserve storage layout
- Minor updates preserve storage layout (from v1.0.0 onward)
- Major updates may break storage layout — never upgrade a live contract across major versions without reviewing the changelog
OpenZeppelin Contracts for Cairo 遵循语义化版本控制以保证存储布局兼容性:
- 补丁版本更新始终保留存储布局
- 次要版本更新保留存储布局(从v1.0.0开始)
- 主要版本更新可能会破坏存储布局——在未查看变更日志的情况下,切勿对线上合约进行跨主要版本的升级
Testing upgrade paths
测试升级路径
Before upgrading a production contract:
- Deploy V1 and V2 classes in a local devnet (e.g., or Katana)
starknet-devnet-rs - Write state with V1, upgrade to V2, and verify that all existing state reads correctly
- Verify new functionality works as expected after the upgrade
- Confirm access control — only authorized callers can invoke
upgrade - Check API compatibility — changed external function signatures break existing callers and integrations
- Review storage changes — ensure no renames, removals, or type changes to existing variables
- Manual review — there is no automated storage layout validation for Cairo; use the MCP contract generators to discover current integration patterns and rely on devnet testing
在升级生产级合约之前:
- 部署V1和V2版本的类到本地开发网络(如或Katana)
starknet-devnet-rs - 用V1版本写入状态,升级到V2版本,验证所有现有状态都能被正确读取
- 验证新功能在升级后能正常工作
- 确认访问控制——只有授权调用者才能调用函数
upgrade - 检查API兼容性——外部函数签名的变更会破坏现有调用者和集成
- 审查存储变更——确保没有对现有变量进行重命名、删除或类型更改
- 人工审查——目前Cairo没有自动化的存储布局验证工具;使用MCP合约生成器了解当前集成模式,并依赖开发网络测试