Skip to content

Commit

Permalink
Add metadata uri to world (#985)
Browse files Browse the repository at this point in the history
  • Loading branch information
tarrencev authored Oct 6, 2023
1 parent 633e26e commit f8ca4c5
Show file tree
Hide file tree
Showing 11 changed files with 218 additions and 35 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions crates/dojo-core/src/test_utils.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ use dojo::world::{world, IWorldDispatcher, IWorldDispatcherTrait};
/// # Returns
/// * address of contract deployed
fn deploy_contract(class_hash: felt252, calldata: Span<felt252>) -> ContractAddress {
let (contract, _) = starknet::deploy_syscall(
class_hash.try_into().unwrap(), 0, calldata, false
)
let (contract, _) = starknet::deploy_syscall(class_hash.try_into().unwrap(), 0, calldata, false)
.unwrap();
contract
}
Expand All @@ -50,7 +48,10 @@ fn spawn_test_world(models: Array<felt252>) -> IWorldDispatcher {
.unwrap();
// deploy world
let (world_address, _) = deploy_syscall(
world::TEST_CLASS_HASH.try_into().unwrap(), 0, array![executor_address.into(), dojo::base::base::TEST_CLASS_HASH].span(), false
world::TEST_CLASS_HASH.try_into().unwrap(),
0,
array![executor_address.into(), dojo::base::base::TEST_CLASS_HASH, 1, 'test_uri'].span(),
false
)
.unwrap();
let world = IWorldDispatcher { contract_address: world_address };
Expand Down
112 changes: 86 additions & 26 deletions crates/dojo-core/src/world.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,15 @@ use option::OptionTrait;

#[starknet::interface]
trait IWorld<T> {
fn metadata_uri(self: @T) -> Span<felt252>;
fn set_metadata_uri(ref self: T, uri: Span<felt252>);
fn model(self: @T, name: felt252) -> ClassHash;
fn register_model(ref self: T, class_hash: ClassHash);
fn deploy_contract(self: @T, salt: felt252, class_hash: ClassHash) -> ContractAddress;
fn uuid(ref self: T) -> usize;
fn emit(self: @T, keys: Array<felt252>, values: Span<felt252>);
fn entity(
self: @T,
model: felt252,
keys: Span<felt252>,
offset: u8,
length: usize,
layout: Span<u8>
self: @T, model: felt252, keys: Span<felt252>, offset: u8, length: usize, layout: Span<u8>
) -> Span<felt252>;
fn set_entity(
ref self: T,
Expand All @@ -26,7 +23,12 @@ trait IWorld<T> {
layout: Span<u8>
);
fn entities(
self: @T, model: felt252, index: Option<felt252>, values: Span<felt252>, values_length: usize, values_layout: Span<u8>
self: @T,
model: felt252,
index: Option<felt252>,
values: Span<felt252>,
values_length: usize,
values_layout: Span<u8>
) -> (Span<felt252>, Span<Span<felt252>>);
fn set_executor(ref self: T, contract_address: ContractAddress);
fn executor(self: @T) -> ContractAddress;
Expand All @@ -51,7 +53,8 @@ mod world {
use starknet::{
get_caller_address, get_contract_address, get_tx_info,
contract_address::ContractAddressIntoFelt252, ClassHash, Zeroable, ContractAddress,
syscalls::{deploy_syscall, emit_event_syscall}, SyscallResult, SyscallResultTrait, SyscallResultTraitImpl
syscalls::{deploy_syscall, emit_event_syscall}, SyscallResult, SyscallResultTrait,
SyscallResultTraitImpl
};

use dojo::database;
Expand All @@ -78,7 +81,8 @@ mod world {
#[derive(Drop, starknet::Event)]
struct WorldSpawned {
address: ContractAddress,
caller: ContractAddress
caller: ContractAddress,
metadata_uri: Span<felt252>
}

#[derive(Drop, starknet::Event)]
Expand Down Expand Up @@ -106,28 +110,27 @@ mod world {
executor_dispatcher: IExecutorDispatcher,
contract_base: ClassHash,
nonce: usize,
metadata_uri: LegacyMap::<usize, felt252>,
models: LegacyMap::<felt252, ClassHash>,
owners: LegacyMap::<(felt252, ContractAddress), bool>,
writers: LegacyMap::<(felt252, ContractAddress), bool>,
}

#[constructor]
fn constructor(ref self: ContractState, executor: ContractAddress, contract_base: ClassHash) {
fn constructor(
ref self: ContractState,
executor: ContractAddress,
contract_base: ClassHash,
metadata_uri: Span<felt252>
) {
let caller = get_caller_address();
self.executor_dispatcher.write(IExecutorDispatcher { contract_address: executor });
self.contract_base.write(contract_base);

self
.owners
.write(
(WORLD, starknet::get_tx_info().unbox().account_contract_address), bool::True(())
);
self.owners.write((WORLD, caller), true);
self.set_metadata_uri(metadata_uri);

EventEmitter::emit(
ref self,
WorldSpawned {
address: get_contract_address(),
caller: get_tx_info().unbox().account_contract_address
}
ref self, WorldSpawned { address: get_contract_address(), caller, metadata_uri }
);
}

Expand All @@ -151,6 +154,54 @@ mod world {

#[external(v0)]
impl World of IWorld<ContractState> {
/// Returns the metadata URI of the world.
///
/// # Returns
///
/// * `Span<felt252>` - The metadata URI of the world.
fn metadata_uri(self: @ContractState) -> Span<felt252> {
let mut uri = array![];

// We add one here since we start i at 1;
let len = self.metadata_uri.read(0) + 1;

let mut i: usize = 1;
loop {
if len == i.into() {
break;
}

uri.append(self.metadata_uri.read(i));
i += 1;
};

uri.span()
}

/// Sets the metadata URI of the world.
///
/// # Arguments
///
/// * `uri` - The new metadata URI to be set.
fn set_metadata_uri(ref self: ContractState, mut uri: Span<felt252>) {
assert(self.is_owner(get_caller_address(), WORLD), 'not owner');

self.metadata_uri.write(0, uri.len().into());

let mut i: usize = 1;
loop {
match uri.pop_front() {
Option::Some(item) => {
self.metadata_uri.write(i, *item);
i += 1;
},
Option::None(_) => {
break;
}
};
};
}

/// Checks if the provided account is an owner of the target.
///
/// # Arguments
Expand Down Expand Up @@ -216,8 +267,7 @@ mod world {
let caller = get_caller_address();

assert(
self.is_owner(caller, model) || self.is_owner(caller, WORLD),
'not owner or writer'
self.is_owner(caller, model) || self.is_owner(caller, WORLD), 'not owner or writer'
);
self.writers.write((model, system), bool::True(()));
}
Expand Down Expand Up @@ -286,8 +336,13 @@ mod world {
/// # Returns
///
/// * `ClassHash` - The class hash of the model.
fn deploy_contract(self: @ContractState, salt: felt252, class_hash: ClassHash) -> ContractAddress {
let (contract_address, _) = deploy_syscall(self.contract_base.read(), salt, array![].span(), false).unwrap_syscall();
fn deploy_contract(
self: @ContractState, salt: felt252, class_hash: ClassHash
) -> ContractAddress {
let (contract_address, _) = deploy_syscall(
self.contract_base.read(), salt, array![].span(), false
)
.unwrap_syscall();
let upgradable_dispatcher = IUpgradeableDispatcher { contract_address };
upgradable_dispatcher.upgrade(class_hash);
contract_address
Expand Down Expand Up @@ -399,7 +454,12 @@ mod world {
/// * `Span<felt252>` - The entity IDs.
/// * `Span<Span<felt252>>` - The entities.
fn entities(
self: @ContractState, model: felt252, index: Option<felt252>, values: Span<felt252>, values_length: usize, values_layout: Span<u8>
self: @ContractState,
model: felt252,
index: Option<felt252>,
values: Span<felt252>,
values_length: usize,
values_layout: Span<u8>
) -> (Span<felt252>, Span<Span<felt252>>) {
let class_hash = self.models.read(model);

Expand Down
31 changes: 29 additions & 2 deletions crates/dojo-core/src/world_test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,35 @@ fn deploy_world() -> IWorldDispatcher {
spawn_test_world(array![])
}

#[test]
#[available_gas(60000000)]
fn test_metadata_uri() {
// Deploy world contract
let world = deploy_world();
let uri = world.metadata_uri();

assert(uri.len() == 1, 'Incorrect metadata uri len');
assert(uri[0] == @'test_uri', 'Incorrect metadata uri');

world.set_metadata_uri(array!['new_uri', 'longer'].span());

let uri = world.metadata_uri();
assert(uri.len() == 2, 'Incorrect metadata uri len');
assert(uri[0] == @'new_uri', 'Incorrect metadata uri 1');
assert(uri[1] == @'longer', 'Incorrect metadata uri 2');
}

#[test]
#[available_gas(60000000)]
#[should_panic]
fn test_set_metadata_uri_reverts_for_not_owner() {
// Deploy world contract
let world = deploy_world();

starknet::testing::set_contract_address(starknet::contract_address_const::<0x1337>());
world.set_metadata_uri(array!['new_uri', 'longer'].span());
}

#[test]
#[available_gas(60000000)]
fn test_entities() {
Expand All @@ -191,7 +220,6 @@ fn test_entities() {
let layout = array![251].span();
let (keys, values) = world.entities('Foo', Option::None(()), query_keys, 2, layout);
assert(keys.len() == 1, 'No keys found for any!');

// query_keys.append(0x1337);
// let (keys, values) = world.entities('Foo', 42, query_keys.span(), 2, layout);
// assert(keys.len() == 1, 'No keys found!');
Expand Down Expand Up @@ -368,4 +396,3 @@ fn test_execute_multiple_worlds() {
assert(data2.a == 7331, 'data2 not stored');
}


34 changes: 33 additions & 1 deletion crates/dojo-lang/src/manifest_test_data/manifest
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ test_manifest_file
"world": {
"name": "world",
"address": null,
"class_hash": "0x45539636cfa153f8ea0975102b04d35f455240c98c1dcf1eeb0013bef358d35",
"class_hash": "0x7cb53315435063879e8aa2487ead65eb1196ac71aa7f2888e9762ac430400d",
"abi": [
{
"type": "impl",
Expand Down Expand Up @@ -77,6 +77,29 @@ test_manifest_file
"type": "interface",
"name": "dojo::world::IWorld",
"items": [
{
"type": "function",
"name": "metadata_uri",
"inputs": [],
"outputs": [
{
"type": "core::array::Span::<core::felt252>"
}
],
"state_mutability": "view"
},
{
"type": "function",
"name": "set_metadata_uri",
"inputs": [
{
"name": "uri",
"type": "core::array::Span::<core::felt252>"
}
],
"outputs": [],
"state_mutability": "external"
},
{
"type": "function",
"name": "model",
Expand Down Expand Up @@ -411,6 +434,10 @@ test_manifest_file
{
"name": "contract_base",
"type": "core::starknet::class_hash::ClassHash"
},
{
"name": "metadata_uri",
"type": "core::array::Span::<core::felt252>"
}
]
},
Expand All @@ -428,6 +455,11 @@ test_manifest_file
"name": "caller",
"type": "core::starknet::contract_address::ContractAddress",
"kind": "data"
},
{
"name": "metadata_uri",
"type": "core::array::Span::<core::felt252>",
"kind": "data"
}
]
},
Expand Down
6 changes: 5 additions & 1 deletion crates/dojo-world/src/migration/strategy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,11 @@ where
world.contract_address = get_contract_address(
salt,
diff.world.local,
&[executor.as_ref().unwrap().contract_address, base.as_ref().unwrap().diff.local],
&[
executor.as_ref().unwrap().contract_address,
base.as_ref().unwrap().diff.local,
FieldElement::ZERO,
],
FieldElement::ZERO,
);
}
Expand Down
1 change: 1 addition & 0 deletions crates/sozo/src/ops/migration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ where
let calldata = vec![
strategy.executor.as_ref().unwrap().contract_address,
strategy.base.as_ref().unwrap().diff.local,
FieldElement::ZERO,
];
deploy_contract(world, "world", calldata, migrator, ui, &txn_config).await?;

Expand Down
1 change: 1 addition & 0 deletions crates/torii/client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ crypto-bigint = "0.5.3"
dojo-types = { path = "../../dojo-types" }
futures-util = "0.3.28"
futures.workspace = true
http = "0.2.9"
parking_lot.workspace = true
serde.workspace = true
serde_json.workspace = true
Expand Down
Loading

0 comments on commit f8ca4c5

Please sign in to comment.