An open API service indexing awesome lists of open source software.

https://github.com/NethermindEth/0to1CairoDemo

Demo to upgrade your upgradeable cairo 0 proxy contract to cairo 1 via replace_class_syscall
https://github.com/NethermindEth/0to1CairoDemo

Last synced: about 1 month ago
JSON representation

Demo to upgrade your upgradeable cairo 0 proxy contract to cairo 1 via replace_class_syscall

Awesome Lists containing this project

README

        

# How to upgrade your Cairo 0 contracts to Cairo 1 using `replace_class`

## Why upgrade to Cairo 1.0 ?

With Regenesis approaching on Starknet, Cairo 0.x will soon be deprecated in favour of Cairo 1. To ensure your contracts continue working after Regenesis, it's important to migrate them from Cairo 0.x to Cairo 1. As Starknet Alpha v0.11.0 is now live on Mainnet, Cairo 1 contracts can now deployed and current Cairo 0 contracts can now be upgraded with provided `replaced_class` syscall without necessitating a change in contract address.

## Upgrading your Upgradable Cairo 0.x contracts to Cairo 1

In Cairo 0.x, in order to have an upgradable Cairo 0.x contracts, you will often utilize a `Proxy` contract with a `set_implementation` function that allows the contract owner to upgrade

The method that we will be covering utilizes the `replace_class` syscall to remove the need for a proxy pattern altogether. At the end of migration the contract utlizes an implementation class hash with an upgrade method in it. This method assumes that the `replace_call` syscall will not be deprecated and the Proxy pattern in cairo0 will not be the dominant pattern for upgradeable contracts in cairo1.

Before proceeding with the tutorial, make sure you have the following dependencies installed.

```bash
cairo-lang v0.11.0
cairo v1.0.0-alpha.6
protostar
```

You can install `cairo-lang` with `pip`. We are using protostar but it is optional and can be replaced with any other similar tooling that you might prefer.

The code for the contracts used in this article is available at https://github.com/NethermindEth/0to1CairoDemo. Feel free to follow along!

### Building and deploying the Cairo 0 contracts

Let's start off by building the required Cairo 0 contracts.

```shell
cd cairo0
protostar build
```

Declare both the `proxy` and the `cairo0resolver` that's built in the previous step.

```shell
protostar declare ./build/proxy.json \
--account-address $ACCOUNT_ADDRESS --max-fee auto \
--private-key-path=../private --network testnet

protostar declare ./build/cairo0resolver.json \
--account-address $ACCOUNT_ADDRESS --max-fee auto \
--private-key-path=../private --network testnet
```

Here, the `$ACCOUNT_ADDRESS` is the address of your wallet, and `./private` is the file containing your private key.

If for some reason declare doesnt work from CLI, you can try ArgentX wallet's developer settings under `Settings -> Developer settings -> Smart contract development`, which provides a GUI for declaring your contract.

![argent-dev](./argentx-dev-settings.png)

Finally, we deploy an implementation of the declared classes on chain via `protostar deploy`, which calls a UDC to deploy our contracts.

```shell
protostar deploy $PROXY_CLASS_HASH \
--account-address $ACCOUNT_ADDRESS \
-n testnet --max-fee auto --private-key-path ./private \
--wait-for-acceptance \
-i $CAIRO0_RESOLVER_CLASS_HASH \
0x2dd76e7ad84dbed81c314ffe5e7a7cacfb8f4836f01af4e913f275f89a3de1a 1 \
$ACCOUNT_ADDRESS
```

This deploys the Proxy contract and calls the `initializer` with the desired class hash to proxy to, which in this case would be the our `cairo0resolver` class.

The inputs provided via the `-i` flag specifies the class hash for the `cairo0resolver`, the selector for the `initializer` function, the length of the calldata, and wallet the address of the proxy admin respectively.

### Upgrading your contract

Before we perform the upgrade, let's perform some state changes on the contract. We can do this via invoking a the `set_starknet_id` function on the contract which will update the `resolver` variable to the specified value. You can do this either via `protostar invoke` or just using the Voyager provided function call interface.

```shell
protostar invoke \
--contract-address $PROXY_CONTRACT_ADDRESS \
--function set_starknet_id \
--inputs 10 2024 \
--max-fee auto --private-key-path ../private \
--network testnet --account-address $ACCOUNT_ADDRESS
```

In voyager, you can invoke the function by going to https://goerli.voyager.online/contract/{CONTRACT_ADDRESS}#writeContract, where `CONTRACT_ADDRESS` should be replaced by the proxy contract address.

![invoke-with-voyager](./voyager-contract-invoke.png)

After the transaction is accepted, the state should be updated successfully.

Next, let's prepare to upgrade our contract. As most Cairo tooling are still adding support to Cairo 1, we will be using the binaries from the Cairo repo directly as well as utilize the Starknet Cli.

You can reuse the account you used for the deployment of your previous contracts with protostar by editing your starknet account config, which usually resides in `~/.starknet_accounts`.

```json
{
"alpha-goerli": {
"account_v11": {
"private_key": "${WALLET_PRIVATE_KEY}",
"address": "${WALLET_ADDRESS}",
"deployed": true
}
}
}
```

As usual, build your Cairo contracts, but this time using the binaries from `Cairo v1.0.0-alpha.6`.

```json
starknet-compile ./cairo1/cairo1resolver.cairo ./cairo1/cairo1resolver.json --replace-ids
```

Now, we can start declaring our Cairo 1 contract on chain.

```shell
starknet declare --contract ./cairo1resolver.json --account account_v11
```

If you have any issue declaring your Cairo 1 contract, you can check out [our article] on deploying your first Cairo 1 contract, which covers some of the problems you might face.

Finally, we can now perform an upgrade via the proxy to the new Cairo 1 implementation.

```bash
starknet invoke \
--address $PROXY_CONTRACT_ADDRESS \
--abi ./cairo0/build/cairo0resolver_abi.json \
--function upgrade \
--inputs $CAIRO_1_RESOLVER_CLASS_HASH \
--account account_v11
```

After the transaction is accepted by L2, you can now check if the implementation has been updated and the state is in tact as well to confirm that the update is successful! The proxy should now point to your Cairo 1 class and reading `resolver` should return you the same state as before without issues!

With this, you have successfully upgraded your Cairo 0.x implementation to Cairo 1!

## Upgradable Cairo 1 contract

With the `replace_class` syscall, it is now possible to remove the need for a Proxy altogether. Now, to upgrade your contract, you can call the `upgrade` function which will call `replace_class` to replace the current class of your implementation with the provided class, effectively performing an upgrade.

Our `cairo1resolver` class already implemented an `upgrade` function that utilizes `replace_class` for this. If you haven't implemented something like this yet, you might need to perform a upgrade for your proxy again to a class with this function implemented. It will look something like this:

```rust
#[external]
fn upgrade(new_class_hash: core::starknet::class_hash::ClassHash) ->felt252 {
replace_class_syscall(new_class_hash);
1
}
```

Let's now proceed with calling the above `upgrade` function:

```shell
starknet invoke \
--address $PROXY_CONTRACT_ADDRESS \
--function upgrade \
--inputs $CAIRO_1_RESOLVER_CLASS_HASH \
--account account_v11
```

After the transaction is accepted, you should now see that your proxy contract has been changed to a regular contract with an implementation class of `cairo1resolver`!

With this, you now have a Cairo 1 contract that is upgradable as well!