Skip to content

Commit

Permalink
feat: makes models upgradeable
Browse files Browse the repository at this point in the history
  • Loading branch information
remybar committed Oct 2, 2024
1 parent 25f1376 commit bc265e8
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 155 deletions.
53 changes: 30 additions & 23 deletions crates/compiler/src/attribute_macros/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,15 +178,29 @@ impl DojoContract {
use dojo::world;
use dojo::world::IWorldDispatcher;
use dojo::world::IWorldDispatcherTrait;
use dojo::world::IWorldProvider;
use dojo::components::world_provider::{IWorldProvider, WorldProviderComponent};
use dojo::components::upgradeable::upgradeable;
use dojo::contract::IContract;
use starknet::storage::{
StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, \
StoragePointerWriteAccess
};
component!(path: dojo::contract::upgradeable::upgradeable, storage: \
upgradeable, event: UpgradeableEvent);
component!(path: WorldProviderComponent, storage: world_provider, event: WorldProviderEvent);
component!(path: upgradeable, storage: upgradeable, event: UpgradeableEvent);
#[abi(embed_v0)]
impl WorldProviderImpl = WorldProviderComponent::WorldProviderImpl<ContractState>;
impl WorldProviderInternalImpl = WorldProviderComponent::InternalImpl<ContractState>;
#[abi(embed_v0)]
impl UpgradableImpl = upgradeable::UpgradableImpl<ContractState>;
#[constructor]
fn constructor(ref self: ContractState) {
self.world_provider.initializer();
}
#[abi(embed_v0)]
pub impl ContractImpl of IContract<ContractState> {
Expand Down Expand Up @@ -215,17 +229,6 @@ impl DojoContract {
}
}
#[abi(embed_v0)]
impl WorldProviderImpl of IWorldProvider<ContractState> {
fn world(self: @ContractState) -> IWorldDispatcher {
self.world_dispatcher.read()
}
}
#[abi(embed_v0)]
impl UpgradableImpl = \
dojo::contract::upgradeable::upgradeable::UpgradableImpl<ContractState>;
$body$
}
",
Expand Down Expand Up @@ -338,7 +341,7 @@ impl DojoContract {
};

let world_line_node = if was_world_injected {
RewriteNode::Text("let world = self.world_dispatcher.read();".to_string())
RewriteNode::Text("let world = self.world();".to_string())
} else {
RewriteNode::empty()
};
Expand Down Expand Up @@ -395,7 +398,8 @@ impl DojoContract {
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
UpgradeableEvent: dojo::contract::upgradeable::upgradeable::Event,
WorldProviderEvent: WorldProviderComponent::Event,
UpgradeableEvent: upgradeable::Event,
$variants$
}
",
Expand All @@ -410,7 +414,8 @@ impl DojoContract {
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
UpgradeableEvent: dojo::contract::upgradeable::upgradeable::Event,
WorldProviderEvent: WorldProviderComponent::Event,
UpgradeableEvent: upgradeable::Event,
}
"
.to_string(),
Expand All @@ -436,9 +441,10 @@ impl DojoContract {
"
#[storage]
struct Storage {
world_dispatcher: IWorldDispatcher,
#[substorage(v0)]
upgradeable: dojo::contract::upgradeable::upgradeable::Storage,
world_provider: WorldProviderComponent::Storage,
#[substorage(v0)]
upgradeable: upgradeable::Storage,
$members$
}
",
Expand All @@ -452,9 +458,10 @@ impl DojoContract {
"
#[storage]
struct Storage {
world_dispatcher: IWorldDispatcher,
#[substorage(v0)]
upgradeable: dojo::contract::upgradeable::upgradeable::Storage,
world_provider: WorldProviderComponent::Storage,
#[substorage(v0)]
upgradeable: upgradeable::Storage,
}
"
.to_string(),
Expand Down Expand Up @@ -537,7 +544,7 @@ impl DojoContract {
/// Rewrites function declaration by:
/// * adding `self` parameter if missing,
/// * removing `world` if present as first parameter (self excluded),
/// * adding `let world = self.world_dispatcher.read();` statement at the beginning of the
/// * adding `let world = self.world();` statement at the beginning of the
/// function to restore the removed `world` parameter.
/// * if `has_generate_trait` is true, the implementation containing the function has the
/// #[generate_trait] attribute.
Expand Down Expand Up @@ -578,7 +585,7 @@ impl DojoContract {
};

let world_line_node = if was_world_injected {
RewriteNode::Text("let world = self.world_dispatcher.read();".to_string())
RewriteNode::Text("let world = self.world();".to_string())
} else {
RewriteNode::empty()
};
Expand Down
31 changes: 30 additions & 1 deletion crates/compiler/src/attribute_macros/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -731,9 +731,38 @@ pub trait I$contract_name$<T> {
pub mod $contract_name$ {
use super::$type_name$;
use super::I$contract_name$;
use dojo::components::world_provider::{IWorldProvider, WorldProviderComponent};
use dojo::components::upgradeable::upgradeable;
component!(path: WorldProviderComponent, storage: world_provider, event: WorldProviderEvent);
component!(path: upgradeable, storage: upgradeable, event: UpgradeableEvent);
#[abi(embed_v0)]
impl WorldProviderImpl = WorldProviderComponent::WorldProviderImpl<ContractState>;
impl WorldProviderInternalImpl = WorldProviderComponent::InternalImpl<ContractState>;
#[abi(embed_v0)]
impl UpgradableImpl = upgradeable::UpgradableImpl<ContractState>;
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
WorldProviderEvent: WorldProviderComponent::Event,
UpgradeableEvent: upgradeable::Event,
}
#[storage]
struct Storage {}
struct Storage {
#[substorage(v0)]
world_provider: WorldProviderComponent::Storage,
#[substorage(v0)]
upgradeable: upgradeable::Storage,
}
#[constructor]
fn constructor(ref self: ContractState) {
self.world_provider.initializer();
}
#[abi(embed_v0)]
impl DojoModelImpl of dojo::model::IModel<ContractState>{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ pub mod upgradeable {
use starknet::{ClassHash, ContractAddress, get_caller_address};
use starknet::syscalls::replace_class_syscall;

use dojo::world::{IWorldProvider, IWorldProviderDispatcher, IWorldDispatcher};
use dojo::components::world_provider::{IWorldProvider, IWorldProviderDispatcher};
use dojo::world::IWorldDispatcher;

#[storage]
pub struct Storage {}
Expand Down
37 changes: 37 additions & 0 deletions crates/contracts/src/components/world_provider.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use dojo::world::IWorldDispatcher;

#[starknet::interface]
pub trait IWorldProvider<T> {
fn world(self: @T) -> IWorldDispatcher;
}

#[starknet::component]
pub mod WorldProviderComponent {
use starknet::{ClassHash, ContractAddress, get_caller_address};
use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess};

use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait};

#[storage]
pub struct Storage {
world_dispatcher: IWorldDispatcher,
}

#[embeddable_as(WorldProviderImpl)]
impl WorldProvider<
TContractState, +HasComponent<TContractState>
> of super::IWorldProvider<ComponentState<TContractState>> {
fn world(self: @ComponentState<TContractState>) -> IWorldDispatcher {
self.world_dispatcher.read()
}
}

#[generate_trait]
pub impl InternalImpl<
TContractState, +HasComponent<TContractState>
> of InternalTrait<TContractState> {
fn initializer(ref self: ComponentState<TContractState>) {
self.world_dispatcher.write(IWorldDispatcher { contract_address: get_caller_address() });
}
}
}
39 changes: 0 additions & 39 deletions crates/contracts/src/contract/base_contract.cairo

This file was deleted.

11 changes: 6 additions & 5 deletions crates/contracts/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
pub mod components {
pub mod world_provider;
pub mod upgradeable;
}

pub mod contract {
mod base_contract;
pub use base_contract::base;
pub mod contract;
pub use contract::{IContract, IContractDispatcher, IContractDispatcherTrait};
pub mod upgradeable;
}

pub mod model {
Expand Down Expand Up @@ -59,8 +61,7 @@ pub mod world {

mod world_contract;
pub use world_contract::{
world, IWorld, IWorldDispatcher, IWorldDispatcherTrait, IWorldProvider,
IWorldProviderDispatcher, IWorldProviderDispatcherTrait, Resource,
world, IWorld, IWorldDispatcher, IWorldDispatcherTrait, Resource,
};
pub(crate) use world_contract::{
IUpgradeableWorld, IUpgradeableWorldDispatcher, IUpgradeableWorldDispatcherTrait
Expand Down
6 changes: 3 additions & 3 deletions crates/contracts/src/tests/base.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ use core::traits::TryInto;

use starknet::ClassHash;

use dojo::contract::base;
use dojo::contract::upgradeable::{IUpgradeableDispatcher, IUpgradeableDispatcherTrait};
use dojo::components::upgradeable::{IUpgradeableDispatcher, IUpgradeableDispatcherTrait};
use dojo::utils::test::{spawn_test_world};
use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait};


#[starknet::contract]
pub mod contract_upgrade {
use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait, IWorldProvider};
use dojo::components::world_provider::IWorldProvider;
use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait};

#[storage]
struct Storage {}
Expand Down
10 changes: 4 additions & 6 deletions crates/contracts/src/tests/world/resources.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -193,14 +193,12 @@ fn test_upgrade_model_from_model_owner() {

drop_all_events(world.contract_address);

world.upgrade_model(foo::TEST_CLASS_HASH.try_into().unwrap());
world.upgrade_model(Model::<Foo>::selector(), foo::TEST_CLASS_HASH.try_into().unwrap());

let event = starknet::testing::pop_log::<ModelUpgraded>(world.contract_address);

assert(event.is_some(), 'no ModelRegistered event');
assert(event.is_some(), 'no ModelUpgraded event');
let event = event.unwrap();
assert(event.name == Model::<Foo>::name(), 'bad model name');
assert(event.namespace == Model::<Foo>::namespace(), 'bad model namespace');
assert(event.class_hash == foo::TEST_CLASS_HASH.try_into().unwrap(), 'bad model class_hash');
assert(
event.address != core::num::traits::Zero::<ContractAddress>::zero(),
Expand All @@ -213,7 +211,7 @@ fn test_upgrade_model_from_model_owner() {
#[test]
#[should_panic(
expected: (
"Caller `2827` cannot upgrade the resource `3123252206139358744730647958636922105676576163624049771737508399526017186883` (not owner)",
"Caller `2827` is not the owner of the resource `3123252206139358744730647958636922105676576163624049771737508399526017186883`",
'ENTRYPOINT_FAILED',
)
)]
Expand All @@ -229,7 +227,7 @@ fn test_upgrade_model_from_model_writer() {

starknet::testing::set_account_contract_address(bob);
starknet::testing::set_contract_address(bob);
world.upgrade_model(foo::TEST_CLASS_HASH.try_into().unwrap());
world.upgrade_model(Model::<Foo>::selector(), foo::TEST_CLASS_HASH.try_into().unwrap());

starknet::testing::set_account_contract_address(alice);
starknet::testing::set_contract_address(alice);
Expand Down
3 changes: 1 addition & 2 deletions crates/contracts/src/utils/test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use core::traits::{Into, TryInto};

use starknet::{ClassHash, ContractAddress, syscalls::deploy_syscall, get_caller_address};

use dojo::contract::base;
use dojo::model::resource_metadata;
use dojo::storage::packing::{shl, shr};
use dojo::world::{world, IWorldDispatcher, IWorldDispatcherTrait};
Expand Down Expand Up @@ -56,7 +55,7 @@ pub fn spawn_test_world(namespaces: Span<ByteArray>, models: Span<felt252>) -> I
let (world_address, _) = deploy_syscall(
world::TEST_CLASS_HASH.try_into().unwrap(),
salt.into(),
[base::TEST_CLASS_HASH].span(),
[].span(),
false
)
.unwrap();
Expand Down
Loading

0 comments on commit bc265e8

Please sign in to comment.