diff --git a/crates/dojo-core/src/base.cairo b/crates/dojo-core/src/base.cairo index 9b6a58f621..d5265b31bd 100644 --- a/crates/dojo-core/src/base.cairo +++ b/crates/dojo-core/src/base.cairo @@ -1,20 +1,26 @@ use dojo::world::IWorldDispatcher; -#[starknet::interface] -trait IBase { - fn world(self: @T) -> IWorldDispatcher; -} - #[starknet::contract] mod base { use starknet::{ClassHash, get_caller_address}; - - use dojo::upgradable::{IUpgradeable, UpgradeableTrait}; use dojo::world::IWorldDispatcher; + use dojo::world::IWorldProvider; + + use dojo::components::upgradeable::upgradeable as upgradeable_component; + + component!(path: upgradeable_component, storage: upgradeable, event: UpgradeableEvent); + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + UpgradeableEvent: upgradeable_component::Event + } #[storage] struct Storage { world_dispatcher: IWorldDispatcher, + #[substorage(v0)] + upgradeable: upgradeable_component::Storage, } #[constructor] @@ -23,19 +29,12 @@ mod base { } #[external(v0)] - fn world(self: @ContractState) -> IWorldDispatcher { - self.world_dispatcher.read() - } - - #[external(v0)] - impl Upgradeable of IUpgradeable { - /// Upgrade contract implementation to new_class_hash - /// - /// # Arguments - /// - /// * `new_class_hash` - The new implementation class hahs. - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) { - UpgradeableTrait::upgrade(new_class_hash); + impl WorldProviderImpl of IWorldProvider { + fn world(self: @ContractState) -> IWorldDispatcher { + self.world_dispatcher.read() } } + + #[abi(embed_v0)] + impl UpgradableImpl = upgradeable_component::UpgradableImpl; } diff --git a/crates/dojo-core/src/base_test.cairo b/crates/dojo-core/src/base_test.cairo index 691ad3bac6..2a86667870 100644 --- a/crates/dojo-core/src/base_test.cairo +++ b/crates/dojo-core/src/base_test.cairo @@ -3,8 +3,10 @@ use starknet::ClassHash; use traits::TryInto; use dojo::base::base; -use dojo::upgradable::{IUpgradeableDispatcher, IUpgradeableDispatcherTrait}; -use dojo::test_utils::deploy_contract; +use dojo::components::upgradeable::{IUpgradeableDispatcher, IUpgradeableDispatcherTrait}; +use dojo::test_utils::{spawn_test_world}; +use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; + #[starknet::contract] mod contract_upgrade { @@ -29,15 +31,34 @@ mod contract_upgrade { use contract_upgrade::{IQuantumLeapDispatcher, IQuantumLeapDispatcherTrait}; +// Utils +fn deploy_world() -> IWorldDispatcher { + spawn_test_world(array![]) +} + #[test] #[available_gas(6000000)] -fn test_upgrade() { - let base_address = deploy_contract(base::TEST_CLASS_HASH, array![].span()); - let upgradable_dispatcher = IUpgradeableDispatcher { contract_address: base_address }; +fn test_upgrade_from_world() { + let world = deploy_world(); + let base_address = world.deploy_contract('salt', base::TEST_CLASS_HASH.try_into().unwrap()); let new_class_hash: ClassHash = contract_upgrade::TEST_CLASS_HASH.try_into().unwrap(); - upgradable_dispatcher.upgrade(new_class_hash); + + world.upgrade_contract(base_address, new_class_hash); let quantum_dispatcher = IQuantumLeapDispatcher { contract_address: base_address }; assert(quantum_dispatcher.plz_more_tps() == 'daddy', 'quantum leap failed'); } + +#[test] +#[available_gas(6000000)] +#[should_panic(expected: ('must be called by world', 'ENTRYPOINT_FAILED'))] +fn test_upgrade_direct() { + let world = deploy_world(); + + let base_address = world.deploy_contract('salt', base::TEST_CLASS_HASH.try_into().unwrap()); + let new_class_hash: ClassHash = contract_upgrade::TEST_CLASS_HASH.try_into().unwrap(); + + let upgradeable_dispatcher = IUpgradeableDispatcher { contract_address: base_address }; + upgradeable_dispatcher.upgrade(new_class_hash); +} diff --git a/crates/dojo-core/src/components.cairo b/crates/dojo-core/src/components.cairo new file mode 100644 index 0000000000..bd830eac21 --- /dev/null +++ b/crates/dojo-core/src/components.cairo @@ -0,0 +1 @@ +mod upgradeable; \ No newline at end of file diff --git a/crates/dojo-core/src/components/upgradeable.cairo b/crates/dojo-core/src/components/upgradeable.cairo new file mode 100644 index 0000000000..c5a030f12f --- /dev/null +++ b/crates/dojo-core/src/components/upgradeable.cairo @@ -0,0 +1,56 @@ +use starknet::ClassHash; + +#[starknet::interface] +trait IUpgradeable { + fn upgrade(ref self: T, new_class_hash: ClassHash); +} + +#[starknet::component] +mod upgradeable { + use starknet::ClassHash; + use starknet::ContractAddress; + use starknet::get_caller_address; + use starknet::syscalls::replace_class_syscall; + use dojo::world::{IWorldProvider, IWorldProviderDispatcher, IWorldDispatcher}; + + #[storage] + struct Storage {} + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + Upgraded: Upgraded, + } + + #[derive(Drop, starknet::Event)] + struct Upgraded { + class_hash: ClassHash + } + + mod Errors { + const INVALID_CLASS: felt252 = 'class_hash cannot be zero'; + const INVALID_CALLER: felt252 = 'must be called by world'; + const INVALID_WORLD_ADDRESS: felt252 = 'invalid world address'; + } + + #[embeddable_as(UpgradableImpl)] + impl Upgradable< + TContractState, +HasComponent, +IWorldProvider + > of super::IUpgradeable> { + fn upgrade(ref self: ComponentState, new_class_hash: ClassHash) { + assert( + self.get_contract().world().contract_address.is_non_zero(), + Errors::INVALID_WORLD_ADDRESS + ); + assert( + get_caller_address() == self.get_contract().world().contract_address, + Errors::INVALID_CALLER + ); + assert(new_class_hash.is_non_zero(), Errors::INVALID_CLASS); + + replace_class_syscall(new_class_hash).unwrap(); + + self.emit(Upgraded { class_hash: new_class_hash }); + } + } +} diff --git a/crates/dojo-core/src/lib.cairo b/crates/dojo-core/src/lib.cairo index 6e3301c6ee..8a8ba0918d 100644 --- a/crates/dojo-core/src/lib.cairo +++ b/crates/dojo-core/src/lib.cairo @@ -14,10 +14,11 @@ mod packing_test; mod world; #[cfg(test)] mod world_test; -mod upgradable; #[cfg(test)] mod test_utils; #[cfg(test)] -mod benchmarks; \ No newline at end of file +mod benchmarks; + +mod components; \ No newline at end of file diff --git a/crates/dojo-core/src/upgradable.cairo b/crates/dojo-core/src/upgradable.cairo deleted file mode 100644 index 1a446770d8..0000000000 --- a/crates/dojo-core/src/upgradable.cairo +++ /dev/null @@ -1,19 +0,0 @@ -use starknet::{ClassHash, SyscallResult, SyscallResultTrait}; -use zeroable::Zeroable; -use result::ResultTrait; - -#[starknet::interface] -trait IUpgradeable { - fn upgrade(ref self: T, new_class_hash: ClassHash); -} - -trait UpgradeableTrait { - fn upgrade(new_class_hash: ClassHash); -} - -impl UpgradeableTraitImpl of UpgradeableTrait { - fn upgrade(new_class_hash: ClassHash) { - assert(new_class_hash.is_non_zero(), 'class_hash cannot be zero'); - starknet::replace_class_syscall(new_class_hash).unwrap_syscall(); - } -} diff --git a/crates/dojo-core/src/world.cairo b/crates/dojo-core/src/world.cairo index d38df35d3f..53094323c8 100644 --- a/crates/dojo-core/src/world.cairo +++ b/crates/dojo-core/src/world.cairo @@ -45,6 +45,12 @@ trait IWorld { fn revoke_writer(ref self: T, model: felt252, system: ContractAddress); } +#[starknet::interface] +trait IWorldProvider { + fn world(self: @T) -> IWorldDispatcher; +} + + #[starknet::contract] mod world { use core::traits::TryInto; @@ -66,9 +72,9 @@ mod world { use dojo::database; use dojo::database::index::WhereCondition; use dojo::executor::{IExecutorDispatcher, IExecutorDispatcherTrait}; - use dojo::upgradable::{IUpgradeableDispatcher, IUpgradeableDispatcherTrait}; use dojo::world::{IWorldDispatcher, IWorld}; - + + use dojo::components::upgradeable::{IUpgradeableDispatcher, IUpgradeableDispatcherTrait}; const NAME_ENTRYPOINT: felt252 = 0x0361458367e696363fbcc70777d07ebbd2394e89fd0adcaf147faccd1d294d60; @@ -404,8 +410,8 @@ mod world { self.contract_base.read(), salt, array![].span(), false ) .unwrap_syscall(); - let upgradable_dispatcher = IUpgradeableDispatcher { contract_address }; - upgradable_dispatcher.upgrade(class_hash); + let upgradeable_dispatcher = IUpgradeableDispatcher { contract_address }; + upgradeable_dispatcher.upgrade(class_hash); self.owners.write((contract_address.into(), get_caller_address()), true); diff --git a/crates/dojo-lang/src/contract.rs b/crates/dojo-lang/src/contract.rs index 8436eeb735..9880b4efc6 100644 --- a/crates/dojo-lang/src/contract.rs +++ b/crates/dojo-lang/src/contract.rs @@ -6,7 +6,7 @@ use cairo_lang_defs::plugin::{ }; // use cairo_lang_syntax::node::ast::{MaybeModuleBody, Param}; use cairo_lang_syntax::node::ast::MaybeModuleBody; -use cairo_lang_syntax::node::ast::OptionReturnTypeClause::ReturnTypeClause; +// use cairo_lang_syntax::node::ast::OptionReturnTypeClause::ReturnTypeClause; use cairo_lang_syntax::node::db::SyntaxGroup; use cairo_lang_syntax::node::{ast, Terminal, TypedSyntaxNode}; use cairo_lang_utils::unordered_hash_map::UnorderedHashMap; @@ -23,16 +23,18 @@ impl DojoContract { pub fn from_module(db: &dyn SyntaxGroup, module_ast: ast::ItemModule) -> PluginResult { let name = module_ast.name(db).text(db); let mut system = DojoContract { diagnostics: vec![], dependencies: HashMap::new() }; + let mut has_event = false; if let MaybeModuleBody::Some(body) = module_ast.body(db) { - let body_nodes = body + let mut body_nodes: Vec<_> = body .items(db) .elements(db) .iter() .flat_map(|el| { - if let ast::Item::FreeFunction(fn_ast) = el { - if fn_ast.declaration(db).name(db).text(db).to_string() == "execute" { - return system.handle_execute(db, fn_ast.clone()); + if let ast::Item::Enum(enum_ast) = el { + if enum_ast.name(db).text(db).to_string() == "Event" { + has_event = true; + return system.merge_event(db, enum_ast.clone()); } } @@ -40,6 +42,10 @@ impl DojoContract { }) .collect(); + if !has_event { + body_nodes.append(&mut system.create_event()) + } + let mut builder = PatchBuilder::new(db); builder.add_modified(RewriteNode::interpolate_patched( " @@ -48,10 +54,17 @@ impl DojoContract { use dojo::world; use dojo::world::IWorldDispatcher; use dojo::world::IWorldDispatcherTrait; + use dojo::world::IWorldProvider; + + component!(path: dojo::components::upgradeable::upgradeable, storage: \ + upgradeable, event: UpgradeableEvent); + #[storage] struct Storage { world_dispatcher: IWorldDispatcher, + #[substorage(v0)] + upgradeable: dojo::components::upgradeable::upgradeable::Storage, } #[external(v0)] @@ -60,17 +73,16 @@ impl DojoContract { } #[external(v0)] - impl Upgradeable of dojo::upgradable::IUpgradeable { - fn upgrade(ref self: ContractState, new_class_hash: starknet::ClassHash) { - let caller = starknet::get_caller_address(); - assert( - self.world_dispatcher.read().contract_address == caller, 'only \ - World can upgrade' - ); - dojo::upgradable::UpgradeableTrait::upgrade(new_class_hash); + impl WorldProviderImpl of IWorldProvider { + fn world(self: @ContractState) -> IWorldDispatcher { + self.world_dispatcher.read() } } + #[abi(embed_v0)] + impl UpgradableImpl = \ + dojo::components::upgradeable::upgradeable::UpgradableImpl; + $body$ } ", @@ -101,60 +113,44 @@ impl DojoContract { PluginResult::default() } - pub fn handle_execute( + pub fn merge_event( &mut self, db: &dyn SyntaxGroup, - function_ast: ast::FunctionWithBody, + enum_ast: ast::ItemEnum, ) -> Vec { let mut rewrite_nodes = vec![]; - let signature = function_ast.declaration(db).signature(db); - - let parameters = signature.parameters(db); - let elements = parameters.elements(db); - - // let mut context = "_ctx: dojo::world::Context".to_string(); - // if let Some(first) = elements.first() { - // // If context is first, move it to last. - // if is_context(db, first) { - // let ctx = elements.remove(0); - // context = ctx.as_syntax_node().get_text(db); - // } - // } else if let Some(param) = elements.iter().find(|p| is_context(db, p)) { - // // Context not the first element, but exists. - // self.diagnostics.push(PluginDiagnostic { - // message: "Context must be first parameter when provided".into(), - // stable_ptr: param.stable_ptr().untyped(), - // }); - // } - - let params = elements.iter().map(|e| e.as_syntax_node().get_text(db)).collect::>(); - // params.push(context); - let params = params.join(", "); - - let ret_clause = if let ReturnTypeClause(clause) = signature.ret_ty(db) { - RewriteNode::new_trimmed(clause.as_syntax_node()) - } else { - RewriteNode::Text("".to_string()) - }; + let elements = enum_ast.variants(db).elements(db); + + let variants = elements.iter().map(|e| e.as_syntax_node().get_text(db)).collect::>(); + let variants = variants.join(", "); rewrite_nodes.push(RewriteNode::interpolate_patched( " - #[external(v0)] - fn execute(self: @ContractState, $params$) $ret_clause$ $body$ + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + UpgradeableEvent: dojo::components::upgradeable::upgradeable::Event, + $variants$ + } ", - &UnorderedHashMap::from([ - ("params".to_string(), RewriteNode::Text(params)), - ( - "body".to_string(), - RewriteNode::new_trimmed(function_ast.body(db).as_syntax_node()), - ), - ("ret_clause".to_string(), ret_clause), - ]), + &UnorderedHashMap::from([("variants".to_string(), RewriteNode::Text(variants))]), )); - rewrite_nodes } + + pub fn create_event(&mut self) -> Vec { + vec![RewriteNode::Text( + " + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + UpgradeableEvent: dojo::components::upgradeable::upgradeable::Event, + } + " + .to_string(), + )] + } } // fn is_context(db: &dyn SyntaxGroup, param: &Param) -> bool { diff --git a/crates/dojo-lang/src/manifest_test_data/manifest b/crates/dojo-lang/src/manifest_test_data/manifest index 1393fe2cdf..5a491c57f8 100644 --- a/crates/dojo-lang/src/manifest_test_data/manifest +++ b/crates/dojo-lang/src/manifest_test_data/manifest @@ -8,7 +8,7 @@ test_manifest_file "world": { "name": "world", "address": null, - "class_hash": "0x481a9c7b128847a520bb234d93ef8a83b462de03fce7089eb4ed9135d2f31d9", + "class_hash": "0xb3e374b8087dca92601afbb9881fed855ac0d568e3bf878a876fca5ffcb479", "abi": [ { "type": "impl", @@ -811,16 +811,48 @@ test_manifest_file }, "base": { "name": "base", - "class_hash": "0x5a2c567ed06c8059c8d1199684796a0a0ef614f9a2ab628700e804524816b5c", + "class_hash": "0x77638e9a645209ac1e32e143bfdbfe9caf723c4f7645fcf465c38967545ea2f", "abi": [ { "type": "impl", - "name": "Upgradeable", - "interface_name": "dojo::upgradable::IUpgradeable" + "name": "WorldProviderImpl", + "interface_name": "dojo::world::IWorldProvider" + }, + { + "type": "struct", + "name": "dojo::world::IWorldDispatcher", + "members": [ + { + "name": "contract_address", + "type": "core::starknet::contract_address::ContractAddress" + } + ] + }, + { + "type": "interface", + "name": "dojo::world::IWorldProvider", + "items": [ + { + "type": "function", + "name": "world", + "inputs": [], + "outputs": [ + { + "type": "dojo::world::IWorldDispatcher" + } + ], + "state_mutability": "view" + } + ] + }, + { + "type": "impl", + "name": "UpgradableImpl", + "interface_name": "dojo::components::upgradeable::IUpgradeable" }, { "type": "interface", - "name": "dojo::upgradable::IUpgradeable", + "name": "dojo::components::upgradeable::IUpgradeable", "items": [ { "type": "function", @@ -842,31 +874,40 @@ test_manifest_file "inputs": [] }, { - "type": "struct", - "name": "dojo::world::IWorldDispatcher", + "type": "event", + "name": "dojo::components::upgradeable::upgradeable::Upgraded", + "kind": "struct", "members": [ { - "name": "contract_address", - "type": "core::starknet::contract_address::ContractAddress" + "name": "class_hash", + "type": "core::starknet::class_hash::ClassHash", + "kind": "data" } ] }, { - "type": "function", - "name": "world", - "inputs": [], - "outputs": [ + "type": "event", + "name": "dojo::components::upgradeable::upgradeable::Event", + "kind": "enum", + "variants": [ { - "type": "dojo::world::IWorldDispatcher" + "name": "Upgraded", + "type": "dojo::components::upgradeable::upgradeable::Upgraded", + "kind": "nested" } - ], - "state_mutability": "view" + ] }, { "type": "event", "name": "dojo::base::base::Event", "kind": "enum", - "variants": [] + "variants": [ + { + "name": "UpgradeableEvent", + "type": "dojo::components::upgradeable::upgradeable::Event", + "kind": "nested" + } + ] } ] }, @@ -874,28 +915,37 @@ test_manifest_file { "name": "actions", "address": null, - "class_hash": "0x308ad5fcd288ea5ded168bbc502261d75458c13fa1df552bd41ca3d86347dfe", + "class_hash": "0x1f740b30fc835ecf509a40e8dc8e4eb7ada046243833d2060f17ab961e4e154", "abi": [ { "type": "impl", - "name": "Upgradeable", - "interface_name": "dojo::upgradable::IUpgradeable" + "name": "WorldProviderImpl", + "interface_name": "dojo::world::IWorldProvider" + }, + { + "type": "struct", + "name": "dojo::world::IWorldDispatcher", + "members": [ + { + "name": "contract_address", + "type": "core::starknet::contract_address::ContractAddress" + } + ] }, { "type": "interface", - "name": "dojo::upgradable::IUpgradeable", + "name": "dojo::world::IWorldProvider", "items": [ { "type": "function", - "name": "upgrade", - "inputs": [ + "name": "world", + "inputs": [], + "outputs": [ { - "name": "new_class_hash", - "type": "core::starknet::class_hash::ClassHash" + "type": "dojo::world::IWorldDispatcher" } ], - "outputs": [], - "state_mutability": "external" + "state_mutability": "view" } ] }, @@ -955,6 +1005,29 @@ test_manifest_file } ] }, + { + "type": "impl", + "name": "UpgradableImpl", + "interface_name": "dojo::components::upgradeable::IUpgradeable" + }, + { + "type": "interface", + "name": "dojo::components::upgradeable::IUpgradeable", + "items": [ + { + "type": "function", + "name": "upgrade", + "inputs": [ + { + "name": "new_class_hash", + "type": "core::starknet::class_hash::ClassHash" + } + ], + "outputs": [], + "state_mutability": "external" + } + ] + }, { "type": "function", "name": "dojo_resource", @@ -1026,6 +1099,30 @@ test_manifest_file ], "state_mutability": "view" }, + { + "type": "event", + "name": "dojo::components::upgradeable::upgradeable::Upgraded", + "kind": "struct", + "members": [ + { + "name": "class_hash", + "type": "core::starknet::class_hash::ClassHash", + "kind": "data" + } + ] + }, + { + "type": "event", + "name": "dojo::components::upgradeable::upgradeable::Event", + "kind": "enum", + "variants": [ + { + "name": "Upgraded", + "type": "dojo::components::upgradeable::upgradeable::Upgraded", + "kind": "nested" + } + ] + }, { "type": "event", "name": "dojo_examples::actions::actions::Moved", @@ -1048,6 +1145,11 @@ test_manifest_file "name": "dojo_examples::actions::actions::Event", "kind": "enum", "variants": [ + { + "name": "UpgradeableEvent", + "type": "dojo::components::upgradeable::upgradeable::Event", + "kind": "nested" + }, { "name": "Moved", "type": "dojo_examples::actions::actions::Moved", diff --git a/crates/dojo-lang/src/plugin_test_data/system b/crates/dojo-lang/src/plugin_test_data/system index e588abd684..bb252973ac 100644 --- a/crates/dojo-lang/src/plugin_test_data/system +++ b/crates/dojo-lang/src/plugin_test_data/system @@ -31,6 +31,26 @@ mod ctxnamed { } } +#[dojo::contract] +mod withevent { + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + TestEvent: TestEvent, + } + + #[derive(Drop, starknet::Event)] + struct TestEvent { + address: ContractAddress, + } + + #[external(v0)] + fn test(value: felt252) -> value { + value + } +} + //! > generated_cairo_code #[starknet::contract] mod spawn { @@ -157,64 +177,154 @@ error: Unsupported attribute. ^*******************^ error: Unsupported attribute. - --> test_src/lib.cairo[spawn]:8:21 + --> test_src/lib.cairo[withevent]:2:17 + #[starknet::contract] + ^*******************^ + +error: Unknown inline item macro: 'component'. + --> test_src/lib.cairo[spawn]:9:21 + component!(path: dojo::components::upgradeable::upgradeable, storage: upgradeable, event: UpgradeableEvent); + ^**********************************************************************************************************^ + +error: Unsupported attribute. + --> test_src/lib.cairo[spawn]:12:21 #[storage] ^********^ error: Unsupported attribute. - --> test_src/lib.cairo[spawn]:13:21 + --> test_src/lib.cairo[spawn]:15:25 + #[substorage(v0)] + ^***************^ + +error: Unsupported attribute. + --> test_src/lib.cairo[spawn]:19:21 #[external(v0)] ^*************^ error: Unsupported attribute. - --> test_src/lib.cairo[spawn]:18:21 + --> test_src/lib.cairo[spawn]:24:21 #[external(v0)] ^*************^ error: Unsupported attribute. - --> test_src/lib.cairo[spawn]:32:17 - #[external(v0)] - ^*************^ + --> test_src/lib.cairo[spawn]:31:21 + #[abi(embed_v0)] + ^**************^ error: Unsupported attribute. - --> test_src/lib.cairo[proxy]:8:21 + --> test_src/lib.cairo[spawn]:41:13 + #[event] + ^******^ + +error: Unknown inline item macro: 'component'. + --> test_src/lib.cairo[proxy]:9:21 + component!(path: dojo::components::upgradeable::upgradeable, storage: upgradeable, event: UpgradeableEvent); + ^**********************************************************************************************************^ + +error: Unsupported attribute. + --> test_src/lib.cairo[proxy]:12:21 #[storage] ^********^ error: Unsupported attribute. - --> test_src/lib.cairo[proxy]:13:21 + --> test_src/lib.cairo[proxy]:15:25 + #[substorage(v0)] + ^***************^ + +error: Unsupported attribute. + --> test_src/lib.cairo[proxy]:19:21 #[external(v0)] ^*************^ error: Unsupported attribute. - --> test_src/lib.cairo[proxy]:18:21 + --> test_src/lib.cairo[proxy]:24:21 #[external(v0)] ^*************^ error: Unsupported attribute. - --> test_src/lib.cairo[proxy]:30:17 - #[external(v0)] - ^*************^ + --> test_src/lib.cairo[proxy]:31:21 + #[abi(embed_v0)] + ^**************^ error: Unsupported attribute. - --> test_src/lib.cairo[ctxnamed]:8:21 + --> test_src/lib.cairo[proxy]:38:13 + #[event] + ^******^ + +error: Unknown inline item macro: 'component'. + --> test_src/lib.cairo[ctxnamed]:9:21 + component!(path: dojo::components::upgradeable::upgradeable, storage: upgradeable, event: UpgradeableEvent); + ^**********************************************************************************************************^ + +error: Unsupported attribute. + --> test_src/lib.cairo[ctxnamed]:12:21 #[storage] ^********^ error: Unsupported attribute. - --> test_src/lib.cairo[ctxnamed]:13:21 + --> test_src/lib.cairo[ctxnamed]:15:25 + #[substorage(v0)] + ^***************^ + +error: Unsupported attribute. + --> test_src/lib.cairo[ctxnamed]:19:21 + #[external(v0)] + ^*************^ + +error: Unsupported attribute. + --> test_src/lib.cairo[ctxnamed]:24:21 + #[external(v0)] + ^*************^ + +error: Unsupported attribute. + --> test_src/lib.cairo[ctxnamed]:31:21 + #[abi(embed_v0)] + ^**************^ + +error: Unsupported attribute. + --> test_src/lib.cairo[ctxnamed]:41:13 + #[event] + ^******^ + +error: Unknown inline item macro: 'component'. + --> test_src/lib.cairo[withevent]:9:21 + component!(path: dojo::components::upgradeable::upgradeable, storage: upgradeable, event: UpgradeableEvent); + ^**********************************************************************************************************^ + +error: Unsupported attribute. + --> test_src/lib.cairo[withevent]:12:21 + #[storage] + ^********^ + +error: Unsupported attribute. + --> test_src/lib.cairo[withevent]:15:25 + #[substorage(v0)] + ^***************^ + +error: Unsupported attribute. + --> test_src/lib.cairo[withevent]:19:21 #[external(v0)] ^*************^ error: Unsupported attribute. - --> test_src/lib.cairo[ctxnamed]:18:21 + --> test_src/lib.cairo[withevent]:24:21 #[external(v0)] ^*************^ error: Unsupported attribute. - --> test_src/lib.cairo[ctxnamed]:32:17 - #[external(v0)] - ^*************^ + --> test_src/lib.cairo[withevent]:31:21 + #[abi(embed_v0)] + ^**************^ + +error: Unsupported attribute. + --> test_src/lib.cairo[withevent]:35:13 + #[event] + ^******^ + +error: Unsupported attribute. + --> test_src/lib.cairo[withevent]:47:5 + #[external(v0)] + ^*************^ //! > expanded_cairo_code #[starknet::contract] @@ -222,10 +332,14 @@ error: Unsupported attribute. use dojo::world; use dojo::world::IWorldDispatcher; use dojo::world::IWorldDispatcherTrait; + use dojo::world::IWorldProvider; + #[storage] struct Storage { world_dispatcher: IWorldDispatcher, + #[substorage(v0)] + upgradeable: dojo::components::upgradeable::upgradeable::Storage, } #[external(v0)] @@ -234,23 +348,28 @@ error: Unsupported attribute. } #[external(v0)] - impl Upgradeable of dojo::upgradable::IUpgradeable { - fn upgrade(ref self: ContractState, new_class_hash: starknet::ClassHash) { - let caller = starknet::get_caller_address(); - assert( - self.world_dispatcher.read().contract_address == caller, 'only World can upgrade' - ); - dojo::upgradable::UpgradeableTrait::upgrade(new_class_hash); + impl WorldProviderImpl of IWorldProvider { + fn world(self: @ContractState) -> IWorldDispatcher { + self.world_dispatcher.read() } } + #[abi(embed_v0)] + impl UpgradableImpl = dojo::components::upgradeable::upgradeable::UpgradableImpl; + use traits::Into; use dojo::world::Context; - #[external(v0)] - fn execute(self: @ContractState, ctx: Context, name: felt252) { + fn execute(ctx: Context, name: felt252) { return (); } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + UpgradeableEvent: dojo::components::upgradeable::upgradeable::Event, + } +impl EventDrop of Drop::; } @@ -259,10 +378,14 @@ error: Unsupported attribute. use dojo::world; use dojo::world::IWorldDispatcher; use dojo::world::IWorldDispatcherTrait; + use dojo::world::IWorldProvider; + #[storage] struct Storage { world_dispatcher: IWorldDispatcher, + #[substorage(v0)] + upgradeable: dojo::components::upgradeable::upgradeable::Storage, } #[external(v0)] @@ -271,21 +394,25 @@ error: Unsupported attribute. } #[external(v0)] - impl Upgradeable of dojo::upgradable::IUpgradeable { - fn upgrade(ref self: ContractState, new_class_hash: starknet::ClassHash) { - let caller = starknet::get_caller_address(); - assert( - self.world_dispatcher.read().contract_address == caller, 'only World can upgrade' - ); - dojo::upgradable::UpgradeableTrait::upgrade(new_class_hash); + impl WorldProviderImpl of IWorldProvider { + fn world(self: @ContractState) -> IWorldDispatcher { + self.world_dispatcher.read() } } - - #[external(v0)] - fn execute(self: @ContractState, value: felt252) -> felt252 { + #[abi(embed_v0)] + impl UpgradableImpl = dojo::components::upgradeable::upgradeable::UpgradableImpl; + + fn execute(value: felt252) -> felt252 { value } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + UpgradeableEvent: dojo::components::upgradeable::upgradeable::Event, + } +impl EventDrop of Drop::; } @@ -294,10 +421,14 @@ error: Unsupported attribute. use dojo::world; use dojo::world::IWorldDispatcher; use dojo::world::IWorldDispatcherTrait; + use dojo::world::IWorldProvider; + #[storage] struct Storage { world_dispatcher: IWorldDispatcher, + #[substorage(v0)] + upgradeable: dojo::components::upgradeable::upgradeable::Storage, } #[external(v0)] @@ -306,22 +437,79 @@ error: Unsupported attribute. } #[external(v0)] - impl Upgradeable of dojo::upgradable::IUpgradeable { - fn upgrade(ref self: ContractState, new_class_hash: starknet::ClassHash) { - let caller = starknet::get_caller_address(); - assert( - self.world_dispatcher.read().contract_address == caller, 'only World can upgrade' - ); - dojo::upgradable::UpgradeableTrait::upgrade(new_class_hash); + impl WorldProviderImpl of IWorldProvider { + fn world(self: @ContractState) -> IWorldDispatcher { + self.world_dispatcher.read() } } + #[abi(embed_v0)] + impl UpgradableImpl = dojo::components::upgradeable::upgradeable::UpgradableImpl; + use traits::Into; use dojo::world::Context; - #[external(v0)] - fn execute(self: @ContractState, ctx2: Context, name: felt252) { + fn execute(ctx2: Context, name: felt252) { return (); } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + UpgradeableEvent: dojo::components::upgradeable::upgradeable::Event, + } +impl EventDrop of Drop::; } + + #[starknet::contract] + mod withevent { + use dojo::world; + use dojo::world::IWorldDispatcher; + use dojo::world::IWorldDispatcherTrait; + use dojo::world::IWorldProvider; + + + #[storage] + struct Storage { + world_dispatcher: IWorldDispatcher, + #[substorage(v0)] + upgradeable: dojo::components::upgradeable::upgradeable::Storage, + } + + #[external(v0)] + fn dojo_resource(self: @ContractState) -> felt252 { + 'withevent' + } + + #[external(v0)] + impl WorldProviderImpl of IWorldProvider { + fn world(self: @ContractState) -> IWorldDispatcher { + self.world_dispatcher.read() + } + } + + #[abi(embed_v0)] + impl UpgradableImpl = dojo::components::upgradeable::upgradeable::UpgradableImpl; + + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + UpgradeableEvent: dojo::components::upgradeable::upgradeable::Event, + TestEvent: TestEvent + } + + #[derive(Drop, starknet::Event)] + struct TestEvent { + address: ContractAddress, + } + + #[external(v0)] + fn test(value: felt252) -> value { + value + } +impl EventDrop of Drop::; +impl TestEventDrop of Drop::; + + } diff --git a/crates/torii/graphql/src/tests/mod.rs b/crates/torii/graphql/src/tests/mod.rs index cabad47c4f..2576c5227c 100644 --- a/crates/torii/graphql/src/tests/mod.rs +++ b/crates/torii/graphql/src/tests/mod.rs @@ -289,7 +289,7 @@ pub async fn spinup_types_test() -> Result { execute_strategy(&ws, &migration, &account, None).await.unwrap(); // Execute `create` and insert 10 records into storage - let records_contract = "0x58eaab9779694efb92b43ccad6dc9b40cd8fc69e3efa97137f1c83af69ca8a1"; + let records_contract = "0x27f701de7d71a2a6ee670bc1ff47a901fdc671cca26fe234ca1a42273aa7f7d"; let InvokeTransactionResult { transaction_hash } = account .execute(vec![Call { calldata: vec![FieldElement::from_str("0xa").unwrap()],