Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate Upgrades to component #792

Merged
5 changes: 5 additions & 0 deletions docs/modules/ROOT/pages/access.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ mod MyContract {
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
OwnableEvent: ownable_component::Event
}

Expand Down Expand Up @@ -163,7 +164,9 @@ mod MyContract {
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
AccessControlEvent: accesscontrol_component::Event,
#[flat]
SRC5Event: src5_component::Event
}

Expand Down Expand Up @@ -240,7 +243,9 @@ mod MyContract {
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
AccessControlEvent: accesscontrol_component::Event,
#[flat]
SRC5Event: src5_component::Event
}

Expand Down
2 changes: 1 addition & 1 deletion docs/modules/ROOT/pages/api/upgrades.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ NOTE: This function is usually protected by an xref:access.adoc[Access Control]
use openzeppelin::upgrades::upgradeable::Upgradeable;
```

Upgradeable contract module.
Upgradeable component.

[.contract-index]
.Internal Functions
Expand Down
1 change: 1 addition & 0 deletions docs/modules/ROOT/pages/introspection.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ mod MyContract {
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
SRC5Event: src5_component::Event
}

Expand Down
46 changes: 33 additions & 13 deletions docs/modules/ROOT/pages/upgrades.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn _upgrade(new_class_hash: ClassHash) {

NOTE: If a contract is deployed without this mechanism, its class hash can still be replaced through {library_calls}.

== `Upgradeable` module
== `Upgradeable` component

OpenZeppelin Contracts for Cairo provides {upgradeable} to add upgradeability support to your contracts.

Expand All @@ -49,35 +49,55 @@ NOTE: We will be using the following module to implement the {i_upgradeable} int
----
#[starknet::contract]
mod UpgradeableContract {
use openzeppelin::access::ownable::Ownable;
use openzeppelin::upgrades::Upgradeable;
use openzeppelin::access::ownable::Ownable as ownable_component;
use openzeppelin::upgrades::Upgradeable as upgradeable_component;
use openzeppelin::upgrades::interface::IUpgradeable;
use starknet::ClassHash;
use starknet::ContractAddress;

component!(path: ownable_component, storage: ownable, event: OwnableEvent);
component!(path: upgradeable_component, storage: upgradeable, event: UpgradeableEvent);

/// Ownable
#[abi(embed_v0)]
impl OwnableImpl = ownable_component::OwnableImpl<ContractState>;
impl OwnableInternalImpl = ownable_component::InternalImpl<ContractState>;

/// Upgradeable
impl UpgradeableInternalImpl = upgradeable_component::InternalImpl<ContractState>;

#[storage]
struct Storage {}
struct Storage {
#[substorage(v0)]
ownable: ownable_component::Storage,
#[substorage(v0)]
upgradeable: upgradeable_component::Storage
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
OwnableEvent: ownable_component::Event,
#[flat]
UpgradeableEvent: upgradeable_component::Event
}

#[constructor]
fn constructor(self: @ContractState, owner: ContractAddress) {
let mut unsafe_state = Ownable::unsafe_new_contract_state();
Ownable::InternalImpl::initializer(ref unsafe_state, owner);
fn constructor(ref self: ContractState, owner: ContractAddress) {
self.ownable.initializer(owner);
}

#[external(v0)]
impl UpgradeableImpl of IUpgradeable<ContractState> {
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {
// This function can only be called by the owner
let ownable_state = Ownable::unsafe_new_contract_state();
Ownable::InternalImpl::assert_only_owner(@ownable_state);
self.ownable.assert_only_owner();

// Replace the class hash upgrading the contract
let mut upgradeable_state = Upgradeable::unsafe_new_contract_state();
Upgradeable::InternalImpl::_upgrade(ref upgradeable_state, new_class_hash);
self.upgradeable._upgrade(new_class_hash);
}
}

(...)
}
----

Expand Down
3 changes: 1 addition & 2 deletions src/tests/mocks.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,4 @@ mod snake20_mock;
mod snake721_mock;
mod snake_account_mock;
mod src5_mocks;
mod upgrades_v1;
mod upgrades_v2;
mod upgrades_mocks;
6 changes: 6 additions & 0 deletions src/tests/mocks/accesscontrol_mocks.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ mod DualCaseAccessControlMock {
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
AccessControlEvent: accesscontrol_component::Event,
#[flat]
SRC5Event: src5_component::Event
}

Expand Down Expand Up @@ -69,7 +71,9 @@ mod SnakeAccessControlMock {
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
AccessControlEvent: accesscontrol_component::Event,
#[flat]
SRC5Event: src5_component::Event
}

Expand Down Expand Up @@ -109,7 +113,9 @@ mod CamelAccessControlMock {
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
AccessControlEvent: accesscontrol_component::Event,
#[flat]
SRC5Event: src5_component::Event
}

Expand Down
1 change: 1 addition & 0 deletions src/tests/mocks/initializable_mock.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod InitializableMock {
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
InitializableEvent: initializable_component::Event
}
}
3 changes: 3 additions & 0 deletions src/tests/mocks/ownable_mocks.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mod DualCaseOwnableMock {
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
OwnableEvent: ownable_component::Event
}

Expand Down Expand Up @@ -50,6 +51,7 @@ mod SnakeOwnableMock {
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
OwnableEvent: ownable_component::Event
}

Expand Down Expand Up @@ -80,6 +82,7 @@ mod CamelOwnableMock {
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
OwnableEvent: ownable_component::Event
}

Expand Down
1 change: 1 addition & 0 deletions src/tests/mocks/pausable_mock.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod PausableMock {
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
PausableEvent: pausable_component::Event
}
}
1 change: 1 addition & 0 deletions src/tests/mocks/reentrancy_mock.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ mod ReentrancyMock {
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
ReentrancyGuardEvent: reentrancy_guard_component::Event
}

Expand Down
3 changes: 3 additions & 0 deletions src/tests/mocks/src5_mocks.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mod DualCaseSRC5Mock {
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
SRC5Event: src5_component::Event
}
}
Expand All @@ -43,6 +44,7 @@ mod SnakeSRC5Mock {
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
SRC5Event: src5_component::Event
}
}
Expand All @@ -65,6 +67,7 @@ mod CamelSRC5Mock {
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
SRC5Event: src5_component::Event
}
}
Expand Down
128 changes: 128 additions & 0 deletions src/tests/mocks/upgrades_mocks.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// These contracts are mocks used to test the core functionality of the upgrade functions.
// The functions are NOT PROTECTED.
// DO NOT USE IN PRODUCTION.

use starknet::ClassHash;

#[starknet::interface]
trait IUpgradesV1<TState> {
fn upgrade(ref self: TState, new_class_hash: ClassHash);
fn set_value(ref self: TState, val: felt252);
fn get_value(self: @TState) -> felt252;
fn remove_selector(self: @TState);
}

trait UpgradesV1Trait<TState> {
fn set_value(ref self: TState, val: felt252);
fn get_value(self: @TState) -> felt252;
fn remove_selector(self: @TState);
}

#[starknet::contract]
mod UpgradesV1 {
use openzeppelin::upgrades::Upgradeable as upgradeable_component;
use starknet::ClassHash;
use starknet::ContractAddress;

component!(path: upgradeable_component, storage: upgradeable, event: UpgradeableEvent);

impl InternalImpl = upgradeable_component::InternalImpl<ContractState>;

#[storage]
struct Storage {
#[substorage(v0)]
upgradeable: upgradeable_component::Storage,
value: felt252
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
UpgradeableEvent: upgradeable_component::Event
}

#[external(v0)]
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {
self.upgradeable._upgrade(new_class_hash);
}

#[external(v0)]
impl UpgradesV1Impl of super::UpgradesV1Trait<ContractState> {
fn set_value(ref self: ContractState, val: felt252) {
self.value.write(val);
}

fn get_value(self: @ContractState) -> felt252 {
self.value.read()
}

fn remove_selector(self: @ContractState) {}
}
}

#[starknet::interface]
trait IUpgradesV2<TState> {
fn upgrade(ref self: TState, new_class_hash: ClassHash);
fn set_value(ref self: TState, val: felt252);
fn set_value2(ref self: TState, val: felt252);
fn get_value(self: @TState) -> felt252;
fn get_value2(self: @TState) -> felt252;
}

trait UpgradesV2Trait<TState> {
fn set_value(ref self: TState, val: felt252);
fn set_value2(ref self: TState, val: felt252);
fn get_value(self: @TState) -> felt252;
fn get_value2(self: @TState) -> felt252;
}

#[starknet::contract]
mod UpgradesV2 {
use openzeppelin::upgrades::Upgradeable as upgradeable_component;
use starknet::ClassHash;
use starknet::ContractAddress;

component!(path: upgradeable_component, storage: upgradeable, event: UpgradeableEvent);

impl InternalImpl = upgradeable_component::InternalImpl<ContractState>;

#[storage]
struct Storage {
#[substorage(v0)]
upgradeable: upgradeable_component::Storage,
value: felt252,
value2: felt252
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
UpgradeableEvent: upgradeable_component::Event
}

#[external(v0)]
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {
self.upgradeable._upgrade(new_class_hash);
}

#[external(v0)]
impl UpgradesV2Impl of super::UpgradesV2Trait<ContractState> {
fn set_value(ref self: ContractState, val: felt252) {
self.value.write(val);
}

fn set_value2(ref self: ContractState, val: felt252) {
self.value2.write(val);
}

fn get_value(self: @ContractState) -> felt252 {
self.value.read()
}

fn get_value2(self: @ContractState) -> felt252 {
self.value2.read()
}
}
}
Loading