Skip to content

Commit

Permalink
Merge pull request #181 from dojoengine/next
Browse files Browse the repository at this point in the history
Next
  • Loading branch information
ponderingdemocritus committed Jan 20, 2024
2 parents 19ee465 + 9fbbc9e commit df0cd58
Show file tree
Hide file tree
Showing 357 changed files with 10,266 additions and 60 deletions.
21 changes: 21 additions & 0 deletions dojo-book/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# production
/dist

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# typescript
*.tsbuildinfo
1 change: 1 addition & 0 deletions dojo-book/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is a [Vocs](https://vocs.dev) project bootstrapped with the Vocs CLI.
23 changes: 23 additions & 0 deletions dojo-book/docs/pages/cairo/authorization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## Authorization

> Authorization is crucial to a world, just like how authorization is crucial to any smart contract.
As discussed in the [World](./world.md) chapter, Autonomous Worlds (AWs) function as sovereign chains nested within a public blockchain. These Worlds are also open to the public. This structure allows anyone to enhance a World by deploying models or systems. However, this openness also introduces security considerations. Similar to Ethereum, interacting with a model's state within a System requires the appropriate authorization from the model owner.

### Auth Architecture

Every time a `set!` is called in a `System`, the world checks if the `System` has authorization to update the model state. Only when the `System` possesses the necessary authorization, the `set!` is executed. The following diagram illustrates the authorization architecture.

![Authorization Architecture](/dojo-auth.png)

### Providing Authorization

> The deployer of the model is its initial owner. A model owner is able to grant the `owner` and `writer` roles. Only owners can grant a System the `writer` role which allows it to update the model.
`sozo` offers a convenient tool to authorize systems.

```shell
sozo auth writer Moves spawn
```

This command will generate a `writer` authorization for the `spawn` system to update the `Moves` model.
79 changes: 79 additions & 0 deletions dojo-book/docs/pages/cairo/commands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
## Commands

**_TL;DR_**

- Commands are shorthand ways to write function calls
- Commands abstract complex queries into shorthands
- Commands are similar to rust macros

Understanding commands is key to understanding Dojo. You will leverage them heavily within the systems you design.

Commands in Dojo are generalized functions that are expanded at compile time to facilitate system execution. They provide a convenient way for systems to interact with the world state by abstracting common operations, such as retrieving or updating models, and generating unique IDs. By leveraging these commands, developers can streamline their system implementations and improve code readability.

### Using commands

Commands are used within systems to interact with the world state. They are called using the following syntax:

### The `get!` command

The `get!` command is used to retrieve models from the world state:

```rust,ignore
// world = calling world
// caller = key of the entity that called the system
// (Position, Moves) = tuple of models to retrieve
let (position, moves) = get!(world, caller, (Position, Moves));
```

Here we are retrieving the `Position` and `Moves` models from the world state. We are also using the `caller` to retrieve the models for the current entity.

You can then use `position` and `moves` as you would as any other Cairo struct.

In the case that your model defines several keys as the [resource example](./models.md#the-key-attribute), you must provide a value for each key.

```rust,ignore
let player = get_caller_address();
let location = 0x1234;
let resource = get!(world, (player, location), (Resource));
```

If you use the `get!` command on a model that has never been set before, all the fields that are not `#[key]` are equal to 0 in the returned model, which is the default value in the storage.

### The `set!` command

The `set!` command is used to update models state.

```rust,ignore
set !(world, (
Moves {
player: caller, remaining: 10
},
Position {
player: caller, x: position.x + 10, y: position.y + 10
},
));
// If the structs are already defined it can also be written as:
set!(world, (moves, position));
```

Here we are updating the `Moves` and `Position` models in the world state using the `caller` as the entity id.

### The `emit!` command

The `emit!` command is used to emit custom events. These events are indexed by [Torii](/toolchain/torii/overview.md).

```rust,ignore
emit!(world, Moved { address: caller, direction });
```

This will emit these values which could be captured by a client or you could query these via [Torii](/toolchain/torii/overview.md).

### The `delete!` command

The `delete!` command deletes a model from the db.

```rust,ignore
delete!(world, Moved { address: caller, direction });
```
File renamed without changes.
File renamed without changes.
File renamed without changes.
112 changes: 112 additions & 0 deletions dojo-book/docs/pages/cairo/events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
## Events

Events play a pivotal role in decoding the dynamics of a Dojo world. Every time there's an update to a `Model`, the `World` contract emits these events. What's even more exciting is that you can craft your own custom events to fit specific needs! Moreover, thanks to [Torii](/toolchain/torii/overview.md), all these events are seamlessly indexed, ensuring easy and efficient querying.

### Model Events

Consider this example of a `Moves` model:

```rust,ignore
struct Moves {
#[key]
player: Address,
remaining: u32,
}
```

When this model is updated, the `World` contract will emit an event with the following structure:

```rust,ignore
#[derive(Drop, starknet::Event)]
struct StoreSetRecord {
table: felt252, // Moves
keys: Span<felt252>, // [player]
offset: u8, // offset for the value in the table
value: Span<felt252>, // [remaining]
}
```

This will then be captured by [Torii](/toolchain/torii/overview.md) and indexed for querying. This will allow you to then reconstruct the state of your world.

Similarly, when a model is deleted, the `World` contract will emit an event with the following structure:

```rust,ignore
#[derive(Drop, starknet::Event)]
struct StoreDelRecord {
table: felt252,
keys: Span<felt252>,
}
```

### World Events

The `World` contract also emits events when it's initialized and when new models and contracts are registered. These events are emitted with the following structures:

```rust,ignore
#[derive(Drop, starknet::Event)]
struct WorldSpawned {
address: ContractAddress,
caller: ContractAddress
}
```

```rust,ignore
#[derive(Drop, starknet::Event)]
struct ModelRegistered {
name: felt252,
class_hash: ClassHash,
prev_class_hash: ClassHash
}
```

```rust,ignore
#[derive(Drop, starknet::Event)]
struct ContractDeployed {
salt: felt252,
class_hash: ClassHash,
address: ContractAddress,
}
#[derive(Drop, starknet::Event)]
struct ContractUpgraded {
class_hash: ClassHash,
address: ContractAddress,
}
```

These events are also captured by [Torii](/toolchain/torii/overview.md) and indexed for querying.

### Custom Events

Within your game, emitting custom events can be highly beneficial. Fortunately, there's a handy `emit!` command that lets you release events directly from your world. These events are indexed by [Torii](/toolchain/torii/overview.md).

Use it like so:

```rust,ignore
emit!(world, Moved { address, direction });
```

Include this in your contract and it will emit an event with the following structure:

```rust,ignore
#[derive(Drop, starknet::Event)]
struct Moved {
address: felt252,
direction: felt252,
}
```

Now a full example using a custom event:

```rust,ignore
fn move(ctx: Context, direction: Direction) {
let (mut position, mut moves) = get !(world, caller, (Position, Moves));
moves.remaining -= 1;
let next = next_position(position, direction);
set !(world, (moves, next));
emit !(world, Moved { address: caller, direction });
}
```

> Note: Read about the `get!` and `set!` macros in [Commands](./commands.md).
Loading

0 comments on commit df0cd58

Please sign in to comment.