diff --git a/crates/dojo-core/src/tests/helpers.cairo b/crates/dojo-core/src/tests/helpers.cairo index c955fa1d5b..54d22cff28 100644 --- a/crates/dojo-core/src/tests/helpers.cairo +++ b/crates/dojo-core/src/tests/helpers.cairo @@ -44,6 +44,13 @@ pub mod foo_setter { #[dojo::contract] pub mod test_contract {} +#[dojo::contract] +pub mod test_contract_with_dojo_init_args { + fn dojo_init(world: @IWorldDispatcher, _arg1: felt252) { + let _u = world.uuid(); + } +} + #[dojo::contract(namespace: "buzz_namespace", nomapping: true)] pub mod buzz_contract {} diff --git a/crates/dojo-core/src/tests/world.cairo b/crates/dojo-core/src/tests/world.cairo deleted file mode 100644 index 491c4bd345..0000000000 --- a/crates/dojo-core/src/tests/world.cairo +++ /dev/null @@ -1,1705 +0,0 @@ -use core::array::{ArrayTrait, SpanTrait}; -use core::clone::Clone; -use core::option::OptionTrait; -use core::result::ResultTrait; -use core::traits::{Into, TryInto}; - -use starknet::{contract_address_const, ContractAddress, ClassHash, get_caller_address}; -use starknet::syscalls::deploy_syscall; - -use dojo::world::config::Config::{ - DifferProgramHashUpdate, MergerProgramHashUpdate, FactsRegistryUpdate -}; -use dojo::world::config::{IConfigDispatcher, IConfigDispatcherTrait}; -use dojo::model::{ModelIndex, Layout, FieldLayout, Model, ResourceMetadata}; -use dojo::model::introspect::{Introspect}; -use dojo::utils::bytearray_hash; -use dojo::storage::database::MAX_ARRAY_LENGTH; -use dojo::utils::test::{spawn_test_world, deploy_with_world_address, assert_array, GasCounterTrait}; -use dojo::utils::entity_id_from_keys; -use dojo::world::{ - IWorldDispatcher, IWorldDispatcherTrait, world, IUpgradeableWorld, IUpgradeableWorldDispatcher, - IUpgradeableWorldDispatcherTrait, Resource -}; -use dojo::world::world::NamespaceRegistered; - -use super::benchmarks; -use super::benchmarks::Character; - -#[derive(Introspect, Copy, Drop, Serde)] -enum OneEnum { - FirstArm: (u8, felt252), - SecondArm, -} - -#[derive(Introspect, Drop, Serde)] -enum AnotherEnum { - FirstArm: (u8, OneEnum, ByteArray), - SecondArm: (u8, OneEnum, ByteArray) -} - -#[derive(Copy, Drop, Serde)] -#[dojo::model] -pub struct Foo { - #[key] - pub caller: ContractAddress, - pub a: felt252, - pub b: u128, -} - -#[derive(Copy, Drop, Serde)] -#[dojo::model(namespace: "another_namespace", nomapping: true)] -pub struct Buzz { - #[key] - pub caller: ContractAddress, - pub a: felt252, - pub b: u128, -} - - -fn create_foo() -> Span { - [1, 2].span() -} - -#[derive(Copy, Drop, Serde)] -#[dojo::model] -pub struct Fizz { - #[key] - pub caller: ContractAddress, - pub a: felt252 -} - -#[derive(Copy, Drop, Serde)] -#[dojo::model] -pub struct StructSimpleModel { - #[key] - pub caller: ContractAddress, - pub a: felt252, - pub b: u128, -} - -fn create_struct_simple_model() -> Span { - [1, 2].span() -} - -#[derive(Copy, Drop, Serde)] -#[dojo::model] -pub struct StructWithTuple { - #[key] - pub caller: ContractAddress, - pub a: (u8, u64) -} - -fn create_struct_with_tuple() -> Span { - [12, 58].span() -} - -#[derive(Copy, Drop, Serde)] -#[dojo::model] -pub struct StructWithEnum { - #[key] - pub caller: ContractAddress, - pub a: OneEnum, -} - -fn create_struct_with_enum_first_variant() -> Span { - [0, 1, 2].span() -} - -fn create_struct_with_enum_second_variant() -> Span { - [1].span() -} - -#[derive(Copy, Drop, Serde)] -#[dojo::model] -pub struct StructSimpleArrayModel { - #[key] - pub caller: ContractAddress, - pub a: felt252, - pub b: Array, - pub c: u128, -} - -impl ArrayU64Copy of core::traits::Copy>; - -fn create_struct_simple_array_model() -> Span { - [1, 4, 10, 20, 30, 40, 2].span() -} - -#[derive(Drop, Serde)] -#[dojo::model] -pub struct StructByteArrayModel { - #[key] - pub caller: ContractAddress, - pub a: felt252, - pub b: ByteArray, -} - -fn create_struct_byte_array_model() -> Span { - [1, 3, 'first', 'second', 'third', 'pending', 7].span() -} - -#[derive(Introspect, Copy, Drop, Serde)] -pub struct ModelData { - pub x: u256, - pub y: u32, - pub z: felt252 -} - -#[derive(Drop, Serde)] -#[dojo::model] -pub struct StructComplexArrayModel { - #[key] - pub caller: ContractAddress, - pub a: felt252, - pub b: Array, - pub c: AnotherEnum, -} - -fn create_struct_complex_array_model() -> Span { - [ - 1, // a - 2, // b (array length) - 1, - 2, - 3, - 4, // item 1 - 5, - 6, - 7, - 8, // item 2 - 1, // c (AnotherEnum variant) - 1, // u8 - 0, // OneEnum variant - 0, // u8 - 123, // felt252 - 1, - 'first', - 'pending', - 7 // ByteArray - ].span() -} - -#[derive(Drop, Serde)] -#[dojo::model] -pub struct StructNestedModel { - #[key] - pub caller: ContractAddress, - pub x: (u8, u16, (u32, ByteArray, u8), Array<(u8, u16)>), - pub y: Array> -} - -fn create_struct_nested_model() -> Span { - [ - // -- x - 1, // u8 - 2, // u16 - 3, - 1, - 'first', - 'pending', - 7, - 9, // (u32, ByteArray, u8) - 3, - 1, - 2, - 3, - 4, - 5, - 6, // Array<(u8, u16)> with 3 items - // -- y - 2, // Array> with 2 items - 3, // first array item - Array<(u8, (u16, u256))> of 3 items - 1, - 2, - 0, - 3, // first array item - (u8, (u16, u256)) - 4, - 5, - 0, - 6, // second array item - (u8, (u16, u256)) - 8, - 7, - 9, - 10, // third array item - (u8, (u16, u256)) - 1, // second array item - Array<(u8, (u16, u256))> of 1 item - 5, - 4, - 6, - 7 // first array item - (u8, (u16, u256)) - ].span() -} - -#[derive(Introspect, Copy, Drop, Serde)] -pub enum EnumGeneric { - One: T, - Two: U -} - -#[derive(Drop, Serde)] -#[dojo::model] -pub struct StructWithGeneric { - #[key] - pub caller: ContractAddress, - pub x: EnumGeneric, -} - -fn create_struct_generic_first_variant() -> Span { - [0, 1].span() -} - -fn create_struct_generic_second_variant() -> Span { - [1, 1, 2].span() -} - -fn get_key_test() -> Span { - [0x01234].span() -} - -#[starknet::interface] -trait IMetadataOnly { - fn selector(self: @T) -> felt252; - fn name(self: @T) -> ByteArray; - fn namespace(self: @T) -> ByteArray; - fn namespace_hash(self: @T) -> felt252; -} - -#[starknet::contract] -mod resource_metadata_malicious { - use dojo::model::{Model, ResourceMetadata}; - use dojo::utils::bytearray_hash; - - #[storage] - struct Storage {} - - #[abi(embed_v0)] - impl InvalidModelName of super::IMetadataOnly { - fn selector(self: @ContractState) -> felt252 { - Model::::selector() - } - - fn namespace(self: @ContractState) -> ByteArray { - "dojo" - } - - fn namespace_hash(self: @ContractState) -> felt252 { - bytearray_hash(@Self::namespace(self)) - } - - fn name(self: @ContractState) -> ByteArray { - "invalid_model_name" - } - } -} - -#[starknet::interface] -trait Ibar { - fn set_foo(self: @TContractState, a: felt252, b: u128); - fn delete_foo(self: @TContractState); - fn delete_foo_macro(self: @TContractState, foo: Foo); - fn set_char(self: @TContractState, a: felt252, b: u32); -} - -#[starknet::contract] -mod bar { - use core::traits::Into; - use starknet::{get_caller_address, ContractAddress}; - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - use dojo::model::{Model, ModelIndex}; - - use super::{Foo, IWorldDispatcher, IWorldDispatcherTrait, Introspect}; - use super::benchmarks::{Character, Abilities, Stats, Weapon, Sword}; - - #[storage] - struct Storage { - world: IWorldDispatcher, - } - #[constructor] - fn constructor(ref self: ContractState, world: ContractAddress) { - self.world.write(IWorldDispatcher { contract_address: world }) - } - - #[abi(embed_v0)] - impl IbarImpl of super::Ibar { - fn set_foo(self: @ContractState, a: felt252, b: u128) { - set!(self.world.read(), Foo { caller: get_caller_address(), a, b }); - } - - fn delete_foo(self: @ContractState) { - self - .world - .read() - .delete_entity( - Model::::selector(), - ModelIndex::Keys([get_caller_address().into()].span()), - Model::::layout() - ); - } - - fn delete_foo_macro(self: @ContractState, foo: Foo) { - delete!(self.world.read(), Foo { caller: foo.caller, a: foo.a, b: foo.b }); - } - - fn set_char(self: @ContractState, a: felt252, b: u32) { - set!( - self.world.read(), - Character { - caller: get_caller_address(), - heigth: a, - abilities: Abilities { - strength: 0x12, - dexterity: 0x34, - constitution: 0x56, - intelligence: 0x78, - wisdom: 0x9a, - charisma: 0xbc, - }, - stats: Stats { - kills: 0x123456789abcdef, - deaths: 0x1234, - rests: 0x12345678, - hits: 0x123456789abcdef, - blocks: 0x12345678, - walked: 0x123456789abcdef, - runned: 0x123456789abcdef, - finished: true, - romances: 0x1234, - }, - weapon: Weapon::DualWield( - ( - Sword { swordsmith: get_caller_address(), damage: 0x12345678, }, - Sword { swordsmith: get_caller_address(), damage: 0x12345678, } - ) - ), - gold: b, - } - ); - } - } -} - -// Tests - -fn deploy_world_and_bar() -> (IWorldDispatcher, IbarDispatcher) { - // Spawn empty world - let world = deploy_world(); - world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); - - // System contract - let bar_contract = IbarDispatcher { - contract_address: deploy_with_world_address(bar::TEST_CLASS_HASH, world) - }; - - (world, bar_contract) -} - -#[test] -#[available_gas(2000000)] -fn test_model() { - let world = deploy_world(); - world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); -} - -#[test] -fn test_system() { - let (world, bar_contract) = deploy_world_and_bar(); - - bar_contract.set_foo(1337, 1337); - - let stored: Foo = get!(world, get_caller_address(), Foo); - assert(stored.a == 1337, 'data not stored'); - assert(stored.b == 1337, 'data not stored'); -} - -#[test] -fn test_delete() { - let (world, bar_contract) = deploy_world_and_bar(); - - // set model - bar_contract.set_foo(1337, 1337); - let stored: Foo = get!(world, get_caller_address(), Foo); - assert(stored.a == 1337, 'data not stored'); - assert(stored.b == 1337, 'data not stored'); - - // delete model - bar_contract.delete_foo_macro(stored); - - let deleted: Foo = get!(world, get_caller_address(), Foo); - assert(deleted.a == 0, 'data not deleted'); - assert(deleted.b == 0, 'data not deleted'); -} - -#[test] -#[available_gas(6000000)] -fn test_contract_getter() { - let world = deploy_world(); - - let _ = world - .deploy_contract('salt1', test_contract::TEST_CLASS_HASH.try_into().unwrap(), [].span()); - - if let Resource::Contract((class_hash, _)) = world - .resource(selector_from_tag!("dojo-test_contract")) { - assert( - class_hash == test_contract::TEST_CLASS_HASH.try_into().unwrap(), - 'invalid contract class hash' - ); - } else { - core::panic_with_felt252('invalid resource type'); - } -} - -#[test] -#[available_gas(6000000)] -fn test_model_class_hash_getter() { - let world = deploy_world(); - world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); - - if let Resource::Model((foo_class_hash, _)) = world.resource(Model::::selector()) { - assert(foo_class_hash == foo::TEST_CLASS_HASH.try_into().unwrap(), 'foo wrong class hash'); - } else { - core::panic_with_felt252('invalid resource type'); - } -} - -#[test] -#[ignore] -#[available_gas(6000000)] -fn test_legacy_model_class_hash_getter() { - let world = deploy_world(); - world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); - - if let Resource::Model((foo_class_hash, _)) = world.resource(Model::::selector()) { - assert(foo_class_hash == foo::TEST_CLASS_HASH.try_into().unwrap(), 'foo wrong class hash'); - } else { - core::panic_with_felt252('invalid resource type'); - } -} - -#[test] -fn test_register_namespace() { - let world = deploy_world(); - - let caller = starknet::contract_address_const::<0xb0b>(); - starknet::testing::set_account_contract_address(caller); - - drop_all_events(world.contract_address); - - let namespace = "namespace"; - let hash = bytearray_hash(@namespace); - - world.register_namespace(namespace); - - assert(world.is_owner(hash, caller), 'namespace not registered'); - - assert_eq!( - starknet::testing::pop_log(world.contract_address), - Option::Some(NamespaceRegistered { namespace: "namespace", hash }) - ); -} - -#[test] -fn test_register_namespace_already_registered_same_caller() { - let world = deploy_world(); - - let caller = starknet::contract_address_const::<0xb0b>(); - starknet::testing::set_account_contract_address(caller); - - let namespace = "namespace"; - let hash = bytearray_hash(@namespace); - - world.register_namespace(namespace); - - drop_all_events(world.contract_address); - - world.register_namespace("namespace"); - - assert(world.is_owner(hash, caller), 'namespace not registered'); - - let event = starknet::testing::pop_log_raw(world.contract_address); - assert(event.is_none(), 'unexpected event'); -} - -#[test] -#[should_panic(expected: ('namespace already registered', 'ENTRYPOINT_FAILED',))] -fn test_register_namespace_already_registered_other_caller() { - let world = deploy_world(); - - let account = starknet::contract_address_const::<0xb0b>(); - starknet::testing::set_account_contract_address(account); - - world.register_namespace("namespace"); - - let another_account = starknet::contract_address_const::<0xa11ce>(); - starknet::testing::set_account_contract_address(another_account); - - world.register_namespace("namespace"); -} - -#[test] -#[available_gas(6000000)] -fn test_emit() { - let world = deploy_world(); - - let mut keys = ArrayTrait::new(); - keys.append('MyEvent'); - let mut values = ArrayTrait::new(); - values.append(1); - values.append(2); - world.emit(keys, values.span()); -} - -#[test] -fn test_set_entity_admin() { - let (world, bar_contract) = deploy_world_and_bar(); - - let alice = starknet::contract_address_const::<0x1337>(); - starknet::testing::set_contract_address(alice); - - bar_contract.set_foo(420, 1337); - - let foo: Foo = get!(world, alice, Foo); - assert(foo.a == 420, 'data not stored'); - assert(foo.b == 1337, 'data not stored'); -} - -#[test] -#[available_gas(8000000)] -#[should_panic] -fn test_set_entity_unauthorized() { - // Spawn empty world - let world = deploy_world(); - - let bar_contract = IbarDispatcher { - contract_address: deploy_with_world_address(bar::TEST_CLASS_HASH, world) - }; - - world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); - - let caller = starknet::contract_address_const::<0x1337>(); - starknet::testing::set_account_contract_address(caller); - - // Call bar system, should panic as it's not authorized - bar_contract.set_foo(420, 1337); -} - -// Utils -fn deploy_world() -> IWorldDispatcher { - spawn_test_world("dojo", array![]) -} - -#[test] -#[available_gas(60000000)] -fn test_set_metadata_world() { - let world = deploy_world(); - - let metadata = ResourceMetadata { - resource_id: 0, metadata_uri: format!("ipfs:world_with_a_long_uri_that") - }; - - world.set_metadata(metadata.clone()); - - assert(world.metadata(0) == metadata, 'invalid metadata'); -} - -#[test] -#[available_gas(60000000)] -fn test_set_metadata_model_writer() { - let world = spawn_test_world("dojo", array![foo::TEST_CLASS_HASH],); - - let bar_contract = IbarDispatcher { - contract_address: deploy_with_world_address(bar::TEST_CLASS_HASH, world) - }; - - world.grant_writer(Model::::selector(), bar_contract.contract_address); - - let bob = starknet::contract_address_const::<0xb0b>(); - starknet::testing::set_account_contract_address(bob); - starknet::testing::set_contract_address(bar_contract.contract_address); - - bar_contract.set_foo(1337, 1337); - - let metadata = ResourceMetadata { - resource_id: Model::::selector(), metadata_uri: format!("ipfs:bob") - }; - - // A system that has write access on a model should be able to update the metadata. - // This follows conventional ACL model. - world.set_metadata(metadata.clone()); - assert(world.metadata(Model::::selector()) == metadata, 'bad metadata'); -} - -#[test] -#[available_gas(60000000)] -#[should_panic(expected: ('no write access', 'ENTRYPOINT_FAILED',))] -fn test_set_metadata_same_model_rules() { - let world = deploy_world(); - - let metadata = ResourceMetadata { // World metadata. - resource_id: 0, metadata_uri: format!("ipfs:bob"), - }; - - let bob = starknet::contract_address_const::<0xb0b>(); - starknet::testing::set_contract_address(bob); - starknet::testing::set_account_contract_address(bob); - - // Bob access follows the conventional ACL, he can't write the world - // metadata if he does not have access to it. - world.set_metadata(metadata); -} - -#[test] -#[available_gas(60000000)] -#[should_panic(expected: ('only owner can update', 'ENTRYPOINT_FAILED',))] -fn test_metadata_update_owner_only() { - let world = deploy_world(); - - let bob = starknet::contract_address_const::<0xb0b>(); - starknet::testing::set_contract_address(bob); - - world.grant_owner(bytearray_hash(@"dojo"), bob); - - starknet::testing::set_account_contract_address(bob); - - world.register_model(resource_metadata_malicious::TEST_CLASS_HASH.try_into().unwrap()); -} - -#[test] -#[available_gas(6000000)] -fn test_owner() { - let world = deploy_world(); - world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); - let foo_selector = Model::::selector(); - - let alice = starknet::contract_address_const::<0x1337>(); - let bob = starknet::contract_address_const::<0x1338>(); - - assert(!world.is_owner(0, alice), 'should not be owner'); - assert(!world.is_owner(foo_selector, bob), 'should not be owner'); - - world.grant_owner(0, alice); - assert(world.is_owner(0, alice), 'should be owner'); - - world.grant_owner(foo_selector, bob); - assert(world.is_owner(foo_selector, bob), 'should be owner'); - - world.revoke_owner(0, alice); - assert(!world.is_owner(0, alice), 'should not be owner'); - - world.revoke_owner(foo_selector, bob); - assert(!world.is_owner(foo_selector, bob), 'should not be owner'); -} - -#[test] -#[available_gas(6000000)] -#[should_panic] -fn test_set_owner_fails_for_non_owner() { - let world = deploy_world(); - - let alice = starknet::contract_address_const::<0x1337>(); - starknet::testing::set_account_contract_address(alice); - - world.revoke_owner(0, alice); - assert(!world.is_owner(0, alice), 'should not be owner'); - - world.grant_owner(0, alice); -} - -#[test] -#[available_gas(6000000)] -fn test_writer() { - let world = deploy_world(); - world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); - let foo_selector = Model::::selector(); - - assert(!world.is_writer(foo_selector, 69.try_into().unwrap()), 'should not be writer'); - - world.grant_writer(foo_selector, 69.try_into().unwrap()); - assert(world.is_writer(foo_selector, 69.try_into().unwrap()), 'should be writer'); - - world.revoke_writer(foo_selector, 69.try_into().unwrap()); - assert(!world.is_writer(foo_selector, 69.try_into().unwrap()), 'should not be writer'); -} - -#[test] -#[should_panic(expected: ('resource not registered', 'ENTRYPOINT_FAILED'))] -fn test_writer_not_registered_resource() { - let world = deploy_world(); - - // 42 is not a registered resource ID - world.grant_writer(42, 69.try_into().unwrap()); -} - -#[test] -#[available_gas(6000000)] -#[should_panic] -fn test_system_not_writer_fail() { - let world = spawn_test_world("dojo", array![foo::TEST_CLASS_HASH],); - - let bar_address = deploy_with_world_address(bar::TEST_CLASS_HASH, world); - let bar_contract = IbarDispatcher { contract_address: bar_address }; - - // Caller is not owner now - let account = starknet::contract_address_const::<0xb0b>(); - starknet::testing::set_account_contract_address(account); - - // Should panic, system not writer - bar_contract.set_foo(25, 16); -} - -#[test] -fn test_system_writer_access() { - let world = spawn_test_world("dojo", array![foo::TEST_CLASS_HASH],); - - let bar_address = deploy_with_world_address(bar::TEST_CLASS_HASH, world); - let bar_contract = IbarDispatcher { contract_address: bar_address }; - - world.grant_writer(Model::::selector(), bar_address); - assert(world.is_writer(Model::::selector(), bar_address), 'should be writer'); - - // Caller is not owner now - let caller = starknet::contract_address_const::<0x1337>(); - starknet::testing::set_account_contract_address(caller); - - // Should not panic, system is writer - bar_contract.set_foo(25, 16); -} - -#[test] -#[available_gas(6000000)] -#[should_panic] -fn test_set_writer_fails_for_non_owner() { - let world = deploy_world(); - - let alice = starknet::contract_address_const::<0x1337>(); - starknet::testing::set_contract_address(alice); - - assert(!world.is_owner(0, alice), 'should not be owner'); - - world.grant_writer(42, 69.try_into().unwrap()); -} - -#[test] -fn test_execute_multiple_worlds() { - // Deploy world contract - let world1 = spawn_test_world("dojo", array![foo::TEST_CLASS_HASH],); - - let bar1_contract = IbarDispatcher { - contract_address: deploy_with_world_address(bar::TEST_CLASS_HASH, world1) - }; - - // Deploy another world contract - let world2 = spawn_test_world("dojo", array![foo::TEST_CLASS_HASH],); - - let bar2_contract = IbarDispatcher { - contract_address: deploy_with_world_address(bar::TEST_CLASS_HASH, world2) - }; - - let alice = starknet::contract_address_const::<0x1337>(); - starknet::testing::set_contract_address(alice); - - bar1_contract.set_foo(1337, 1337); - bar2_contract.set_foo(7331, 7331); - - let data1 = get!(world1, alice, Foo); - let data2 = get!(world2, alice, Foo); - - assert(data1.a == 1337, 'data1 not stored'); - assert(data2.a == 7331, 'data2 not stored'); -} - -#[test] -#[available_gas(60000000)] -fn bench_execute() { - let world = spawn_test_world("dojo", array![foo::TEST_CLASS_HASH],); - let bar_contract = IbarDispatcher { - contract_address: deploy_with_world_address(bar::TEST_CLASS_HASH, world) - }; - - let alice = starknet::contract_address_const::<0x1337>(); - starknet::testing::set_contract_address(alice); - - let gas = GasCounterTrait::start(); - - bar_contract.set_foo(1337, 1337); - gas.end("foo set call"); - - let gas = GasCounterTrait::start(); - let data = get!(world, alice, Foo); - gas.end("foo get macro"); - - assert(data.a == 1337, 'data not stored'); -} - -#[test] -fn bench_execute_complex() { - let world = spawn_test_world("dojo", array![benchmarks::character::TEST_CLASS_HASH],); - let bar_contract = IbarDispatcher { - contract_address: deploy_with_world_address(bar::TEST_CLASS_HASH, world) - }; - - let alice = starknet::contract_address_const::<0x1337>(); - starknet::testing::set_contract_address(alice); - - let gas = GasCounterTrait::start(); - - bar_contract.set_char(1337, 1337); - gas.end("char set call"); - - let gas = GasCounterTrait::start(); - - let data = get!(world, alice, Character); - gas.end("char get macro"); - - assert(data.heigth == 1337, 'data not stored'); -} - -#[starknet::interface] -trait IWorldUpgrade { - fn hello(self: @TContractState) -> felt252; -} - -#[starknet::contract] -mod worldupgrade { - use super::{IWorldUpgrade, IWorldDispatcher, ContractAddress}; - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - - #[storage] - struct Storage { - world: IWorldDispatcher, - } - - #[abi(embed_v0)] - impl IWorldUpgradeImpl of super::IWorldUpgrade { - fn hello(self: @ContractState) -> felt252 { - 'dojo' - } - } -} - - -#[test] -#[available_gas(60000000)] -fn test_upgradeable_world() { - // Deploy world contract - let world = deploy_world(); - - let mut upgradeable_world_dispatcher = IUpgradeableWorldDispatcher { - contract_address: world.contract_address - }; - upgradeable_world_dispatcher.upgrade(worldupgrade::TEST_CLASS_HASH.try_into().unwrap()); - - let res = (IWorldUpgradeDispatcher { contract_address: world.contract_address }).hello(); - - assert(res == 'dojo', 'should return dojo'); -} - -#[test] -#[available_gas(60000000)] -#[should_panic(expected: ('invalid class_hash', 'ENTRYPOINT_FAILED'))] -fn test_upgradeable_world_with_class_hash_zero() { - // Deploy world contract - let world = deploy_world(); - - starknet::testing::set_contract_address(starknet::contract_address_const::<0x1337>()); - - let mut upgradeable_world_dispatcher = IUpgradeableWorldDispatcher { - contract_address: world.contract_address - }; - upgradeable_world_dispatcher.upgrade(0.try_into().unwrap()); -} - -#[test] -#[available_gas(60000000)] -#[should_panic(expected: ('only owner can upgrade', 'ENTRYPOINT_FAILED'))] -fn test_upgradeable_world_from_non_owner() { - // Deploy world contract - let world = deploy_world(); - - let not_owner = starknet::contract_address_const::<0x1337>(); - starknet::testing::set_contract_address(not_owner); - starknet::testing::set_account_contract_address(not_owner); - - let mut upgradeable_world_dispatcher = IUpgradeableWorldDispatcher { - contract_address: world.contract_address - }; - upgradeable_world_dispatcher.upgrade(worldupgrade::TEST_CLASS_HASH.try_into().unwrap()); -} - -fn drop_all_events(address: ContractAddress) { - loop { - match starknet::testing::pop_log_raw(address) { - core::option::Option::Some(_) => {}, - core::option::Option::None => { break; }, - }; - } -} - -#[test] -#[available_gas(6000000)] -fn test_differ_program_hash_event_emit() { - let world = deploy_world(); - drop_all_events(world.contract_address); - let config = IConfigDispatcher { contract_address: world.contract_address }; - - config.set_differ_program_hash(program_hash: 98758347158781475198374598718743); - - assert_eq!( - starknet::testing::pop_log(world.contract_address), - Option::Some(DifferProgramHashUpdate { program_hash: 98758347158781475198374598718743 }) - ); -} - -#[test] -#[available_gas(6000000)] -fn test_facts_registry_event_emit() { - let world = deploy_world(); - drop_all_events(world.contract_address); - let config = IConfigDispatcher { contract_address: world.contract_address }; - - config.set_facts_registry(contract_address_const::<0x12>()); - - assert_eq!( - starknet::testing::pop_log(world.contract_address), - Option::Some(FactsRegistryUpdate { address: contract_address_const::<0x12>() }) - ); -} - -#[starknet::interface] -trait IDojoInit { - fn dojo_init(self: @ContractState) -> felt252; -} - -#[dojo::contract] -mod test_contract {} - -#[dojo::contract(namespace: "buzz_namespace", nomapping: true)] -mod buzz_contract {} - -#[test] -#[available_gas(6000000)] -#[should_panic(expected: ('Only world can init', 'ENTRYPOINT_FAILED'))] -fn test_can_call_init() { - let world = deploy_world(); - let address = world - .deploy_contract('salt1', test_contract::TEST_CLASS_HASH.try_into().unwrap(), [].span()); - - let dojo_init = IDojoInitDispatcher { contract_address: address }; - dojo_init.dojo_init(); -} - -#[test] -fn test_set_entity_by_id() { - let world = deploy_world(); - world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); - let selector = Model::::selector(); - let entity_id = entity_id_from_keys([0x01234].span()); - let values = create_foo(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Id(entity_id), values, layout); - let read_values = world.entity(selector, ModelIndex::Id(entity_id), layout); - assert_array(read_values, values); -} - -#[test] -fn test_set_entity_with_fixed_layout() { - let world = deploy_world(); - world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); - let selector = Model::::selector(); - let keys = get_key_test(); - let values = create_foo(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(get_key_test()), values, layout); - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - assert_array(read_values, values); -} - -#[test] -fn test_set_entity_with_struct_layout() { - let world = deploy_world(); - world.register_model(struct_simple_model::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let values = create_struct_simple_model(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); - - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - assert_array(read_values, values); -} - -#[test] -fn test_set_entity_with_struct_tuple_layout() { - let world = deploy_world(); - world.register_model(struct_with_tuple::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let values = create_struct_with_tuple(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); - - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - assert_array(read_values, values); -} - -#[test] -fn test_set_entity_with_struct_enum_layout() { - let world = deploy_world(); - world.register_model(struct_with_enum::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let values = create_struct_with_enum_first_variant(); - let layout = Model::::layout(); - - // test with the first variant - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); - - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - assert_array(read_values, values); - - // then override with the second variant - let values = create_struct_with_enum_second_variant(); - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); - - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - assert_array(read_values, values); -} - -#[test] -fn test_set_entity_with_struct_simple_array_layout() { - let world = deploy_world(); - world.register_model(struct_simple_array_model::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let values = create_struct_simple_array_model(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); - - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - assert_array(read_values, values); -} - -#[test] -fn test_set_entity_with_struct_complex_array_layout() { - let world = deploy_world(); - world.register_model(struct_complex_array_model::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let values = create_struct_complex_array_model(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); - - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - assert_array(read_values, values); -} - -#[test] -fn test_set_entity_with_struct_layout_and_byte_array() { - let world = deploy_world(); - world.register_model(struct_byte_array_model::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let values = create_struct_byte_array_model(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); - - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - assert_array(read_values, values); -} - -#[test] -fn test_set_entity_with_nested_elements() { - let world = deploy_world(); - world.register_model(struct_nested_model::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let values = create_struct_nested_model(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); - - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - assert_array(read_values, values); -} - -fn assert_empty_array(values: Span) { - let mut i = 0; - loop { - if i >= values.len() { - break; - } - assert!(*values.at(i) == 0); - i += 1; - }; -} - -#[test] -fn test_set_entity_with_struct_generics_enum_layout() { - let world = deploy_world(); - world.register_model(struct_with_generic::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let values = create_struct_generic_first_variant(); - let layout = Model::::layout(); - - // test with the first variant - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); - - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - assert_array(read_values, values); - - // then override with the second variant - let values = create_struct_generic_second_variant(); - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); - - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - assert_array(read_values, values); -} - -#[test] -fn test_delete_entity_by_id() { - let world = deploy_world(); - world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); - let selector = Model::::selector(); - let entity_id = entity_id_from_keys(get_key_test()); - let values = create_foo(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Id(entity_id), values, layout); - - world.delete_entity(selector, ModelIndex::Id(entity_id), layout); - - let read_values = world.entity(selector, ModelIndex::Id(entity_id), layout); - - assert!(read_values.len() == values.len()); - assert_empty_array(read_values); -} - -#[test] -fn test_delete_entity_with_fixed_layout() { - let world = deploy_world(); - world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); - let selector = Model::::selector(); - let keys = get_key_test(); - let values = create_foo(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(get_key_test()), values, layout); - - world.delete_entity(selector, ModelIndex::Keys(keys), layout); - - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - - assert!(read_values.len() == values.len()); - assert_empty_array(read_values); -} - -#[test] -fn test_delete_entity_with_simple_struct_layout() { - let world = deploy_world(); - world.register_model(struct_simple_model::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let values = create_struct_simple_model(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); - - world.delete_entity(selector, ModelIndex::Keys(keys), layout); - - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - - assert!(read_values.len() == values.len()); - assert_empty_array(read_values); -} - -#[test] -fn test_delete_entity_with_struct_simple_array_layout() { - let world = deploy_world(); - world.register_model(struct_simple_array_model::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let values = create_struct_simple_array_model(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); - - world.delete_entity(selector, ModelIndex::Keys(keys), layout); - - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - - // array length set to 0, so the expected value span is shorter than the initial values - let expected_values = [0, 0, 0].span(); - - assert!(read_values.len() == expected_values.len()); - assert_empty_array(read_values); -} - -#[test] -fn test_delete_entity_with_complex_array_struct_layout() { - let world = deploy_world(); - world.register_model(struct_complex_array_model::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let values = create_struct_complex_array_model(); - - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); - - world.delete_entity(selector, ModelIndex::Keys(keys), layout); - - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - - // array length set to 0, so the expected value span is shorter than the initial values - let expected_values = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0].span(); - - assert!(read_values.len() == expected_values.len()); - assert_empty_array(read_values); -} - -#[test] -fn test_delete_entity_with_struct_tuple_layout() { - let world = deploy_world(); - world.register_model(struct_with_tuple::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let values = create_struct_with_tuple(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); - - world.delete_entity(selector, ModelIndex::Keys(keys), layout); - - let expected_values = [0, 0].span(); - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - - assert!(read_values.len() == expected_values.len()); - assert_empty_array(read_values); -} - -#[test] -fn test_delete_entity_with_struct_enum_layout() { - let world = deploy_world(); - world.register_model(struct_with_enum::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let values = create_struct_with_enum_first_variant(); - let layout = Model::::layout(); - - // test with the first variant - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); - - world.delete_entity(selector, ModelIndex::Keys(keys), layout); - - let expected_values = [0, 0, 0].span(); - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - - assert!(read_values.len() == expected_values.len()); - assert_empty_array(read_values); -} - -#[test] -fn test_delete_entity_with_struct_layout_and_byte_array() { - let world = deploy_world(); - world.register_model(struct_byte_array_model::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let values = create_struct_byte_array_model(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); - - world.delete_entity(selector, ModelIndex::Keys(keys), layout); - - let expected_values = [0, 0, 0, 0].span(); - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - - assert!(read_values.len() == expected_values.len()); - assert_empty_array(read_values); -} - -#[test] -fn test_delete_entity_with_nested_elements() { - let world = deploy_world(); - world.register_model(struct_nested_model::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let values = create_struct_nested_model(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); - - world.delete_entity(selector, ModelIndex::Keys(keys), layout); - - let expected_values = [0, 0, 0, 0, 0, 0, 0, 0, 0].span(); - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - - assert!(read_values.len() == expected_values.len()); - assert_empty_array(read_values); -} - -#[test] -fn test_delete_entity_with_struct_generics_enum_layout() { - let world = deploy_world(); - world.register_model(struct_with_generic::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let values = create_struct_generic_first_variant(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); - - world.delete_entity(selector, ModelIndex::Keys(keys), layout); - - let expected_values = [0, 0].span(); - let read_values = world.entity(selector, ModelIndex::Keys(keys), layout); - - assert!(read_values.len() == expected_values.len()); - assert_empty_array(read_values); -} - -#[test] -#[should_panic(expected: ("Unexpected layout type for a model.", 'ENTRYPOINT_FAILED'))] -fn test_set_entity_with_unexpected_array_model_layout() { - let world = deploy_world(); - world.register_model(struct_simple_array_model::TEST_CLASS_HASH.try_into().unwrap()); - - let layout = Layout::Array([Introspect::::layout()].span()); - - world - .set_entity( - Model::::selector(), - ModelIndex::Keys([].span()), - [].span(), - layout - ); -} - -#[test] -#[should_panic(expected: ("Unexpected layout type for a model.", 'ENTRYPOINT_FAILED'))] -fn test_set_entity_with_unexpected_tuple_model_layout() { - let world = deploy_world(); - world.register_model(struct_simple_array_model::TEST_CLASS_HASH.try_into().unwrap()); - - let layout = Layout::Tuple([Introspect::::layout()].span()); - - world - .set_entity( - Model::::selector(), - ModelIndex::Keys([].span()), - [].span(), - layout - ); -} - -#[test] -#[should_panic(expected: ("Unexpected layout type for a model.", 'ENTRYPOINT_FAILED'))] -fn test_delete_entity_with_unexpected_array_model_layout() { - let world = deploy_world(); - world.register_model(struct_simple_array_model::TEST_CLASS_HASH.try_into().unwrap()); - - let layout = Layout::Array([Introspect::::layout()].span()); - - world - .delete_entity( - Model::::selector(), ModelIndex::Keys([].span()), layout - ); -} - -#[test] -#[should_panic(expected: ("Unexpected layout type for a model.", 'ENTRYPOINT_FAILED'))] -fn test_delete_entity_with_unexpected_tuple_model_layout() { - let world = deploy_world(); - world.register_model(struct_simple_array_model::TEST_CLASS_HASH.try_into().unwrap()); - - let layout = Layout::Tuple([Introspect::::layout()].span()); - - world - .delete_entity( - Model::::selector(), ModelIndex::Keys([].span()), layout - ); -} - -#[test] -#[should_panic(expected: ("Unexpected layout type for a model.", 'ENTRYPOINT_FAILED'))] -fn test_get_entity_with_unexpected_array_model_layout() { - let world = deploy_world(); - world.register_model(struct_simple_array_model::TEST_CLASS_HASH.try_into().unwrap()); - - let layout = Layout::Array([Introspect::::layout()].span()); - - world.entity(Model::::selector(), ModelIndex::Keys([].span()), layout); -} - -#[test] -#[should_panic(expected: ("Unexpected layout type for a model.", 'ENTRYPOINT_FAILED'))] -fn test_get_entity_with_unexpected_tuple_model_layout() { - let world = deploy_world(); - world.register_model(struct_simple_array_model::TEST_CLASS_HASH.try_into().unwrap()); - - let layout = Layout::Tuple([Introspect::::layout()].span()); - - world.entity(Model::::selector(), ModelIndex::Keys([].span()), layout); -} - - -#[test] -#[should_panic(expected: ('Invalid values length', 'ENTRYPOINT_FAILED',))] -fn test_set_entity_with_bad_values_length_error_for_array_layout() { - let world = deploy_world(); - world.register_model(struct_simple_array_model::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(keys), [1].span(), layout); -} - -#[test] -#[should_panic(expected: ('invalid array length', 'ENTRYPOINT_FAILED',))] -fn test_set_entity_with_too_big_array_length() { - let world = deploy_world(); - world.register_model(struct_simple_array_model::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let values: Span = [ - 1, MAX_ARRAY_LENGTH.try_into().unwrap() + 1, 10, 20, 30, 40, 2 - ].span(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); -} - -#[test] -#[should_panic(expected: ('invalid array length', 'ENTRYPOINT_FAILED',))] -fn test_set_entity_with_struct_layout_and_bad_byte_array_length() { - let world = deploy_world(); - world.register_model(struct_byte_array_model::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let values: Span = [ - 1, MAX_ARRAY_LENGTH.try_into().unwrap(), 'first', 'second', 'third', 'pending', 7 - ].span(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); -} - -#[test] -#[should_panic(expected: ('Invalid values length', 'ENTRYPOINT_FAILED',))] -fn test_set_entity_with_struct_layout_and_bad_value_length_for_byte_array() { - let world = deploy_world(); - world.register_model(struct_byte_array_model::TEST_CLASS_HASH.try_into().unwrap()); - - let selector = Model::::selector(); - let keys = get_key_test(); - let values: Span = [1, 3, 'first', 'second', 'third', 'pending'].span(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(keys), values, layout); -} - -fn write_foo_record(world: IWorldDispatcher) { - let selector = Model::::selector(); - let values = create_foo(); - let layout = Model::::layout(); - - world.set_entity(selector, ModelIndex::Keys(get_key_test()), values, layout); -} - -#[test] -fn test_write_model_for_namespace_owner() { - let world = deploy_world(); - world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); - - let account = starknet::contract_address_const::<0xb0b>(); - let contract = starknet::contract_address_const::<0xdeadbeef>(); - - // the caller account is a model namespace owner - world.grant_owner(Model::::namespace_hash(), account); - starknet::testing::set_account_contract_address(account); - starknet::testing::set_contract_address(contract); - - write_foo_record(world); -} - -#[test] -fn test_write_model_for_model_owner() { - let world = deploy_world(); - world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); - - // the caller account is a model owner - let account = starknet::contract_address_const::<0xb0b>(); - let contract = starknet::contract_address_const::<0xdeadbeef>(); - - world.grant_owner(Model::::selector(), account); - starknet::testing::set_account_contract_address(account); - starknet::testing::set_contract_address(contract); - - write_foo_record(world); -} - -#[test] -fn test_write_model_for_namespace_writer() { - let world = deploy_world(); - world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); - - let account = starknet::contract_address_const::<0xb0b>(); - let contract = starknet::contract_address_const::<0xdeadbeef>(); - - world.grant_writer(Model::::namespace_hash(), contract); - - // the account does not own anything - starknet::testing::set_account_contract_address(account); - starknet::testing::set_contract_address(contract); - - write_foo_record(world); -} - -#[test] -fn test_write_model_for_model_writer() { - let world = deploy_world(); - world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); - - let account = starknet::contract_address_const::<0xb0b>(); - let contract = starknet::contract_address_const::<0xdeadbeef>(); - - world.grant_writer(Model::::selector(), contract); - - // the account does not own anything - starknet::testing::set_account_contract_address(account); - starknet::testing::set_contract_address(contract); - - write_foo_record(world); -} - -#[test] -fn test_write_namespace_for_namespace_owner() { - let world = deploy_world(); - - let account = starknet::contract_address_const::<0xb0b>(); - let contract = starknet::contract_address_const::<0xdeadbeef>(); - - world.grant_owner(Model::::namespace_hash(), account); - - // the account owns the Foo model namespace so it should be able to deploy - // and register the model. - starknet::testing::set_account_contract_address(account); - starknet::testing::set_contract_address(contract); - - world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); -} - -#[test] -fn test_write_namespace_for_namespace_writer() { - let world = deploy_world(); - - let account = starknet::contract_address_const::<0xb0b>(); - let contract = starknet::contract_address_const::<0xdeadbeef>(); - - world.grant_writer(Model::::namespace_hash(), account); - - // the account has write access to the Foo model namespace so it should be able - // to deploy and register the model. - starknet::testing::set_account_contract_address(account); - starknet::testing::set_contract_address(contract); - - world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); -} - -#[test] -#[should_panic(expected: ('no model write access', 'ENTRYPOINT_FAILED',))] -fn test_write_model_no_write_access() { - let world = deploy_world(); - world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); - - // the caller account does not own the model nor the model namespace nor the world - let account = starknet::contract_address_const::<0xb0b>(); - starknet::testing::set_account_contract_address(account); - - // the contract is not a writer for the model nor for the model namespace - let contract = starknet::contract_address_const::<0xdeadbeef>(); - starknet::testing::set_contract_address(contract); - - write_foo_record(world); -} - -#[test] -#[should_panic(expected: ('namespace not registered', 'ENTRYPOINT_FAILED',))] -fn test_register_model_with_unregistered_namespace() { - let world = deploy_world(); - world.register_model(buzz::TEST_CLASS_HASH.try_into().unwrap()); -} - -#[test] -fn test_deploy_contract_for_namespace_owner() { - let world = deploy_world(); - - let account = starknet::contract_address_const::<0xb0b>(); - world.grant_owner(bytearray_hash(@"dojo"), account); - - // the account owns the 'test_contract' namespace so it should be able to deploy - // and register the model. - starknet::testing::set_account_contract_address(account); - - world.deploy_contract('salt1', test_contract::TEST_CLASS_HASH.try_into().unwrap(), [].span()); -} - -#[test] -fn test_deploy_contract_for_namespace_writer() { - let world = deploy_world(); - - let account = starknet::contract_address_const::<0xb0b>(); - world.grant_writer(bytearray_hash(@"dojo"), account); - - // the account has write access to the 'test_contract' namespace so it should be able - // to deploy and register the model. - starknet::testing::set_account_contract_address(account); - - world.deploy_contract('salt1', test_contract::TEST_CLASS_HASH.try_into().unwrap(), [].span()); -} - -#[test] -#[should_panic(expected: ('namespace not registered', 'ENTRYPOINT_FAILED',))] -fn test_deploy_contract_with_unregistered_namespace() { - let world = deploy_world(); - world.deploy_contract('salt1', buzz_contract::TEST_CLASS_HASH.try_into().unwrap(), [].span()); -} - -#[test] -#[should_panic(expected: ('no namespace write access', 'ENTRYPOINT_FAILED',))] -fn test_deploy_contract_no_namespace_write_access() { - let world = deploy_world(); - - let account = starknet::contract_address_const::<0xb0b>(); - starknet::testing::set_account_contract_address(account); - - world.deploy_contract('salt1', test_contract::TEST_CLASS_HASH.try_into().unwrap(), [].span()); -} - diff --git a/crates/dojo-core/src/tests/world/acl.cairo b/crates/dojo-core/src/tests/world/acl.cairo index a6422f087c..9679f1e58b 100644 --- a/crates/dojo-core/src/tests/world/acl.cairo +++ b/crates/dojo-core/src/tests/world/acl.cairo @@ -44,7 +44,12 @@ fn test_grant_owner_not_registered_resource() { } #[test] -#[should_panic(expected: ("Caller `57005` is not an account", 'ENTRYPOINT_FAILED'))] +#[should_panic( + expected: ( + "Caller `57005` is not the owner of the resource `3123252206139358744730647958636922105676576163624049771737508399526017186883`", + 'ENTRYPOINT_FAILED' + ) +)] fn test_grant_owner_through_malicious_contract() { let world = deploy_world(); world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); @@ -84,7 +89,12 @@ fn test_grant_owner_fails_for_non_owner() { } #[test] -#[should_panic(expected: ("Caller `57005` is not an account", 'ENTRYPOINT_FAILED'))] +#[should_panic( + expected: ( + "Caller `57005` is not the owner of the resource `3123252206139358744730647958636922105676576163624049771737508399526017186883`", + 'ENTRYPOINT_FAILED' + ) +)] fn test_revoke_owner_through_malicious_contract() { let world = deploy_world(); world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); @@ -151,7 +161,12 @@ fn test_writer_not_registered_resource() { } #[test] -#[should_panic(expected: ("Caller `57005` is not an account", 'ENTRYPOINT_FAILED'))] +#[should_panic( + expected: ( + "Caller `57005` is not the owner of the resource `3123252206139358744730647958636922105676576163624049771737508399526017186883`", + 'ENTRYPOINT_FAILED' + ) +)] fn test_grant_writer_through_malicious_contract() { let world = deploy_world(); world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); @@ -191,7 +206,12 @@ fn test_grant_writer_fails_for_non_owner() { } #[test] -#[should_panic(expected: ("Caller `57005` is not an account", 'ENTRYPOINT_FAILED'))] +#[should_panic( + expected: ( + "Caller `57005` is not the owner of the resource `3123252206139358744730647958636922105676576163624049771737508399526017186883`", + 'ENTRYPOINT_FAILED' + ) +)] fn test_revoke_writer_through_malicious_contract() { let world = deploy_world(); world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); diff --git a/crates/dojo-core/src/tests/world/resources.cairo b/crates/dojo-core/src/tests/world/resources.cairo index 39c4fb5488..94702f02a7 100644 --- a/crates/dojo-core/src/tests/world/resources.cairo +++ b/crates/dojo-core/src/tests/world/resources.cairo @@ -100,7 +100,12 @@ fn test_set_metadata_not_possible_for_random_account() { } #[test] -#[should_panic(expected: ("Caller `57005` is not an account", 'ENTRYPOINT_FAILED',))] +#[should_panic( + expected: ( + "Caller `57005` is not the owner of the resource `3123252206139358744730647958636922105676576163624049771737508399526017186883`", + 'ENTRYPOINT_FAILED', + ) +)] fn test_set_metadata_through_malicious_contract() { let world = spawn_test_world(["dojo"].span(), [foo::TEST_CLASS_HASH].span(),); @@ -217,7 +222,7 @@ fn test_upgrade_model_from_model_writer() { let alice = starknet::contract_address_const::<0xa11ce>(); let world = deploy_world(); - world.register_namespace(Model::::namespace()); + // dojo namespace is registered by the deploy_world function. world.register_model(foo::TEST_CLASS_HASH.try_into().unwrap()); world.grant_owner(Model::::namespace_hash(), bob); world.grant_writer(Model::::namespace_hash(), alice); @@ -257,8 +262,10 @@ fn test_register_model_with_unregistered_namespace() { world.register_model(buzz::TEST_CLASS_HASH.try_into().unwrap()); } +// It's CONTRACT_NOT_DEPLOYED for now as in this example the contract is not a dojo contract +// and it's not the account that is calling the register_model function. #[test] -#[should_panic(expected: ("Caller `57005` is not an account", 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ('CONTRACT_NOT_DEPLOYED', 'ENTRYPOINT_FAILED',))] fn test_register_model_through_malicious_contract() { let bob = starknet::contract_address_const::<0xb0b>(); let malicious_contract = starknet::contract_address_const::<0xdead>(); @@ -295,6 +302,7 @@ fn test_register_namespace() { } #[test] +#[should_panic(expected: ("Namespace `namespace` is already registered", 'ENTRYPOINT_FAILED',))] fn test_register_namespace_already_registered_same_caller() { let world = deploy_world(); @@ -302,19 +310,8 @@ fn test_register_namespace_already_registered_same_caller() { starknet::testing::set_account_contract_address(bob); starknet::testing::set_contract_address(bob); - let namespace = "namespace"; - let hash = bytearray_hash(@namespace); - - world.register_namespace(namespace.clone()); - - drop_all_events(world.contract_address); - - world.register_namespace(namespace); - - assert(world.is_owner(hash, bob), 'namespace not registered'); - - let event = starknet::testing::pop_log_raw(world.contract_address); - assert(event.is_none(), 'unexpected event'); + world.register_namespace("namespace"); + world.register_namespace("namespace"); } #[test] @@ -335,20 +332,6 @@ fn test_register_namespace_already_registered_other_caller() { world.register_namespace("namespace"); } -#[test] -#[should_panic(expected: ("Caller `48879` is not an account", 'ENTRYPOINT_FAILED',))] -fn test_register_namespace_is_not_a_direct_call_from_account() { - let world = deploy_world(); - - let bob = starknet::contract_address_const::<0xb0b>(); - let malicious_contract = starknet::contract_address_const::<0xbeef>(); - - starknet::testing::set_account_contract_address(bob); - starknet::testing::set_contract_address(malicious_contract); - - world.register_namespace("namespace"); -} - #[test] fn test_deploy_contract_for_namespace_owner() { let world = deploy_world(); @@ -415,8 +398,10 @@ fn test_deploy_contract_with_unregistered_namespace() { world.deploy_contract('salt1', buzz_contract::TEST_CLASS_HASH.try_into().unwrap(),); } +// It's CONTRACT_NOT_DEPLOYED for now as in this example the contract is not a dojo contract +// and it's not the account that is calling the deploy_contract function. #[test] -#[should_panic(expected: ("Caller `57005` is not an account", 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ('CONTRACT_NOT_DEPLOYED', 'ENTRYPOINT_FAILED',))] fn test_deploy_contract_through_malicious_contract() { let world = deploy_world(); @@ -515,7 +500,12 @@ fn test_upgrade_contract_from_random_account() { } #[test] -#[should_panic(expected: ("Caller `57005` is not an account", 'ENTRYPOINT_FAILED',))] +#[should_panic( + expected: ( + "Caller `57005` is not the owner of the resource `2368393732245529956313345237151518608283468650081902115301417183793437311044`", + 'ENTRYPOINT_FAILED', + ) +)] fn test_upgrade_contract_through_malicious_contract() { let world = deploy_world(); let class_hash = test_contract::TEST_CLASS_HASH.try_into().unwrap(); diff --git a/crates/dojo-core/src/tests/world/world.cairo b/crates/dojo-core/src/tests/world/world.cairo index 6dcc8f3a8a..5ee498982b 100644 --- a/crates/dojo-core/src/tests/world/world.cairo +++ b/crates/dojo-core/src/tests/world/world.cairo @@ -11,7 +11,7 @@ use dojo::world::{ }; use dojo::tests::helpers::{ IbarDispatcher, IbarDispatcherTrait, drop_all_events, deploy_world_and_bar, Foo, foo, bar, - Character, character, test_contract + Character, character, test_contract, test_contract_with_dojo_init_args }; use dojo::utils::test::{spawn_test_world, deploy_with_world_address, GasCounterTrait}; @@ -331,19 +331,114 @@ fn test_facts_registry_event_emit() { ); } -#[starknet::interface] -trait IDojoInit { - fn dojo_init(self: @ContractState) -> felt252; -} +use test_contract::IDojoInitDispatcherTrait; #[test] #[available_gas(6000000)] -#[should_panic(expected: ('Only world can init', 'ENTRYPOINT_FAILED'))] -fn test_can_call_init() { +#[should_panic( + expected: ( + "Only the world can init contract `dojo-test_contract`, but caller is `0`", + 'ENTRYPOINT_FAILED' + ) +)] +fn test_can_call_init_only_world() { let world = deploy_world(); let address = world .deploy_contract('salt1', test_contract::TEST_CLASS_HASH.try_into().unwrap()); - let dojo_init = IDojoInitDispatcher { contract_address: address }; - dojo_init.dojo_init(); + let d = test_contract::IDojoInitDispatcher { contract_address: address }; + d.dojo_init(); +} + +#[test] +#[available_gas(6000000)] +#[should_panic( + expected: ( + "Caller `4919` cannot initialize contract `dojo-test_contract` (not owner)", + 'ENTRYPOINT_FAILED' + ) +)] +fn test_can_call_init_only_owner() { + let world = deploy_world(); + let _address = world + .deploy_contract('salt1', test_contract::TEST_CLASS_HASH.try_into().unwrap()); + + let bob = starknet::contract_address_const::<0x1337>(); + starknet::testing::set_contract_address(bob); + + world.init_contract(selector_from_tag!("dojo-test_contract"), [].span()); +} + +#[test] +#[available_gas(6000000)] +fn test_can_call_init_default() { + let world = deploy_world(); + let _address = world + .deploy_contract('salt1', test_contract::TEST_CLASS_HASH.try_into().unwrap()); + + world.init_contract(selector_from_tag!("dojo-test_contract"), [].span()); +} + +#[test] +#[available_gas(6000000)] +fn test_can_call_init_args() { + let world = deploy_world(); + let _address = world + .deploy_contract( + 'salt1', test_contract_with_dojo_init_args::TEST_CLASS_HASH.try_into().unwrap() + ); + + world.init_contract(selector_from_tag!("dojo-test_contract_with_dojo_init_args"), [1].span()); +} + +use test_contract_with_dojo_init_args::IDojoInitDispatcherTrait as IDojoInitArgs; + +#[test] +#[available_gas(6000000)] +#[should_panic( + expected: ( + "Only the world can init contract `dojo-test_contract_with_dojo_init_args`, but caller is `0`", + 'ENTRYPOINT_FAILED' + ) +)] +fn test_can_call_init_only_world_args() { + let world = deploy_world(); + let address = world + .deploy_contract( + 'salt1', test_contract_with_dojo_init_args::TEST_CLASS_HASH.try_into().unwrap() + ); + + let d = test_contract_with_dojo_init_args::IDojoInitDispatcher { contract_address: address }; + d.dojo_init(123); +} + +use dojo::world::update::IUpgradeableStateDispatcherTrait; + +#[test] +#[available_gas(6000000)] +#[should_panic( + expected: ("Caller `4919` can't upgrade state (not world owner)", 'ENTRYPOINT_FAILED') +)] +fn test_upgrade_state_not_owner() { + let world = deploy_world(); + + let not_owner = starknet::contract_address_const::<0x1337>(); + starknet::testing::set_contract_address(not_owner); + starknet::testing::set_account_contract_address(not_owner); + + let output = dojo::world::update::ProgramOutput { + prev_state_root: 0, + new_state_root: 0, + block_number: 0, + block_hash: 0, + config_hash: 0, + world_da_hash: 0, + message_to_starknet_segment: [].span(), + message_to_appchain_segment: [].span(), + }; + + let d = dojo::world::update::IUpgradeableStateDispatcher { + contract_address: world.contract_address + }; + d.upgrade_state([].span(), output, 0); } diff --git a/crates/dojo-core/src/world/errors.cairo b/crates/dojo-core/src/world/errors.cairo index e4b4492f97..ca1cadfb5c 100644 --- a/crates/dojo-core/src/world/errors.cairo +++ b/crates/dojo-core/src/world/errors.cairo @@ -8,6 +8,14 @@ pub fn no_write_access_with_tags( format!("Caller `{}` has no write access on {} `{}`", contract_tag, on_type, on_tag) } +pub fn not_owner_init(contract_tag: @ByteArray, caller: ContractAddress) -> ByteArray { + format!("Caller `{:?}` cannot initialize contract `{}` (not owner)", caller, contract_tag) +} + +pub fn contract_already_initialized(contract_tag: @ByteArray) -> ByteArray { + format!("Contract `{}` has already been initialized", contract_tag) +} + pub fn namespace_already_registered(namespace: @ByteArray) -> ByteArray { format!("Namespace `{}` is already registered", namespace) } @@ -55,3 +63,7 @@ pub fn resource_conflict(name: @ByteArray, expected_type: @ByteArray) -> ByteArr pub fn no_model_write_access(tag: @ByteArray, caller: ContractAddress) -> ByteArray { format!("Caller `{:?}` has no write access on model `{}`", caller, tag) } + +pub fn no_world_owner(caller: ContractAddress, target: @ByteArray) -> ByteArray { + format!("Caller `{:?}` can't {} (not world owner)", caller, target) +} diff --git a/crates/dojo-core/src/world/world_contract.cairo b/crates/dojo-core/src/world/world_contract.cairo index df8207b09c..c43cea508e 100644 --- a/crates/dojo-core/src/world/world_contract.cairo +++ b/crates/dojo-core/src/world/world_contract.cairo @@ -361,8 +361,7 @@ pub mod world { /// /// `metadata` - The metadata content for the resource. fn set_metadata(ref self: ContractState, metadata: ResourceMetadata) { - self.assert_caller_is_account(); - self.assert_resource_owner(metadata.resource_id); + self.assert_caller_is_resource_owner(metadata.resource_id); self .write_model_entity( @@ -402,13 +401,11 @@ pub mod world { /// * `resource` - The resource. /// * `address` - The contract address. fn grant_owner(ref self: ContractState, resource: felt252, address: ContractAddress) { - self.assert_caller_is_account(); - if self.resources.read(resource).is_unregistered() { panic_with_byte_array(@errors::resource_not_registered(resource)); } - self.assert_resource_owner(resource); + self.assert_caller_is_resource_owner(resource); self.owners.write((resource, address), true); @@ -425,13 +422,11 @@ pub mod world { /// * `resource` - The resource. /// * `address` - The contract address. fn revoke_owner(ref self: ContractState, resource: felt252, address: ContractAddress) { - self.assert_caller_is_account(); - if self.resources.read(resource).is_unregistered() { panic_with_byte_array(@errors::resource_not_registered(resource)); } - self.assert_resource_owner(resource); + self.assert_caller_is_resource_owner(resource); self.owners.write((resource, address), false); @@ -462,13 +457,11 @@ pub mod world { /// * `resource` - The hash of the resource name. /// * `contract` - The name of the contract. fn grant_writer(ref self: ContractState, resource: felt252, contract: ContractAddress) { - self.assert_caller_is_account(); - if self.resources.read(resource).is_unregistered() { panic_with_byte_array(@errors::resource_not_registered(resource)); } - self.assert_resource_owner(resource); + self.assert_caller_is_resource_owner(resource); self.writers.write((resource, contract), true); @@ -485,13 +478,11 @@ pub mod world { /// * `model` - The name of the model. /// * `contract` - The name of the contract. fn revoke_writer(ref self: ContractState, resource: felt252, contract: ContractAddress) { - self.assert_caller_is_account(); - if self.resources.read(resource).is_unregistered() { panic_with_byte_array(@errors::resource_not_registered(resource)); } - self.assert_resource_owner(resource); + self.assert_caller_is_resource_owner(resource); self.writers.write((resource, contract), false); @@ -505,8 +496,6 @@ pub mod world { /// /// * `class_hash` - The class hash of the model to be registered. fn register_model(ref self: ContractState, class_hash: ClassHash) { - self.assert_caller_is_account(); - let caller = get_caller_address(); let salt = self.models_salt.read(); @@ -525,7 +514,7 @@ pub mod world { panic_with_byte_array(@errors::namespace_not_registered(@namespace)); } - self.assert_namespace_write_access(@namespace, namespace_hash); + self.assert_caller_namespace_write_access(@namespace, namespace_hash); let model = self.resources.read(selector); if !model.is_unregistered() { @@ -539,8 +528,6 @@ pub mod world { } fn upgrade_model(ref self: ContractState, class_hash: ClassHash) { - self.assert_caller_is_account(); - let caller = get_caller_address(); let salt = self.models_salt.read(); @@ -555,7 +542,7 @@ pub mod world { panic_with_byte_array(@errors::namespace_not_registered(@namespace)); } - self.assert_namespace_write_access(@namespace, namespace_hash); + self.assert_caller_namespace_write_access(@namespace, namespace_hash); if selector.is_zero() { panic_with_byte_array(@errors::invalid_resource_selector(selector)); @@ -600,18 +587,14 @@ pub mod world { /// /// * `namespace` - The name of the namespace to be registered. fn register_namespace(ref self: ContractState, namespace: ByteArray) { - self.assert_caller_is_account(); - let caller = get_caller_address(); let hash = bytearray_hash(@namespace); match self.resources.read(hash) { - Resource::Namespace => { - if !self.is_owner(hash, caller) { - panic_with_byte_array(@errors::namespace_already_registered(@namespace)); - } - }, + Resource::Namespace => panic_with_byte_array( + @errors::namespace_already_registered(@namespace) + ), Resource::Unregistered => { self.resources.write(hash, Resource::Namespace); self.owners.write((hash, caller), true); @@ -638,8 +621,6 @@ pub mod world { fn deploy_contract( ref self: ContractState, salt: felt252, class_hash: ClassHash, ) -> ContractAddress { - self.assert_caller_is_account(); - let caller = get_caller_address(); let (contract_address, _) = deploy_syscall( @@ -658,7 +639,7 @@ pub mod world { panic_with_byte_array(@errors::namespace_not_registered(@namespace)); } - self.assert_namespace_write_access(@namespace, namespace_hash); + self.assert_caller_namespace_write_access(@namespace, namespace_hash); let selector = dispatcher.selector(); self.owners.write((selector, caller), true); @@ -685,8 +666,7 @@ pub mod world { fn upgrade_contract( ref self: ContractState, selector: felt252, class_hash: ClassHash ) -> ClassHash { - self.assert_caller_is_account(); - self.assert_resource_owner(selector); + self.assert_caller_is_resource_owner(selector); if let Resource::Contract((_, contract_address)) = self.resources.read(selector) { IUpgradeableDispatcher { contract_address }.upgrade(class_hash); @@ -707,15 +687,28 @@ pub mod world { /// * `init_calldata` - Calldata used to initialize the contract. fn init_contract(ref self: ContractState, selector: felt252, init_calldata: Span) { if let Resource::Contract((_, contract_address)) = self.resources.read(selector) { + let caller = get_caller_address(); + + let dispatcher = IContractDispatcher { contract_address }; + let tag = dispatcher.tag(); + if self.initialized_contract.read(selector) { - let dispatcher = IContractDispatcher { contract_address }; - let tag = dispatcher.tag(); - panic!("Contract {} has already been initialized", tag); + panic_with_byte_array(@errors::contract_already_initialized(@tag)); } else { + if !self.is_owner(selector, caller) { + panic_with_byte_array(@errors::not_owner_init(@tag, caller)); + } + + // For the init, to ensure only the world can call the init function, + // the verification is done in the init function of the contract: + // `crates/dojo-lang/src/contract.rs#L140` + // `crates/dojo-lang/src/contract.rs#L331` + starknet::syscalls::call_contract_syscall( contract_address, DOJO_INIT_SELECTOR, init_calldata ) .unwrap_syscall(); + self.initialized_contract.write(selector, true); EventEmitter::emit(ref self, ContractInitialized { selector, init_calldata }); @@ -795,7 +788,7 @@ pub mod world { values: Span, layout: Layout ) { - self.assert_model_write_access(model_selector); + self.assert_caller_model_write_access(model_selector); self.set_entity_internal(model_selector, index, values, layout); } @@ -810,7 +803,7 @@ pub mod world { fn delete_entity( ref self: ContractState, model_selector: felt252, index: ModelIndex, layout: Layout ) { - self.assert_model_write_access(model_selector); + self.assert_caller_model_write_access(model_selector); self.delete_entity_internal(model_selector, index, layout); } @@ -844,8 +837,6 @@ pub mod world { /// /// * `new_class_hash` - The new world class hash. fn upgrade(ref self: ContractState, new_class_hash: ClassHash) { - self.assert_caller_is_account(); - assert(new_class_hash.is_non_zero(), 'invalid class_hash'); if !self.is_caller_world_owner() { @@ -868,6 +859,12 @@ pub mod world { program_output: ProgramOutput, program_hash: felt252 ) { + if !self.is_caller_world_owner() { + panic_with_byte_array( + @errors::no_world_owner(get_caller_address(), @"upgrade state") + ); + } + let mut da_hasher = PedersenTrait::new(0); let mut i = 0; loop { @@ -930,27 +927,12 @@ pub mod world { self.is_owner(WORLD, get_caller_address()) } - /// Asserts that the caller is an account. - /// - /// This check is done to be sure that a sensible world function has been directly called - /// from an account (with sozo for example), to avoid any malicious contract between the - /// account and the world to be able to call some functions with account privileges. - #[inline(always)] - fn assert_caller_is_account(self: @ContractState) { - let caller = get_caller_address(); - let account = get_tx_info().unbox().account_contract_address; - - if caller != account { - panic_with_byte_array(@errors::caller_not_account(caller)); - } - } - /// Panics if the caller is NOT an owner of the resource. /// /// # Arguments /// * `resource_selector` - the selector of the resource. #[inline(always)] - fn assert_resource_owner(self: @ContractState, resource_selector: felt252) { + fn assert_caller_is_resource_owner(self: @ContractState, resource_selector: felt252) { let caller = get_caller_address(); if self.is_owner(resource_selector, caller) { @@ -969,7 +951,7 @@ pub mod world { /// # Arguments /// * `model_selector` - the selector of the model. #[inline(always)] - fn assert_model_write_access(self: @ContractState, model_selector: felt252) { + fn assert_caller_model_write_access(self: @ContractState, model_selector: felt252) { let caller = get_caller_address(); // Must have owner or writer role on the namespace or on the model. @@ -1036,7 +1018,7 @@ pub mod world { /// * `namespace` - the namespace name. /// * `namespace_hash` - the hash of the namespace. #[inline(always)] - fn assert_namespace_write_access( + fn assert_caller_namespace_write_access( self: @ContractState, namespace: @ByteArray, namespace_hash: felt252 ) { let caller = get_caller_address(); @@ -1051,6 +1033,8 @@ pub mod world { return; } + // We know it's an account and return the explicit error message as no tag will match + // the account. if caller == get_tx_info().account_contract_address { panic_with_byte_array(@errors::no_namespace_write_access(caller, namespace)); } @@ -1068,6 +1052,9 @@ pub mod world { @errors::no_write_access_with_tags(@d.tag(), @"namespace", namespace) ); } else { + // This is in theory unreachable code as the contract call syscall made by the + // dispatcher will panic. Which may lead to a bad user experience in testing as the + // error will be something like "CONTRACT_NOT_DEPLOYED". panic_with_byte_array(@errors::no_namespace_write_access(caller, namespace)); } } diff --git a/crates/dojo-lang/src/contract.rs b/crates/dojo-lang/src/contract.rs index 337c01a935..23810b113b 100644 --- a/crates/dojo-lang/src/contract.rs +++ b/crates/dojo-lang/src/contract.rs @@ -130,17 +130,21 @@ impl DojoContract { let node = RewriteNode::interpolate_patched( " #[starknet::interface] - trait IDojoInit { + pub trait IDojoInit { fn $init_name$(self: @ContractState); } #[abi(embed_v0)] - impl IDojoInitImpl of IDojoInit { + pub impl IDojoInitImpl of IDojoInit { fn $init_name$(self: @ContractState) { - assert(starknet::get_caller_address() == \ - self.world().contract_address, 'Only world can init'); - assert(self.world().is_owner(self.selector(), \ - starknet::get_tx_info().account_contract_address), 'Only owner can init'); + if starknet::get_caller_address() != self.world().contract_address { + core::panics::panic_with_byte_array( + @format!(\"Only the world can init contract `{}`, but caller \ + is `{:?}`\", + self.tag(), + starknet::get_caller_address(), + )); + } } } ", @@ -294,26 +298,26 @@ impl DojoContract { let trait_node = RewriteNode::interpolate_patched( "#[starknet::interface] - trait IDojoInit { - fn dojo_init($params_str$); + pub trait IDojoInit { + fn $init_name$($params_str$); } ", - &UnorderedHashMap::from([( - "params_str".to_string(), - RewriteNode::Text(params_str.clone()), - )]), + &UnorderedHashMap::from([ + ("init_name".to_string(), RewriteNode::Text(DOJO_INIT_FN.to_string())), + ("params_str".to_string(), RewriteNode::Text(params_str.clone())), + ]), ); let impl_node = RewriteNode::Text( " #[abi(embed_v0)] - impl IDojoInitImpl of IDojoInit { + pub impl IDojoInitImpl of IDojoInit { " .to_string(), ); let declaration_node = RewriteNode::Mapped { - node: Box::new(RewriteNode::Text(format!("fn dojo_init({}) {{", params_str))), + node: Box::new(RewriteNode::Text(format!("fn {}({}) {{", DOJO_INIT_FN, params_str))), origin: fn_ast.declaration(db).as_syntax_node().span_without_trivia(db), }; @@ -324,8 +328,9 @@ impl DojoContract { }; let assert_world_caller_node = RewriteNode::Text( - "assert(starknet::get_caller_address() == self.world().contract_address, 'Only world \ - can init');" + "if starknet::get_caller_address() != self.world().contract_address { \ + core::panics::panic_with_byte_array(@format!(\"Only the world can init contract \ + `{}`, but caller is `{:?}`\", self.tag(), starknet::get_caller_address())); }" .to_string(), ); diff --git a/crates/dojo-lang/src/manifest_test_data/compiler_cairo/manifests/dev/base/dojo-world.toml b/crates/dojo-lang/src/manifest_test_data/compiler_cairo/manifests/dev/base/dojo-world.toml index 38a401a6d8..2b3b1409df 100644 --- a/crates/dojo-lang/src/manifest_test_data/compiler_cairo/manifests/dev/base/dojo-world.toml +++ b/crates/dojo-lang/src/manifest_test_data/compiler_cairo/manifests/dev/base/dojo-world.toml @@ -1,6 +1,6 @@ kind = "Class" -class_hash = "0x3715f072aa1c07be724249fcda8b0322687f6c5c585eebc4402d162649c707c" -original_class_hash = "0x3715f072aa1c07be724249fcda8b0322687f6c5c585eebc4402d162649c707c" +class_hash = "0xa349b743d361ce4567361475a89b84a386bb383448c6926954e5fe0b525597" +original_class_hash = "0xa349b743d361ce4567361475a89b84a386bb383448c6926954e5fe0b525597" abi = "manifests/dev/base/abis/dojo-world.json" tag = "dojo-world" manifest_name = "dojo-world" diff --git a/crates/sozo/ops/src/tests/model.rs b/crates/sozo/ops/src/tests/model.rs index 2edc2d4299..3b369b8928 100644 --- a/crates/sozo/ops/src/tests/model.rs +++ b/crates/sozo/ops/src/tests/model.rs @@ -58,8 +58,7 @@ async fn test_model_ops() { ) .await .unwrap(), - Felt::from_hex("0x604735fb6510c558ba3ae21972fcbdb1b4234bedcbc990910bd7efd194e7db3") - .unwrap() + Felt::from_hex("0x5581faa4aa9c7cf1903a7e07f28707a0a599b602ca13f3d2f88d68322e240d").unwrap() ); let layout = diff --git a/examples/spawn-and-move/dojo_dev.toml b/examples/spawn-and-move/dojo_dev.toml index 9ae05eaa54..b468dae76b 100644 --- a/examples/spawn-and-move/dojo_dev.toml +++ b/examples/spawn-and-move/dojo_dev.toml @@ -14,4 +14,4 @@ rpc_url = "http://localhost:5050/" # Default account for katana with seed = 0 account_address = "0x6162896d1d7ab204c7ccac6dd5f8e9e7c25ecd5ae4fcb4ad32e57786bb46e03" private_key = "0x1800000000300000180000000000030000000000003006001800006600" -world_address = "0x75f37b9d81cd262f3ba32ef89596e4e6eae99b345cf11fc1a85521c6be87c06" +world_address = "0x6a5152f02567ffb01e5da73a92253dacd50f74932e1a87f3cb58723237a6dda" diff --git a/examples/spawn-and-move/manifests/dev/base/contracts/dojo_examples-actions-40b6994c.toml b/examples/spawn-and-move/manifests/dev/base/contracts/dojo_examples-actions-40b6994c.toml index 0a34841a2d..d387ebd05e 100644 --- a/examples/spawn-and-move/manifests/dev/base/contracts/dojo_examples-actions-40b6994c.toml +++ b/examples/spawn-and-move/manifests/dev/base/contracts/dojo_examples-actions-40b6994c.toml @@ -1,6 +1,6 @@ kind = "DojoContract" -class_hash = "0x6bb4a7b55dc9c9b8193beca79526b6b8f8f2c33f5be0662f5215e10883c653f" -original_class_hash = "0x6bb4a7b55dc9c9b8193beca79526b6b8f8f2c33f5be0662f5215e10883c653f" +class_hash = "0x31df0c74e76e64d5701a806c62961a7ca62eda8978666e14c34497b48a7a501" +original_class_hash = "0x31df0c74e76e64d5701a806c62961a7ca62eda8978666e14c34497b48a7a501" base_class_hash = "0x0" abi = "manifests/dev/base/abis/contracts/dojo_examples-actions-40b6994c.json" reads = [] diff --git a/examples/spawn-and-move/manifests/dev/base/contracts/dojo_examples-dungeon-6620e0e6.toml b/examples/spawn-and-move/manifests/dev/base/contracts/dojo_examples-dungeon-6620e0e6.toml index 74d6bb4a20..75d087c886 100644 --- a/examples/spawn-and-move/manifests/dev/base/contracts/dojo_examples-dungeon-6620e0e6.toml +++ b/examples/spawn-and-move/manifests/dev/base/contracts/dojo_examples-dungeon-6620e0e6.toml @@ -1,6 +1,6 @@ kind = "DojoContract" -class_hash = "0x5d2892f0389e921a051daaad07efb49af7a13213ba309a901fc386acef15c3c" -original_class_hash = "0x5d2892f0389e921a051daaad07efb49af7a13213ba309a901fc386acef15c3c" +class_hash = "0x4590a27e4ec7366358ba5f60323777f301435ebbdd113ab02c54b947717530d" +original_class_hash = "0x4590a27e4ec7366358ba5f60323777f301435ebbdd113ab02c54b947717530d" base_class_hash = "0x0" abi = "manifests/dev/base/abis/contracts/dojo_examples-dungeon-6620e0e6.json" reads = [] diff --git a/examples/spawn-and-move/manifests/dev/base/contracts/dojo_examples-mock_token-31599eb2.toml b/examples/spawn-and-move/manifests/dev/base/contracts/dojo_examples-mock_token-31599eb2.toml index dae6e41296..6385a30c6c 100644 --- a/examples/spawn-and-move/manifests/dev/base/contracts/dojo_examples-mock_token-31599eb2.toml +++ b/examples/spawn-and-move/manifests/dev/base/contracts/dojo_examples-mock_token-31599eb2.toml @@ -1,6 +1,6 @@ kind = "DojoContract" -class_hash = "0x71fdf374f04ab0a918b1e8a0578f38ad2d7d0d61da131b8d3e7b0b41a3d2282" -original_class_hash = "0x71fdf374f04ab0a918b1e8a0578f38ad2d7d0d61da131b8d3e7b0b41a3d2282" +class_hash = "0x67edb33671cd2f5b766d073e3dec53b03400761a20f349ea9628cf4c883b393" +original_class_hash = "0x67edb33671cd2f5b766d073e3dec53b03400761a20f349ea9628cf4c883b393" base_class_hash = "0x0" abi = "manifests/dev/base/abis/contracts/dojo_examples-mock_token-31599eb2.json" reads = [] diff --git a/examples/spawn-and-move/manifests/dev/base/contracts/dojo_examples-others-61de2c18.toml b/examples/spawn-and-move/manifests/dev/base/contracts/dojo_examples-others-61de2c18.toml index 9db0728b63..5a43d3fad8 100644 --- a/examples/spawn-and-move/manifests/dev/base/contracts/dojo_examples-others-61de2c18.toml +++ b/examples/spawn-and-move/manifests/dev/base/contracts/dojo_examples-others-61de2c18.toml @@ -1,6 +1,6 @@ kind = "DojoContract" -class_hash = "0x647fc1b2d2e902e6304e127b36995d8f57fe45c38e38e15d8860db508dbf24a" -original_class_hash = "0x647fc1b2d2e902e6304e127b36995d8f57fe45c38e38e15d8860db508dbf24a" +class_hash = "0x40e824b8814bafef18cce2cf68f5765e9c9a1c86f55a8491b0c2a4faebdcc87" +original_class_hash = "0x40e824b8814bafef18cce2cf68f5765e9c9a1c86f55a8491b0c2a4faebdcc87" base_class_hash = "0x0" abi = "manifests/dev/base/abis/contracts/dojo_examples-others-61de2c18.json" reads = [] diff --git a/examples/spawn-and-move/manifests/dev/base/dojo-world.toml b/examples/spawn-and-move/manifests/dev/base/dojo-world.toml index 38a401a6d8..2b3b1409df 100644 --- a/examples/spawn-and-move/manifests/dev/base/dojo-world.toml +++ b/examples/spawn-and-move/manifests/dev/base/dojo-world.toml @@ -1,6 +1,6 @@ kind = "Class" -class_hash = "0x3715f072aa1c07be724249fcda8b0322687f6c5c585eebc4402d162649c707c" -original_class_hash = "0x3715f072aa1c07be724249fcda8b0322687f6c5c585eebc4402d162649c707c" +class_hash = "0xa349b743d361ce4567361475a89b84a386bb383448c6926954e5fe0b525597" +original_class_hash = "0xa349b743d361ce4567361475a89b84a386bb383448c6926954e5fe0b525597" abi = "manifests/dev/base/abis/dojo-world.json" tag = "dojo-world" manifest_name = "dojo-world" diff --git a/examples/spawn-and-move/manifests/dev/deployment/manifest.json b/examples/spawn-and-move/manifests/dev/deployment/manifest.json index 5bba1ae3e2..65a049ad32 100644 --- a/examples/spawn-and-move/manifests/dev/deployment/manifest.json +++ b/examples/spawn-and-move/manifests/dev/deployment/manifest.json @@ -1,8 +1,8 @@ { "world": { "kind": "WorldContract", - "class_hash": "0x3715f072aa1c07be724249fcda8b0322687f6c5c585eebc4402d162649c707c", - "original_class_hash": "0x3715f072aa1c07be724249fcda8b0322687f6c5c585eebc4402d162649c707c", + "class_hash": "0xa349b743d361ce4567361475a89b84a386bb383448c6926954e5fe0b525597", + "original_class_hash": "0xa349b743d361ce4567361475a89b84a386bb383448c6926954e5fe0b525597", "abi": [ { "type": "impl", @@ -1229,8 +1229,8 @@ ] } ], - "address": "0x75f37b9d81cd262f3ba32ef89596e4e6eae99b345cf11fc1a85521c6be87c06", - "transaction_hash": "0x4caecaee04b1af0f999a4f5fdb7102e8e1821aac296b260458d422ae0a41a1f", + "address": "0x6a5152f02567ffb01e5da73a92253dacd50f74932e1a87f3cb58723237a6dda", + "transaction_hash": "0x67359c73d4f29e73a35f681bc3e807b3dc694c3ea699a9b2f7d3cd166e6d877", "block_number": 3, "seed": "dojo_examples", "metadata": { @@ -1250,9 +1250,9 @@ "contracts": [ { "kind": "DojoContract", - "address": "0x2cd5e4ee3b898ff0578e0eec1ef5947a0a6b2c0d08ab95a14010c54d26265dc", - "class_hash": "0x6bb4a7b55dc9c9b8193beca79526b6b8f8f2c33f5be0662f5215e10883c653f", - "original_class_hash": "0x6bb4a7b55dc9c9b8193beca79526b6b8f8f2c33f5be0662f5215e10883c653f", + "address": "0x643578322854b652b2f84bcce2cc8db6707cc80dcef1def20d9c4c6a8bb1a8e", + "class_hash": "0x31df0c74e76e64d5701a806c62961a7ca62eda8978666e14c34497b48a7a501", + "original_class_hash": "0x31df0c74e76e64d5701a806c62961a7ca62eda8978666e14c34497b48a7a501", "base_class_hash": "0x2427dd10a58850ac9a5ca6ce04b7771b05330fd18f2e481831ad903b969e6b2", "abi": [ { @@ -1664,9 +1664,9 @@ }, { "kind": "DojoContract", - "address": "0x1470b0304ed67a22acdca949eb99d50ff7a6def6de539b19254e121904c12c", - "class_hash": "0x5d2892f0389e921a051daaad07efb49af7a13213ba309a901fc386acef15c3c", - "original_class_hash": "0x5d2892f0389e921a051daaad07efb49af7a13213ba309a901fc386acef15c3c", + "address": "0x544e5f126803b8c09711533d4f1731da3a0552841cd2c8fdc656cc9f6bb8bde", + "class_hash": "0x4590a27e4ec7366358ba5f60323777f301435ebbdd113ab02c54b947717530d", + "original_class_hash": "0x4590a27e4ec7366358ba5f60323777f301435ebbdd113ab02c54b947717530d", "base_class_hash": "0x2427dd10a58850ac9a5ca6ce04b7771b05330fd18f2e481831ad903b969e6b2", "abi": [ { @@ -1903,9 +1903,9 @@ }, { "kind": "DojoContract", - "address": "0x5a651aad0672c139bce3db0770ad128dafae568dde6550dbc5679f819b634fd", - "class_hash": "0x71fdf374f04ab0a918b1e8a0578f38ad2d7d0d61da131b8d3e7b0b41a3d2282", - "original_class_hash": "0x71fdf374f04ab0a918b1e8a0578f38ad2d7d0d61da131b8d3e7b0b41a3d2282", + "address": "0x32c35d3816051018bb7f79e5c7a7e6384b320f9f777515faa554f74a9ed6231", + "class_hash": "0x67edb33671cd2f5b766d073e3dec53b03400761a20f349ea9628cf4c883b393", + "original_class_hash": "0x67edb33671cd2f5b766d073e3dec53b03400761a20f349ea9628cf4c883b393", "base_class_hash": "0x2427dd10a58850ac9a5ca6ce04b7771b05330fd18f2e481831ad903b969e6b2", "abi": [ { @@ -2124,9 +2124,9 @@ }, { "kind": "DojoContract", - "address": "0x5114288a545fd35096cacb0b4a1869aadba49b6403bea303f603c23f6455375", - "class_hash": "0x647fc1b2d2e902e6304e127b36995d8f57fe45c38e38e15d8860db508dbf24a", - "original_class_hash": "0x647fc1b2d2e902e6304e127b36995d8f57fe45c38e38e15d8860db508dbf24a", + "address": "0x79c9d1c008b6550c8fc92e3a0a6a24f3d461f7d1fea09f9c33127051d61c2c0", + "class_hash": "0x40e824b8814bafef18cce2cf68f5765e9c9a1c86f55a8491b0c2a4faebdcc87", + "original_class_hash": "0x40e824b8814bafef18cce2cf68f5765e9c9a1c86f55a8491b0c2a4faebdcc87", "base_class_hash": "0x2427dd10a58850ac9a5ca6ce04b7771b05330fd18f2e481831ad903b969e6b2", "abi": [ { diff --git a/examples/spawn-and-move/manifests/dev/deployment/manifest.toml b/examples/spawn-and-move/manifests/dev/deployment/manifest.toml index 37c31c08c1..62a597cb00 100644 --- a/examples/spawn-and-move/manifests/dev/deployment/manifest.toml +++ b/examples/spawn-and-move/manifests/dev/deployment/manifest.toml @@ -1,10 +1,10 @@ [world] kind = "WorldContract" -class_hash = "0x3715f072aa1c07be724249fcda8b0322687f6c5c585eebc4402d162649c707c" -original_class_hash = "0x3715f072aa1c07be724249fcda8b0322687f6c5c585eebc4402d162649c707c" +class_hash = "0xa349b743d361ce4567361475a89b84a386bb383448c6926954e5fe0b525597" +original_class_hash = "0xa349b743d361ce4567361475a89b84a386bb383448c6926954e5fe0b525597" abi = "manifests/dev/deployment/abis/dojo-world.json" -address = "0x75f37b9d81cd262f3ba32ef89596e4e6eae99b345cf11fc1a85521c6be87c06" -transaction_hash = "0x4caecaee04b1af0f999a4f5fdb7102e8e1821aac296b260458d422ae0a41a1f" +address = "0x6a5152f02567ffb01e5da73a92253dacd50f74932e1a87f3cb58723237a6dda" +transaction_hash = "0x67359c73d4f29e73a35f681bc3e807b3dc694c3ea699a9b2f7d3cd166e6d877" block_number = 3 seed = "dojo_examples" manifest_name = "dojo-world" @@ -23,9 +23,9 @@ manifest_name = "dojo-base" [[contracts]] kind = "DojoContract" -address = "0x2cd5e4ee3b898ff0578e0eec1ef5947a0a6b2c0d08ab95a14010c54d26265dc" -class_hash = "0x6bb4a7b55dc9c9b8193beca79526b6b8f8f2c33f5be0662f5215e10883c653f" -original_class_hash = "0x6bb4a7b55dc9c9b8193beca79526b6b8f8f2c33f5be0662f5215e10883c653f" +address = "0x643578322854b652b2f84bcce2cc8db6707cc80dcef1def20d9c4c6a8bb1a8e" +class_hash = "0x31df0c74e76e64d5701a806c62961a7ca62eda8978666e14c34497b48a7a501" +original_class_hash = "0x31df0c74e76e64d5701a806c62961a7ca62eda8978666e14c34497b48a7a501" base_class_hash = "0x2427dd10a58850ac9a5ca6ce04b7771b05330fd18f2e481831ad903b969e6b2" abi = "manifests/dev/deployment/abis/contracts/dojo_examples-actions-40b6994c.json" reads = [] @@ -46,9 +46,9 @@ manifest_name = "dojo_examples-actions-40b6994c" [[contracts]] kind = "DojoContract" -address = "0x1470b0304ed67a22acdca949eb99d50ff7a6def6de539b19254e121904c12c" -class_hash = "0x5d2892f0389e921a051daaad07efb49af7a13213ba309a901fc386acef15c3c" -original_class_hash = "0x5d2892f0389e921a051daaad07efb49af7a13213ba309a901fc386acef15c3c" +address = "0x544e5f126803b8c09711533d4f1731da3a0552841cd2c8fdc656cc9f6bb8bde" +class_hash = "0x4590a27e4ec7366358ba5f60323777f301435ebbdd113ab02c54b947717530d" +original_class_hash = "0x4590a27e4ec7366358ba5f60323777f301435ebbdd113ab02c54b947717530d" base_class_hash = "0x2427dd10a58850ac9a5ca6ce04b7771b05330fd18f2e481831ad903b969e6b2" abi = "manifests/dev/deployment/abis/contracts/dojo_examples-dungeon-6620e0e6.json" reads = [] @@ -60,9 +60,9 @@ manifest_name = "dojo_examples-dungeon-6620e0e6" [[contracts]] kind = "DojoContract" -address = "0x5a651aad0672c139bce3db0770ad128dafae568dde6550dbc5679f819b634fd" -class_hash = "0x71fdf374f04ab0a918b1e8a0578f38ad2d7d0d61da131b8d3e7b0b41a3d2282" -original_class_hash = "0x71fdf374f04ab0a918b1e8a0578f38ad2d7d0d61da131b8d3e7b0b41a3d2282" +address = "0x32c35d3816051018bb7f79e5c7a7e6384b320f9f777515faa554f74a9ed6231" +class_hash = "0x67edb33671cd2f5b766d073e3dec53b03400761a20f349ea9628cf4c883b393" +original_class_hash = "0x67edb33671cd2f5b766d073e3dec53b03400761a20f349ea9628cf4c883b393" base_class_hash = "0x2427dd10a58850ac9a5ca6ce04b7771b05330fd18f2e481831ad903b969e6b2" abi = "manifests/dev/deployment/abis/contracts/dojo_examples-mock_token-31599eb2.json" reads = [] @@ -74,9 +74,9 @@ manifest_name = "dojo_examples-mock_token-31599eb2" [[contracts]] kind = "DojoContract" -address = "0x5114288a545fd35096cacb0b4a1869aadba49b6403bea303f603c23f6455375" -class_hash = "0x647fc1b2d2e902e6304e127b36995d8f57fe45c38e38e15d8860db508dbf24a" -original_class_hash = "0x647fc1b2d2e902e6304e127b36995d8f57fe45c38e38e15d8860db508dbf24a" +address = "0x79c9d1c008b6550c8fc92e3a0a6a24f3d461f7d1fea09f9c33127051d61c2c0" +class_hash = "0x40e824b8814bafef18cce2cf68f5765e9c9a1c86f55a8491b0c2a4faebdcc87" +original_class_hash = "0x40e824b8814bafef18cce2cf68f5765e9c9a1c86f55a8491b0c2a4faebdcc87" base_class_hash = "0x2427dd10a58850ac9a5ca6ce04b7771b05330fd18f2e481831ad903b969e6b2" abi = "manifests/dev/deployment/abis/contracts/dojo_examples-others-61de2c18.json" reads = [] diff --git a/examples/spawn-and-move/manifests/release/base/contracts/dojo_examples-actions-40b6994c.toml b/examples/spawn-and-move/manifests/release/base/contracts/dojo_examples-actions-40b6994c.toml index 78d5c93026..a56fc9b106 100644 --- a/examples/spawn-and-move/manifests/release/base/contracts/dojo_examples-actions-40b6994c.toml +++ b/examples/spawn-and-move/manifests/release/base/contracts/dojo_examples-actions-40b6994c.toml @@ -1,6 +1,6 @@ kind = "DojoContract" -class_hash = "0x6bb4a7b55dc9c9b8193beca79526b6b8f8f2c33f5be0662f5215e10883c653f" -original_class_hash = "0x6bb4a7b55dc9c9b8193beca79526b6b8f8f2c33f5be0662f5215e10883c653f" +class_hash = "0x31df0c74e76e64d5701a806c62961a7ca62eda8978666e14c34497b48a7a501" +original_class_hash = "0x31df0c74e76e64d5701a806c62961a7ca62eda8978666e14c34497b48a7a501" base_class_hash = "0x0" abi = "manifests/release/base/abis/contracts/dojo_examples-actions-40b6994c.json" reads = [] diff --git a/examples/spawn-and-move/manifests/release/base/contracts/dojo_examples-dungeon-6620e0e6.toml b/examples/spawn-and-move/manifests/release/base/contracts/dojo_examples-dungeon-6620e0e6.toml index 16b9830374..a3a45a7634 100644 --- a/examples/spawn-and-move/manifests/release/base/contracts/dojo_examples-dungeon-6620e0e6.toml +++ b/examples/spawn-and-move/manifests/release/base/contracts/dojo_examples-dungeon-6620e0e6.toml @@ -1,6 +1,6 @@ kind = "DojoContract" -class_hash = "0x5d2892f0389e921a051daaad07efb49af7a13213ba309a901fc386acef15c3c" -original_class_hash = "0x5d2892f0389e921a051daaad07efb49af7a13213ba309a901fc386acef15c3c" +class_hash = "0x4590a27e4ec7366358ba5f60323777f301435ebbdd113ab02c54b947717530d" +original_class_hash = "0x4590a27e4ec7366358ba5f60323777f301435ebbdd113ab02c54b947717530d" base_class_hash = "0x0" abi = "manifests/release/base/abis/contracts/dojo_examples-dungeon-6620e0e6.json" reads = [] diff --git a/examples/spawn-and-move/manifests/release/base/contracts/dojo_examples-mock_token-31599eb2.toml b/examples/spawn-and-move/manifests/release/base/contracts/dojo_examples-mock_token-31599eb2.toml index 16e42f275e..a91d6e646d 100644 --- a/examples/spawn-and-move/manifests/release/base/contracts/dojo_examples-mock_token-31599eb2.toml +++ b/examples/spawn-and-move/manifests/release/base/contracts/dojo_examples-mock_token-31599eb2.toml @@ -1,6 +1,6 @@ kind = "DojoContract" -class_hash = "0x71fdf374f04ab0a918b1e8a0578f38ad2d7d0d61da131b8d3e7b0b41a3d2282" -original_class_hash = "0x71fdf374f04ab0a918b1e8a0578f38ad2d7d0d61da131b8d3e7b0b41a3d2282" +class_hash = "0x67edb33671cd2f5b766d073e3dec53b03400761a20f349ea9628cf4c883b393" +original_class_hash = "0x67edb33671cd2f5b766d073e3dec53b03400761a20f349ea9628cf4c883b393" base_class_hash = "0x0" abi = "manifests/release/base/abis/contracts/dojo_examples-mock_token-31599eb2.json" reads = [] diff --git a/examples/spawn-and-move/manifests/release/base/contracts/dojo_examples-others-61de2c18.toml b/examples/spawn-and-move/manifests/release/base/contracts/dojo_examples-others-61de2c18.toml index 06f17468c4..0e3f247385 100644 --- a/examples/spawn-and-move/manifests/release/base/contracts/dojo_examples-others-61de2c18.toml +++ b/examples/spawn-and-move/manifests/release/base/contracts/dojo_examples-others-61de2c18.toml @@ -1,6 +1,6 @@ kind = "DojoContract" -class_hash = "0x647fc1b2d2e902e6304e127b36995d8f57fe45c38e38e15d8860db508dbf24a" -original_class_hash = "0x647fc1b2d2e902e6304e127b36995d8f57fe45c38e38e15d8860db508dbf24a" +class_hash = "0x40e824b8814bafef18cce2cf68f5765e9c9a1c86f55a8491b0c2a4faebdcc87" +original_class_hash = "0x40e824b8814bafef18cce2cf68f5765e9c9a1c86f55a8491b0c2a4faebdcc87" base_class_hash = "0x0" abi = "manifests/release/base/abis/contracts/dojo_examples-others-61de2c18.json" reads = [] diff --git a/examples/spawn-and-move/manifests/release/base/dojo-world.toml b/examples/spawn-and-move/manifests/release/base/dojo-world.toml index ecb6fdb514..48b34c3f4d 100644 --- a/examples/spawn-and-move/manifests/release/base/dojo-world.toml +++ b/examples/spawn-and-move/manifests/release/base/dojo-world.toml @@ -1,6 +1,6 @@ kind = "Class" -class_hash = "0x3715f072aa1c07be724249fcda8b0322687f6c5c585eebc4402d162649c707c" -original_class_hash = "0x3715f072aa1c07be724249fcda8b0322687f6c5c585eebc4402d162649c707c" +class_hash = "0xa349b743d361ce4567361475a89b84a386bb383448c6926954e5fe0b525597" +original_class_hash = "0xa349b743d361ce4567361475a89b84a386bb383448c6926954e5fe0b525597" abi = "manifests/release/base/abis/dojo-world.json" tag = "dojo-world" manifest_name = "dojo-world" diff --git a/spawn-and-move-db.tar.gz b/spawn-and-move-db.tar.gz index e0c30d40be..7b811cc13a 100644 Binary files a/spawn-and-move-db.tar.gz and b/spawn-and-move-db.tar.gz differ diff --git a/types-test-db.tar.gz b/types-test-db.tar.gz index e1ea502f5f..c234d2b798 100644 Binary files a/types-test-db.tar.gz and b/types-test-db.tar.gz differ