TLDR
- Make sure your contracts are upgradable
- Upgrade your proxy and implementation contracts to Cairo1.0 during regenesis (you can upgrade them also to non-upgradable apps)
- Stay tuned for more information around Cairo 1.0 (and examples for migrating to it)
Intro
During regenesis, Starknet’s contracts would gradually shift over a transition period to a new, more straightforward, and more feature-rich language - Cairo 1.0. You can find more information about the motivation behind this transition here. This document focuses on the technical perspective - what code you need to add to guarantee your app continues functioning without disruption during and after the regenesis.
Timeline
Regenesis is planned to take place over the first quarter of 2023. StarkNet will support Cairo 1.0 starting early Q1, and Cairo v0 would be deprecated starting early Q2, though this date might shift a bit based on the community adoption rate.
Moving forward with backward compatible state
To ensure regenesis is state-compatible and non-disruptive process, we need the following:
- The addresses of all contracts remain the same after Cairo 1.0 migration.
- The storage layout of variables inside the Application stays the same.
For example, Alice, a user in the system, has 1000 USDC. Property number (1) ensures that the USDC contract is indifferent to Alice updating her account contract to Cairo 1.0, as her address stays the same. Property number (2) ensures that Alice is indifferent to the USDC contract updating to Cairo 1.0 - it continues to function the same and refers to the pre-upgrade balances.
How to ensure these attributes?
We will start with the first attribute, namely preserving the address - as this is what has immediate effect on Cairo v0 implementation. The second attribute would be relevant only when you rewrite the Cairo 1.0 implementation, and is addressed in the FAQ section.
Notice that by default (i.e., without any unique action), the addresses of all the apps would change as their class hash changes. Thus, to allow address preservation, we will add a new system call that would mean something like “Please replace the code in my address with class hash X (and the current state).”
Notice that this process wouldn’t call the constructor of your Cairo1.0 contract, as it will continue to operate from the same state. If further initialization procedure would be required for the Cairo1.0 logic (due to updating the app logic itself) you can add initialize function and trigger it through multicall.
Your Application contract would thus eventually need to contain a function that looks roughly like that:
func upgrade_to_cairo_one(new_class_hash: felt)
{
// Implement the flow control your app / DAO needs to migrate the contract.
check_caller_is_allowed();
update_class_hash(new_class_hash);
// At this point, your contract will have the same address as before,
// but use the new Cairo 1.0 code.
}
In particular, note that your app needs some “controller” (an individual, multi-sig, another smart contract, etc.) to migrate smoothly.
At the end of the transition period (i.e., when the regenesis is completed) we will eliminate this system call from StarkNet - we view it as a temporary solution for ease up migration to the new Cairo variant, and not as a long-term feature of the network.
StarkWare will release the concrete API for the syscall at the start of the transition period at the latest. However, you can still launch now without the function “update_class_hash” by launching an upgradable app. The flow looks as follows:
- Launch before the transition period as an upgradable app (following the proxy pattern).
- Upgrade your implementation to contain the function “upgrade_to_cairo_one”.
- Use this function to update the main/proxy contract to Cairo 1.0 while keeping its address and state. Notice that if used in this manner, this system call would update the proxy contract itself - and not the “implementation” behind it. As the proxy is the contract in charge of the state, this enables moving to Cairo-1.0 logic with the same state. In particular, you can upgrade your proxy to a non-upgradable (non-proxy) contract containing all the logic, and turn your app into a non-upgradable one.
FAQs
How can I make my app upgradable? What code to add?
It’s easy! All you have to do is to adopt and use the upgradability pattern written by OpenZepplin (with sample proxy contract and implementation contract). proxy_admin’s identity can be the same controller you plan to verify in the check_caller_is_allowed() component given above.
What about keeping the storage layout consistent?
This is, first and foremost, an attribute of Cairo 1.0. Cairo 1.0 will support the same memory layout as the current version of Cairo. This means that if the USDC contract currently expects to find Alice’s balance in the index matching her address, and the Cairo 1.0 implementation of the contract is written the same way, it will continue to fetch Alice’s balance from the state.
Thus, when writing your Cairo 1.0 implementation, you must ensure that the variable names are consistent with your current deployment.
Where can I find more information on Cairo 1.0 and rewriting examples?
We will release all these materials as soon as we have them, and will add a link to this post.