├── .github ├── mark-dark.svg ├── mark-light.svg └── workflows │ ├── release.yml │ └── test.yaml ├── .gitignore ├── .vscode └── settings.json ├── Dockerfile ├── LICENSE ├── README.md ├── Scarb.lock ├── Scarb.toml ├── assets ├── cover.png └── icon.png ├── compose.yaml ├── dojo_dev.toml ├── dojo_release.toml ├── manifest_dev.json ├── src ├── lib.cairo ├── models.cairo ├── systems │ └── actions.cairo └── tests │ └── test_world.cairo └── torii_dev.toml /.github/mark-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /.github/mark-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | version: 7 | description: "Version to release (e.g., v1.0.0)" 8 | required: true 9 | type: string 10 | dojo_version: 11 | description: "Dojo version to use" 12 | required: true 13 | type: string 14 | 15 | jobs: 16 | create-release: 17 | runs-on: ubuntu-latest 18 | env: 19 | DOJO_VERSION: ${{ inputs.dojo_version }} 20 | steps: 21 | - uses: actions/checkout@v3 22 | 23 | # Setup and test with specified Dojo version 24 | - run: curl -L https://install.dojoengine.org | bash 25 | - run: /home/runner/.config/.dojo/dojoup/dojoup install ${{ env.DOJO_VERSION }} 26 | - run: | 27 | /home/runner/.config/.dojo/bin/sozo build 28 | /home/runner/.config/.dojo/bin/sozo test 29 | 30 | # Create tag and release 31 | - name: Create Tag 32 | run: | 33 | git tag ${{ inputs.version }} 34 | git push origin ${{ inputs.version }} 35 | 36 | - name: Create Release 37 | uses: softprops/action-gh-release@v1 38 | with: 39 | tag_name: ${{ inputs.version }} 40 | name: Release ${{ inputs.version }} 41 | draft: false 42 | prerelease: false 43 | generate_release_notes: true 44 | 45 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - "main" 7 | pull_request: 8 | 9 | jobs: 10 | sozo-test: 11 | runs-on: ubuntu-latest 12 | env: 13 | DOJO_VERSION: v1.5.0-alpha.2 14 | steps: 15 | - uses: actions/checkout@v3 16 | - uses: software-mansion/setup-scarb@v1 17 | with: 18 | scarb-version: "2.10.1" 19 | - run: | 20 | curl -L https://install.dojoengine.org | bash 21 | /home/runner/.config/.dojo/dojoup/dojoup install ${{ env.DOJO_VERSION }} 22 | - run: | 23 | /home/runner/.config/.dojo/bin/sozo build 24 | /home/runner/.config/.dojo/bin/sozo test 25 | if [[ `git status --porcelain` ]]; then 26 | echo The git repo is dirty 27 | echo "Make sure to run \"sozo build\" after changing Scarb.toml and commit Scarb.lock" 28 | exit 1 29 | fi 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | dojo_mainnet.toml 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cairo1.enableLanguageServer": true, 3 | "cairo1.enableScarb": true, 4 | "cairo1.languageServerPath": "${userHome}/.dojo/bin/dojo-language-server" 5 | } 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/dojoengine/dojo:v1.5.0 AS dojo 2 | 3 | RUN apt update && apt install curl jq -y 4 | 5 | FROM ghcr.io/dojoengine/katana-dev:test AS katana 6 | 7 | 8 | FROM ghcr.io/dojoengine/torii:v1.5.0 AS torii 9 | 10 | RUN apt update && apt install jq -y 11 | 12 | 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Dojo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Dojo Starter](./assets/cover.png) 2 | 3 | 4 | 5 | Dojo logo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | [![discord](https://img.shields.io/badge/join-dojo-green?logo=discord&logoColor=white)](https://discord.com/invite/dojoengine) 16 | [![Telegram Chat][tg-badge]][tg-url] 17 | 18 | [tg-badge]: https://img.shields.io/endpoint?color=neon&logo=telegram&label=chat&style=flat-square&url=https%3A%2F%2Ftg.sumanjay.workers.dev%2Fdojoengine 19 | [tg-url]: https://t.me/dojoengine 20 | 21 | # Dojo Starter: Official Guide 22 | 23 | A quickstart guide to help you build and deploy your first Dojo provable game. 24 | 25 | Read the full tutorial [here](https://dojoengine.org/tutorial/dojo-starter). 26 | 27 | ## Running Locally 28 | 29 | #### Terminal one (Make sure this is running) 30 | 31 | ```bash 32 | # Run Katana 33 | katana --dev --dev.no-fee 34 | ``` 35 | 36 | #### Terminal two 37 | 38 | ```bash 39 | # Build the example 40 | sozo build 41 | 42 | # Inspect the world 43 | sozo inspect 44 | 45 | # Migrate the example 46 | sozo migrate 47 | 48 | # Start Torii 49 | # Replace with the address of the deployed world from the previous step 50 | torii --world --http.cors_origins "*" 51 | ``` 52 | 53 | ## Docker 54 | You can start stack using docker compose. [Here are the installation instruction](https://docs.docker.com/engine/install/) 55 | 56 | ```bash 57 | docker compose up 58 | ``` 59 | You'll get all services logs in the same terminal instance. Whenever you want to stop just ctrl+c 60 | 61 | --- 62 | 63 | ## Contribution 64 | 65 | 1. **Report a Bug** 66 | 67 | - If you think you have encountered a bug, and we should know about it, feel free to report it [here](https://github.com/dojoengine/dojo-starter/issues) and we will take care of it. 68 | 69 | 2. **Request a Feature** 70 | 71 | - You can also request for a feature [here](https://github.com/dojoengine/dojo-starter/issues), and if it's viable, it will be picked for development. 72 | 73 | 3. **Create a Pull Request** 74 | - It can't get better then this, your pull request will be appreciated by the community. 75 | 76 | Happy coding! 77 | -------------------------------------------------------------------------------- /Scarb.lock: -------------------------------------------------------------------------------- 1 | # Code generated by scarb DO NOT EDIT. 2 | version = 1 3 | 4 | [[package]] 5 | name = "dojo" 6 | version = "1.5.0" 7 | source = "git+https://github.com/dojoengine/dojo?tag=v1.5.0#812f17c9c57fd057d0bf1e648a591ea0ca9ea718" 8 | dependencies = [ 9 | "dojo_plugin", 10 | ] 11 | 12 | [[package]] 13 | name = "dojo_cairo_test" 14 | version = "1.0.12" 15 | source = "git+https://github.com/dojoengine/dojo?tag=v1.5.0#812f17c9c57fd057d0bf1e648a591ea0ca9ea718" 16 | dependencies = [ 17 | "dojo", 18 | ] 19 | 20 | [[package]] 21 | name = "dojo_plugin" 22 | version = "2.10.1" 23 | source = "git+https://github.com/dojoengine/dojo?tag=v1.5.0#812f17c9c57fd057d0bf1e648a591ea0ca9ea718" 24 | 25 | [[package]] 26 | name = "dojo_starter" 27 | version = "1.5.0" 28 | dependencies = [ 29 | "dojo", 30 | "dojo_cairo_test", 31 | ] 32 | -------------------------------------------------------------------------------- /Scarb.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | cairo-version = "=2.10.1" 3 | name = "dojo_starter" 4 | version = "1.5.0" 5 | edition = "2024_07" 6 | 7 | [cairo] 8 | sierra-replace-ids = true 9 | 10 | [scripts] 11 | migrate = "sozo build && sozo migrate" # scarb run migrate 12 | spawn = "sozo execute dojo_starter-actions spawn --wait" # scarb run spawn 13 | move = "sozo execute dojo_starter-actions move -c 1 --wait" # scarb run move 14 | 15 | [dependencies] 16 | dojo = { git = "https://github.com/dojoengine/dojo", tag = "v1.5.0" } 17 | 18 | [[target.starknet-contract]] 19 | build-external-contracts = ["dojo::world::world_contract::world"] 20 | 21 | [dev-dependencies] 22 | cairo_test = "=2.10.1" 23 | dojo_cairo_test = { git = "https://github.com/dojoengine/dojo", tag = "v1.5.0" } 24 | -------------------------------------------------------------------------------- /assets/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dojoengine/dojo-starter/b0320446d54511e4740d0096f49628c1fcf0bc44/assets/cover.png -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dojoengine/dojo-starter/b0320446d54511e4740d0096f49628c1fcf0bc44/assets/icon.png -------------------------------------------------------------------------------- /compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | katana: 3 | build: 4 | context: . 5 | dockerfile: Dockerfile 6 | target: katana 7 | command: > 8 | /bin/sh -c ' 9 | RUST_LOG=info katana --dev --dev.no-fee --http.addr 0.0.0.0 --http.cors_origins "*" --cartridge.paymaster --explorer 10 | ' 11 | ports: 12 | - 5050:5050 13 | - 3001:3001 14 | healthcheck: 15 | test: ["CMD", "curl", "--fail", "http://localhost:5050"] 16 | interval: 10s 17 | timeout: 5s 18 | retries: 5 19 | 20 | sozo-migrate: 21 | build: 22 | context: . 23 | dockerfile: Dockerfile 24 | target: dojo 25 | volumes: 26 | - ./:/app 27 | depends_on: 28 | katana: 29 | condition: service_healthy 30 | command: 31 | [ 32 | "/bin/sh", 33 | "-c", 34 | "cd /app && /root/.dojo/bin/sozo migrate --rpc-url http://katana:5050", 35 | ] 36 | restart: on-failure 37 | 38 | torii: 39 | build: 40 | context: . 41 | dockerfile: Dockerfile 42 | target: torii 43 | command: > 44 | /bin/sh -c ' 45 | world_address=$$(cat /app/manifest_dev.json | jq -r .world.address) && 46 | RUST_LOG=libp2p=DEBUG torii -w $$world_address --http.cors_origins "*" --rpc http://katana:5050 --http.addr 0.0.0.0 --config /app/torii_dev.toml 47 | ' 48 | volumes: 49 | - ./manifest_dev.json:/app/manifest_dev.json 50 | - ./torii_dev.toml:/app/torii_dev.toml 51 | ports: 52 | - 8080:8080 53 | - 9090-9092:9090-9092 54 | depends_on: 55 | sozo-migrate: 56 | condition: service_completed_successfully 57 | katana: 58 | condition: service_healthy 59 | restart: on-failure 60 | -------------------------------------------------------------------------------- /dojo_dev.toml: -------------------------------------------------------------------------------- 1 | [world] 2 | name = "Dojo starter" 3 | description = "The official Dojo Starter guide, the quickest and most streamlined way to get your Dojo Autonomous World up and running. This guide will assist you with the initial setup, from cloning the repository to deploying your world." 4 | cover_uri = "file://assets/cover.png" 5 | icon_uri = "file://assets/icon.png" 6 | website = "https://github.com/dojoengine/dojo-starter" 7 | seed = "dojo_starter" 8 | 9 | [world.socials] 10 | x = "https://x.com/ohayo_dojo" 11 | discord = "https://discord.gg/FB2wR6uF" 12 | github = "https://github.com/dojoengine/dojo-starter" 13 | telegram = "https://t.me/dojoengine" 14 | 15 | [namespace] 16 | default = "dojo_starter" 17 | 18 | [env] 19 | rpc_url = "http://localhost:5050/" 20 | # Default account for katana with seed = 0 21 | account_address = "0x127fd5f1fe78a71f8bcd1fec63e3fe2f0486b6ecd5c86a0466c3a21fa5cfcec" 22 | private_key = "0xc5b2fcab997346f3ea1c00b002ecf6f382c5f9c9659a3894eb783c5320f912" 23 | # world_address = "0x06171ed98331e849d6084bf2b3e3186a7ddf35574dd68cab4691053ee8ab69d7" 24 | 25 | [writers] 26 | "dojo_starter" = ["dojo_starter-actions"] 27 | -------------------------------------------------------------------------------- /dojo_release.toml: -------------------------------------------------------------------------------- 1 | [world] 2 | name = "Dojo starter" 3 | description = "The official Dojo Starter guide, the quickest and most streamlined way to get your Dojo Autonomous World up and running. This guide will assist you with the initial setup, from cloning the repository to deploying your world." 4 | cover_uri = "file://assets/cover.png" 5 | icon_uri = "file://assets/icon.png" 6 | website = "https://github.com/dojoengine/dojo-starter" 7 | seed = "dojo_starter" 8 | 9 | [world.socials] 10 | x = "https://x.com/ohayo_dojo" 11 | discord = "https://discord.gg/FB2wR6uF" 12 | github = "https://github.com/dojoengine/dojo-starter" 13 | telegram = "https://t.me/dojoengine" 14 | 15 | [namespace] 16 | default = "dojo_starter" 17 | 18 | [env] 19 | rpc_url = "http://localhost:5050/" 20 | # Default account for katana with seed = 0 21 | account_address = "0x127fd5f1fe78a71f8bcd1fec63e3fe2f0486b6ecd5c86a0466c3a21fa5cfcec" 22 | private_key = "0xc5b2fcab997346f3ea1c00b002ecf6f382c5f9c9659a3894eb783c5320f912" 23 | #world_address = "0x06171ed98331e849d6084bf2b3e3186a7ddf35574dd68cab4691053ee8ab69d7" # Uncomment and update this line with your world address. 24 | 25 | [writers] 26 | "dojo_starter" = ["dojo_starter-actions"] 27 | -------------------------------------------------------------------------------- /manifest_dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "world": { 3 | "class_hash": "0x2660e42e300e85d14619e31ab1c51520a98ecd6ff97accefb40b62b260aeafc", 4 | "address": "0x4a8ed1a46118db416888f6b98caf1e4c64bb33a20f89d98cbc59da46856fb7e", 5 | "seed": "dojo_starter", 6 | "name": "Dojo starter", 7 | "entrypoints": [ 8 | "uuid", 9 | "set_metadata", 10 | "register_namespace", 11 | "register_event", 12 | "register_model", 13 | "register_contract", 14 | "register_library", 15 | "init_contract", 16 | "upgrade_event", 17 | "upgrade_model", 18 | "upgrade_contract", 19 | "emit_event", 20 | "emit_events", 21 | "set_entity", 22 | "set_entities", 23 | "delete_entity", 24 | "delete_entities", 25 | "grant_owner", 26 | "revoke_owner", 27 | "grant_writer", 28 | "revoke_writer", 29 | "upgrade" 30 | ], 31 | "abi": [ 32 | { 33 | "type": "impl", 34 | "name": "World", 35 | "interface_name": "dojo::world::iworld::IWorld" 36 | }, 37 | { 38 | "type": "struct", 39 | "name": "core::byte_array::ByteArray", 40 | "members": [ 41 | { 42 | "name": "data", 43 | "type": "core::array::Array::" 44 | }, 45 | { 46 | "name": "pending_word", 47 | "type": "core::felt252" 48 | }, 49 | { 50 | "name": "pending_word_len", 51 | "type": "core::integer::u32" 52 | } 53 | ] 54 | }, 55 | { 56 | "type": "enum", 57 | "name": "dojo::world::resource::Resource", 58 | "variants": [ 59 | { 60 | "name": "Model", 61 | "type": "(core::starknet::contract_address::ContractAddress, core::felt252)" 62 | }, 63 | { 64 | "name": "Event", 65 | "type": "(core::starknet::contract_address::ContractAddress, core::felt252)" 66 | }, 67 | { 68 | "name": "Contract", 69 | "type": "(core::starknet::contract_address::ContractAddress, core::felt252)" 70 | }, 71 | { 72 | "name": "Namespace", 73 | "type": "core::byte_array::ByteArray" 74 | }, 75 | { 76 | "name": "World", 77 | "type": "()" 78 | }, 79 | { 80 | "name": "Unregistered", 81 | "type": "()" 82 | }, 83 | { 84 | "name": "Library", 85 | "type": "(core::starknet::class_hash::ClassHash, core::felt252)" 86 | } 87 | ] 88 | }, 89 | { 90 | "type": "struct", 91 | "name": "dojo::model::metadata::ResourceMetadata", 92 | "members": [ 93 | { 94 | "name": "resource_id", 95 | "type": "core::felt252" 96 | }, 97 | { 98 | "name": "metadata_uri", 99 | "type": "core::byte_array::ByteArray" 100 | }, 101 | { 102 | "name": "metadata_hash", 103 | "type": "core::felt252" 104 | } 105 | ] 106 | }, 107 | { 108 | "type": "struct", 109 | "name": "core::array::Span::", 110 | "members": [ 111 | { 112 | "name": "snapshot", 113 | "type": "@core::array::Array::" 114 | } 115 | ] 116 | }, 117 | { 118 | "type": "struct", 119 | "name": "core::array::Span::>", 120 | "members": [ 121 | { 122 | "name": "snapshot", 123 | "type": "@core::array::Array::>" 124 | } 125 | ] 126 | }, 127 | { 128 | "type": "enum", 129 | "name": "dojo::model::definition::ModelIndex", 130 | "variants": [ 131 | { 132 | "name": "Keys", 133 | "type": "core::array::Span::" 134 | }, 135 | { 136 | "name": "Id", 137 | "type": "core::felt252" 138 | }, 139 | { 140 | "name": "MemberId", 141 | "type": "(core::felt252, core::felt252)" 142 | } 143 | ] 144 | }, 145 | { 146 | "type": "struct", 147 | "name": "core::array::Span::", 148 | "members": [ 149 | { 150 | "name": "snapshot", 151 | "type": "@core::array::Array::" 152 | } 153 | ] 154 | }, 155 | { 156 | "type": "struct", 157 | "name": "dojo::meta::layout::FieldLayout", 158 | "members": [ 159 | { 160 | "name": "selector", 161 | "type": "core::felt252" 162 | }, 163 | { 164 | "name": "layout", 165 | "type": "dojo::meta::layout::Layout" 166 | } 167 | ] 168 | }, 169 | { 170 | "type": "struct", 171 | "name": "core::array::Span::", 172 | "members": [ 173 | { 174 | "name": "snapshot", 175 | "type": "@core::array::Array::" 176 | } 177 | ] 178 | }, 179 | { 180 | "type": "struct", 181 | "name": "core::array::Span::", 182 | "members": [ 183 | { 184 | "name": "snapshot", 185 | "type": "@core::array::Array::" 186 | } 187 | ] 188 | }, 189 | { 190 | "type": "enum", 191 | "name": "dojo::meta::layout::Layout", 192 | "variants": [ 193 | { 194 | "name": "Fixed", 195 | "type": "core::array::Span::" 196 | }, 197 | { 198 | "name": "Struct", 199 | "type": "core::array::Span::" 200 | }, 201 | { 202 | "name": "Tuple", 203 | "type": "core::array::Span::" 204 | }, 205 | { 206 | "name": "Array", 207 | "type": "core::array::Span::" 208 | }, 209 | { 210 | "name": "ByteArray", 211 | "type": "()" 212 | }, 213 | { 214 | "name": "Enum", 215 | "type": "core::array::Span::" 216 | } 217 | ] 218 | }, 219 | { 220 | "type": "struct", 221 | "name": "core::array::Span::", 222 | "members": [ 223 | { 224 | "name": "snapshot", 225 | "type": "@core::array::Array::" 226 | } 227 | ] 228 | }, 229 | { 230 | "type": "enum", 231 | "name": "core::bool", 232 | "variants": [ 233 | { 234 | "name": "False", 235 | "type": "()" 236 | }, 237 | { 238 | "name": "True", 239 | "type": "()" 240 | } 241 | ] 242 | }, 243 | { 244 | "type": "interface", 245 | "name": "dojo::world::iworld::IWorld", 246 | "items": [ 247 | { 248 | "type": "function", 249 | "name": "resource", 250 | "inputs": [ 251 | { 252 | "name": "selector", 253 | "type": "core::felt252" 254 | } 255 | ], 256 | "outputs": [ 257 | { 258 | "type": "dojo::world::resource::Resource" 259 | } 260 | ], 261 | "state_mutability": "view" 262 | }, 263 | { 264 | "type": "function", 265 | "name": "uuid", 266 | "inputs": [], 267 | "outputs": [ 268 | { 269 | "type": "core::integer::u32" 270 | } 271 | ], 272 | "state_mutability": "external" 273 | }, 274 | { 275 | "type": "function", 276 | "name": "metadata", 277 | "inputs": [ 278 | { 279 | "name": "resource_selector", 280 | "type": "core::felt252" 281 | } 282 | ], 283 | "outputs": [ 284 | { 285 | "type": "dojo::model::metadata::ResourceMetadata" 286 | } 287 | ], 288 | "state_mutability": "view" 289 | }, 290 | { 291 | "type": "function", 292 | "name": "set_metadata", 293 | "inputs": [ 294 | { 295 | "name": "metadata", 296 | "type": "dojo::model::metadata::ResourceMetadata" 297 | } 298 | ], 299 | "outputs": [], 300 | "state_mutability": "external" 301 | }, 302 | { 303 | "type": "function", 304 | "name": "register_namespace", 305 | "inputs": [ 306 | { 307 | "name": "namespace", 308 | "type": "core::byte_array::ByteArray" 309 | } 310 | ], 311 | "outputs": [], 312 | "state_mutability": "external" 313 | }, 314 | { 315 | "type": "function", 316 | "name": "register_event", 317 | "inputs": [ 318 | { 319 | "name": "namespace", 320 | "type": "core::byte_array::ByteArray" 321 | }, 322 | { 323 | "name": "class_hash", 324 | "type": "core::starknet::class_hash::ClassHash" 325 | } 326 | ], 327 | "outputs": [], 328 | "state_mutability": "external" 329 | }, 330 | { 331 | "type": "function", 332 | "name": "register_model", 333 | "inputs": [ 334 | { 335 | "name": "namespace", 336 | "type": "core::byte_array::ByteArray" 337 | }, 338 | { 339 | "name": "class_hash", 340 | "type": "core::starknet::class_hash::ClassHash" 341 | } 342 | ], 343 | "outputs": [], 344 | "state_mutability": "external" 345 | }, 346 | { 347 | "type": "function", 348 | "name": "register_contract", 349 | "inputs": [ 350 | { 351 | "name": "salt", 352 | "type": "core::felt252" 353 | }, 354 | { 355 | "name": "namespace", 356 | "type": "core::byte_array::ByteArray" 357 | }, 358 | { 359 | "name": "class_hash", 360 | "type": "core::starknet::class_hash::ClassHash" 361 | } 362 | ], 363 | "outputs": [ 364 | { 365 | "type": "core::starknet::contract_address::ContractAddress" 366 | } 367 | ], 368 | "state_mutability": "external" 369 | }, 370 | { 371 | "type": "function", 372 | "name": "register_library", 373 | "inputs": [ 374 | { 375 | "name": "namespace", 376 | "type": "core::byte_array::ByteArray" 377 | }, 378 | { 379 | "name": "class_hash", 380 | "type": "core::starknet::class_hash::ClassHash" 381 | }, 382 | { 383 | "name": "name", 384 | "type": "core::byte_array::ByteArray" 385 | }, 386 | { 387 | "name": "version", 388 | "type": "core::byte_array::ByteArray" 389 | } 390 | ], 391 | "outputs": [ 392 | { 393 | "type": "core::starknet::class_hash::ClassHash" 394 | } 395 | ], 396 | "state_mutability": "external" 397 | }, 398 | { 399 | "type": "function", 400 | "name": "init_contract", 401 | "inputs": [ 402 | { 403 | "name": "selector", 404 | "type": "core::felt252" 405 | }, 406 | { 407 | "name": "init_calldata", 408 | "type": "core::array::Span::" 409 | } 410 | ], 411 | "outputs": [], 412 | "state_mutability": "external" 413 | }, 414 | { 415 | "type": "function", 416 | "name": "upgrade_event", 417 | "inputs": [ 418 | { 419 | "name": "namespace", 420 | "type": "core::byte_array::ByteArray" 421 | }, 422 | { 423 | "name": "class_hash", 424 | "type": "core::starknet::class_hash::ClassHash" 425 | } 426 | ], 427 | "outputs": [], 428 | "state_mutability": "external" 429 | }, 430 | { 431 | "type": "function", 432 | "name": "upgrade_model", 433 | "inputs": [ 434 | { 435 | "name": "namespace", 436 | "type": "core::byte_array::ByteArray" 437 | }, 438 | { 439 | "name": "class_hash", 440 | "type": "core::starknet::class_hash::ClassHash" 441 | } 442 | ], 443 | "outputs": [], 444 | "state_mutability": "external" 445 | }, 446 | { 447 | "type": "function", 448 | "name": "upgrade_contract", 449 | "inputs": [ 450 | { 451 | "name": "namespace", 452 | "type": "core::byte_array::ByteArray" 453 | }, 454 | { 455 | "name": "class_hash", 456 | "type": "core::starknet::class_hash::ClassHash" 457 | } 458 | ], 459 | "outputs": [ 460 | { 461 | "type": "core::starknet::class_hash::ClassHash" 462 | } 463 | ], 464 | "state_mutability": "external" 465 | }, 466 | { 467 | "type": "function", 468 | "name": "emit_event", 469 | "inputs": [ 470 | { 471 | "name": "event_selector", 472 | "type": "core::felt252" 473 | }, 474 | { 475 | "name": "keys", 476 | "type": "core::array::Span::" 477 | }, 478 | { 479 | "name": "values", 480 | "type": "core::array::Span::" 481 | } 482 | ], 483 | "outputs": [], 484 | "state_mutability": "external" 485 | }, 486 | { 487 | "type": "function", 488 | "name": "emit_events", 489 | "inputs": [ 490 | { 491 | "name": "event_selector", 492 | "type": "core::felt252" 493 | }, 494 | { 495 | "name": "keys", 496 | "type": "core::array::Span::>" 497 | }, 498 | { 499 | "name": "values", 500 | "type": "core::array::Span::>" 501 | } 502 | ], 503 | "outputs": [], 504 | "state_mutability": "external" 505 | }, 506 | { 507 | "type": "function", 508 | "name": "entity", 509 | "inputs": [ 510 | { 511 | "name": "model_selector", 512 | "type": "core::felt252" 513 | }, 514 | { 515 | "name": "index", 516 | "type": "dojo::model::definition::ModelIndex" 517 | }, 518 | { 519 | "name": "layout", 520 | "type": "dojo::meta::layout::Layout" 521 | } 522 | ], 523 | "outputs": [ 524 | { 525 | "type": "core::array::Span::" 526 | } 527 | ], 528 | "state_mutability": "view" 529 | }, 530 | { 531 | "type": "function", 532 | "name": "entities", 533 | "inputs": [ 534 | { 535 | "name": "model_selector", 536 | "type": "core::felt252" 537 | }, 538 | { 539 | "name": "indexes", 540 | "type": "core::array::Span::" 541 | }, 542 | { 543 | "name": "layout", 544 | "type": "dojo::meta::layout::Layout" 545 | } 546 | ], 547 | "outputs": [ 548 | { 549 | "type": "core::array::Span::>" 550 | } 551 | ], 552 | "state_mutability": "view" 553 | }, 554 | { 555 | "type": "function", 556 | "name": "set_entity", 557 | "inputs": [ 558 | { 559 | "name": "model_selector", 560 | "type": "core::felt252" 561 | }, 562 | { 563 | "name": "index", 564 | "type": "dojo::model::definition::ModelIndex" 565 | }, 566 | { 567 | "name": "values", 568 | "type": "core::array::Span::" 569 | }, 570 | { 571 | "name": "layout", 572 | "type": "dojo::meta::layout::Layout" 573 | } 574 | ], 575 | "outputs": [], 576 | "state_mutability": "external" 577 | }, 578 | { 579 | "type": "function", 580 | "name": "set_entities", 581 | "inputs": [ 582 | { 583 | "name": "model_selector", 584 | "type": "core::felt252" 585 | }, 586 | { 587 | "name": "indexes", 588 | "type": "core::array::Span::" 589 | }, 590 | { 591 | "name": "values", 592 | "type": "core::array::Span::>" 593 | }, 594 | { 595 | "name": "layout", 596 | "type": "dojo::meta::layout::Layout" 597 | } 598 | ], 599 | "outputs": [], 600 | "state_mutability": "external" 601 | }, 602 | { 603 | "type": "function", 604 | "name": "delete_entity", 605 | "inputs": [ 606 | { 607 | "name": "model_selector", 608 | "type": "core::felt252" 609 | }, 610 | { 611 | "name": "index", 612 | "type": "dojo::model::definition::ModelIndex" 613 | }, 614 | { 615 | "name": "layout", 616 | "type": "dojo::meta::layout::Layout" 617 | } 618 | ], 619 | "outputs": [], 620 | "state_mutability": "external" 621 | }, 622 | { 623 | "type": "function", 624 | "name": "delete_entities", 625 | "inputs": [ 626 | { 627 | "name": "model_selector", 628 | "type": "core::felt252" 629 | }, 630 | { 631 | "name": "indexes", 632 | "type": "core::array::Span::" 633 | }, 634 | { 635 | "name": "layout", 636 | "type": "dojo::meta::layout::Layout" 637 | } 638 | ], 639 | "outputs": [], 640 | "state_mutability": "external" 641 | }, 642 | { 643 | "type": "function", 644 | "name": "is_owner", 645 | "inputs": [ 646 | { 647 | "name": "resource", 648 | "type": "core::felt252" 649 | }, 650 | { 651 | "name": "address", 652 | "type": "core::starknet::contract_address::ContractAddress" 653 | } 654 | ], 655 | "outputs": [ 656 | { 657 | "type": "core::bool" 658 | } 659 | ], 660 | "state_mutability": "view" 661 | }, 662 | { 663 | "type": "function", 664 | "name": "grant_owner", 665 | "inputs": [ 666 | { 667 | "name": "resource", 668 | "type": "core::felt252" 669 | }, 670 | { 671 | "name": "address", 672 | "type": "core::starknet::contract_address::ContractAddress" 673 | } 674 | ], 675 | "outputs": [], 676 | "state_mutability": "external" 677 | }, 678 | { 679 | "type": "function", 680 | "name": "revoke_owner", 681 | "inputs": [ 682 | { 683 | "name": "resource", 684 | "type": "core::felt252" 685 | }, 686 | { 687 | "name": "address", 688 | "type": "core::starknet::contract_address::ContractAddress" 689 | } 690 | ], 691 | "outputs": [], 692 | "state_mutability": "external" 693 | }, 694 | { 695 | "type": "function", 696 | "name": "is_writer", 697 | "inputs": [ 698 | { 699 | "name": "resource", 700 | "type": "core::felt252" 701 | }, 702 | { 703 | "name": "contract", 704 | "type": "core::starknet::contract_address::ContractAddress" 705 | } 706 | ], 707 | "outputs": [ 708 | { 709 | "type": "core::bool" 710 | } 711 | ], 712 | "state_mutability": "view" 713 | }, 714 | { 715 | "type": "function", 716 | "name": "grant_writer", 717 | "inputs": [ 718 | { 719 | "name": "resource", 720 | "type": "core::felt252" 721 | }, 722 | { 723 | "name": "contract", 724 | "type": "core::starknet::contract_address::ContractAddress" 725 | } 726 | ], 727 | "outputs": [], 728 | "state_mutability": "external" 729 | }, 730 | { 731 | "type": "function", 732 | "name": "revoke_writer", 733 | "inputs": [ 734 | { 735 | "name": "resource", 736 | "type": "core::felt252" 737 | }, 738 | { 739 | "name": "contract", 740 | "type": "core::starknet::contract_address::ContractAddress" 741 | } 742 | ], 743 | "outputs": [], 744 | "state_mutability": "external" 745 | } 746 | ] 747 | }, 748 | { 749 | "type": "impl", 750 | "name": "UpgradeableWorld", 751 | "interface_name": "dojo::world::iworld::IUpgradeableWorld" 752 | }, 753 | { 754 | "type": "interface", 755 | "name": "dojo::world::iworld::IUpgradeableWorld", 756 | "items": [ 757 | { 758 | "type": "function", 759 | "name": "upgrade", 760 | "inputs": [ 761 | { 762 | "name": "new_class_hash", 763 | "type": "core::starknet::class_hash::ClassHash" 764 | } 765 | ], 766 | "outputs": [], 767 | "state_mutability": "external" 768 | } 769 | ] 770 | }, 771 | { 772 | "type": "constructor", 773 | "name": "constructor", 774 | "inputs": [ 775 | { 776 | "name": "world_class_hash", 777 | "type": "core::starknet::class_hash::ClassHash" 778 | } 779 | ] 780 | }, 781 | { 782 | "type": "event", 783 | "name": "dojo::world::world_contract::world::WorldSpawned", 784 | "kind": "struct", 785 | "members": [ 786 | { 787 | "name": "creator", 788 | "type": "core::starknet::contract_address::ContractAddress", 789 | "kind": "data" 790 | }, 791 | { 792 | "name": "class_hash", 793 | "type": "core::starknet::class_hash::ClassHash", 794 | "kind": "data" 795 | } 796 | ] 797 | }, 798 | { 799 | "type": "event", 800 | "name": "dojo::world::world_contract::world::WorldUpgraded", 801 | "kind": "struct", 802 | "members": [ 803 | { 804 | "name": "class_hash", 805 | "type": "core::starknet::class_hash::ClassHash", 806 | "kind": "data" 807 | } 808 | ] 809 | }, 810 | { 811 | "type": "event", 812 | "name": "dojo::world::world_contract::world::NamespaceRegistered", 813 | "kind": "struct", 814 | "members": [ 815 | { 816 | "name": "namespace", 817 | "type": "core::byte_array::ByteArray", 818 | "kind": "key" 819 | }, 820 | { 821 | "name": "hash", 822 | "type": "core::felt252", 823 | "kind": "data" 824 | } 825 | ] 826 | }, 827 | { 828 | "type": "event", 829 | "name": "dojo::world::world_contract::world::ModelRegistered", 830 | "kind": "struct", 831 | "members": [ 832 | { 833 | "name": "name", 834 | "type": "core::byte_array::ByteArray", 835 | "kind": "key" 836 | }, 837 | { 838 | "name": "namespace", 839 | "type": "core::byte_array::ByteArray", 840 | "kind": "key" 841 | }, 842 | { 843 | "name": "class_hash", 844 | "type": "core::starknet::class_hash::ClassHash", 845 | "kind": "data" 846 | }, 847 | { 848 | "name": "address", 849 | "type": "core::starknet::contract_address::ContractAddress", 850 | "kind": "data" 851 | } 852 | ] 853 | }, 854 | { 855 | "type": "event", 856 | "name": "dojo::world::world_contract::world::EventRegistered", 857 | "kind": "struct", 858 | "members": [ 859 | { 860 | "name": "name", 861 | "type": "core::byte_array::ByteArray", 862 | "kind": "key" 863 | }, 864 | { 865 | "name": "namespace", 866 | "type": "core::byte_array::ByteArray", 867 | "kind": "key" 868 | }, 869 | { 870 | "name": "class_hash", 871 | "type": "core::starknet::class_hash::ClassHash", 872 | "kind": "data" 873 | }, 874 | { 875 | "name": "address", 876 | "type": "core::starknet::contract_address::ContractAddress", 877 | "kind": "data" 878 | } 879 | ] 880 | }, 881 | { 882 | "type": "event", 883 | "name": "dojo::world::world_contract::world::ContractRegistered", 884 | "kind": "struct", 885 | "members": [ 886 | { 887 | "name": "name", 888 | "type": "core::byte_array::ByteArray", 889 | "kind": "key" 890 | }, 891 | { 892 | "name": "namespace", 893 | "type": "core::byte_array::ByteArray", 894 | "kind": "key" 895 | }, 896 | { 897 | "name": "address", 898 | "type": "core::starknet::contract_address::ContractAddress", 899 | "kind": "data" 900 | }, 901 | { 902 | "name": "class_hash", 903 | "type": "core::starknet::class_hash::ClassHash", 904 | "kind": "data" 905 | }, 906 | { 907 | "name": "salt", 908 | "type": "core::felt252", 909 | "kind": "data" 910 | } 911 | ] 912 | }, 913 | { 914 | "type": "event", 915 | "name": "dojo::world::world_contract::world::ModelUpgraded", 916 | "kind": "struct", 917 | "members": [ 918 | { 919 | "name": "selector", 920 | "type": "core::felt252", 921 | "kind": "key" 922 | }, 923 | { 924 | "name": "class_hash", 925 | "type": "core::starknet::class_hash::ClassHash", 926 | "kind": "data" 927 | }, 928 | { 929 | "name": "address", 930 | "type": "core::starknet::contract_address::ContractAddress", 931 | "kind": "data" 932 | }, 933 | { 934 | "name": "prev_address", 935 | "type": "core::starknet::contract_address::ContractAddress", 936 | "kind": "data" 937 | } 938 | ] 939 | }, 940 | { 941 | "type": "event", 942 | "name": "dojo::world::world_contract::world::EventUpgraded", 943 | "kind": "struct", 944 | "members": [ 945 | { 946 | "name": "selector", 947 | "type": "core::felt252", 948 | "kind": "key" 949 | }, 950 | { 951 | "name": "class_hash", 952 | "type": "core::starknet::class_hash::ClassHash", 953 | "kind": "data" 954 | }, 955 | { 956 | "name": "address", 957 | "type": "core::starknet::contract_address::ContractAddress", 958 | "kind": "data" 959 | }, 960 | { 961 | "name": "prev_address", 962 | "type": "core::starknet::contract_address::ContractAddress", 963 | "kind": "data" 964 | } 965 | ] 966 | }, 967 | { 968 | "type": "event", 969 | "name": "dojo::world::world_contract::world::ContractUpgraded", 970 | "kind": "struct", 971 | "members": [ 972 | { 973 | "name": "selector", 974 | "type": "core::felt252", 975 | "kind": "key" 976 | }, 977 | { 978 | "name": "class_hash", 979 | "type": "core::starknet::class_hash::ClassHash", 980 | "kind": "data" 981 | } 982 | ] 983 | }, 984 | { 985 | "type": "event", 986 | "name": "dojo::world::world_contract::world::ContractInitialized", 987 | "kind": "struct", 988 | "members": [ 989 | { 990 | "name": "selector", 991 | "type": "core::felt252", 992 | "kind": "key" 993 | }, 994 | { 995 | "name": "init_calldata", 996 | "type": "core::array::Span::", 997 | "kind": "data" 998 | } 999 | ] 1000 | }, 1001 | { 1002 | "type": "event", 1003 | "name": "dojo::world::world_contract::world::LibraryRegistered", 1004 | "kind": "struct", 1005 | "members": [ 1006 | { 1007 | "name": "name", 1008 | "type": "core::byte_array::ByteArray", 1009 | "kind": "key" 1010 | }, 1011 | { 1012 | "name": "namespace", 1013 | "type": "core::byte_array::ByteArray", 1014 | "kind": "key" 1015 | }, 1016 | { 1017 | "name": "class_hash", 1018 | "type": "core::starknet::class_hash::ClassHash", 1019 | "kind": "data" 1020 | } 1021 | ] 1022 | }, 1023 | { 1024 | "type": "event", 1025 | "name": "dojo::world::world_contract::world::EventEmitted", 1026 | "kind": "struct", 1027 | "members": [ 1028 | { 1029 | "name": "selector", 1030 | "type": "core::felt252", 1031 | "kind": "key" 1032 | }, 1033 | { 1034 | "name": "system_address", 1035 | "type": "core::starknet::contract_address::ContractAddress", 1036 | "kind": "key" 1037 | }, 1038 | { 1039 | "name": "keys", 1040 | "type": "core::array::Span::", 1041 | "kind": "data" 1042 | }, 1043 | { 1044 | "name": "values", 1045 | "type": "core::array::Span::", 1046 | "kind": "data" 1047 | } 1048 | ] 1049 | }, 1050 | { 1051 | "type": "event", 1052 | "name": "dojo::world::world_contract::world::MetadataUpdate", 1053 | "kind": "struct", 1054 | "members": [ 1055 | { 1056 | "name": "resource", 1057 | "type": "core::felt252", 1058 | "kind": "key" 1059 | }, 1060 | { 1061 | "name": "uri", 1062 | "type": "core::byte_array::ByteArray", 1063 | "kind": "data" 1064 | }, 1065 | { 1066 | "name": "hash", 1067 | "type": "core::felt252", 1068 | "kind": "data" 1069 | } 1070 | ] 1071 | }, 1072 | { 1073 | "type": "event", 1074 | "name": "dojo::world::world_contract::world::StoreSetRecord", 1075 | "kind": "struct", 1076 | "members": [ 1077 | { 1078 | "name": "selector", 1079 | "type": "core::felt252", 1080 | "kind": "key" 1081 | }, 1082 | { 1083 | "name": "entity_id", 1084 | "type": "core::felt252", 1085 | "kind": "key" 1086 | }, 1087 | { 1088 | "name": "keys", 1089 | "type": "core::array::Span::", 1090 | "kind": "data" 1091 | }, 1092 | { 1093 | "name": "values", 1094 | "type": "core::array::Span::", 1095 | "kind": "data" 1096 | } 1097 | ] 1098 | }, 1099 | { 1100 | "type": "event", 1101 | "name": "dojo::world::world_contract::world::StoreUpdateRecord", 1102 | "kind": "struct", 1103 | "members": [ 1104 | { 1105 | "name": "selector", 1106 | "type": "core::felt252", 1107 | "kind": "key" 1108 | }, 1109 | { 1110 | "name": "entity_id", 1111 | "type": "core::felt252", 1112 | "kind": "key" 1113 | }, 1114 | { 1115 | "name": "values", 1116 | "type": "core::array::Span::", 1117 | "kind": "data" 1118 | } 1119 | ] 1120 | }, 1121 | { 1122 | "type": "event", 1123 | "name": "dojo::world::world_contract::world::StoreUpdateMember", 1124 | "kind": "struct", 1125 | "members": [ 1126 | { 1127 | "name": "selector", 1128 | "type": "core::felt252", 1129 | "kind": "key" 1130 | }, 1131 | { 1132 | "name": "entity_id", 1133 | "type": "core::felt252", 1134 | "kind": "key" 1135 | }, 1136 | { 1137 | "name": "member_selector", 1138 | "type": "core::felt252", 1139 | "kind": "key" 1140 | }, 1141 | { 1142 | "name": "values", 1143 | "type": "core::array::Span::", 1144 | "kind": "data" 1145 | } 1146 | ] 1147 | }, 1148 | { 1149 | "type": "event", 1150 | "name": "dojo::world::world_contract::world::StoreDelRecord", 1151 | "kind": "struct", 1152 | "members": [ 1153 | { 1154 | "name": "selector", 1155 | "type": "core::felt252", 1156 | "kind": "key" 1157 | }, 1158 | { 1159 | "name": "entity_id", 1160 | "type": "core::felt252", 1161 | "kind": "key" 1162 | } 1163 | ] 1164 | }, 1165 | { 1166 | "type": "event", 1167 | "name": "dojo::world::world_contract::world::WriterUpdated", 1168 | "kind": "struct", 1169 | "members": [ 1170 | { 1171 | "name": "resource", 1172 | "type": "core::felt252", 1173 | "kind": "key" 1174 | }, 1175 | { 1176 | "name": "contract", 1177 | "type": "core::starknet::contract_address::ContractAddress", 1178 | "kind": "key" 1179 | }, 1180 | { 1181 | "name": "value", 1182 | "type": "core::bool", 1183 | "kind": "data" 1184 | } 1185 | ] 1186 | }, 1187 | { 1188 | "type": "event", 1189 | "name": "dojo::world::world_contract::world::OwnerUpdated", 1190 | "kind": "struct", 1191 | "members": [ 1192 | { 1193 | "name": "resource", 1194 | "type": "core::felt252", 1195 | "kind": "key" 1196 | }, 1197 | { 1198 | "name": "contract", 1199 | "type": "core::starknet::contract_address::ContractAddress", 1200 | "kind": "key" 1201 | }, 1202 | { 1203 | "name": "value", 1204 | "type": "core::bool", 1205 | "kind": "data" 1206 | } 1207 | ] 1208 | }, 1209 | { 1210 | "type": "event", 1211 | "name": "dojo::world::world_contract::world::Event", 1212 | "kind": "enum", 1213 | "variants": [ 1214 | { 1215 | "name": "WorldSpawned", 1216 | "type": "dojo::world::world_contract::world::WorldSpawned", 1217 | "kind": "nested" 1218 | }, 1219 | { 1220 | "name": "WorldUpgraded", 1221 | "type": "dojo::world::world_contract::world::WorldUpgraded", 1222 | "kind": "nested" 1223 | }, 1224 | { 1225 | "name": "NamespaceRegistered", 1226 | "type": "dojo::world::world_contract::world::NamespaceRegistered", 1227 | "kind": "nested" 1228 | }, 1229 | { 1230 | "name": "ModelRegistered", 1231 | "type": "dojo::world::world_contract::world::ModelRegistered", 1232 | "kind": "nested" 1233 | }, 1234 | { 1235 | "name": "EventRegistered", 1236 | "type": "dojo::world::world_contract::world::EventRegistered", 1237 | "kind": "nested" 1238 | }, 1239 | { 1240 | "name": "ContractRegistered", 1241 | "type": "dojo::world::world_contract::world::ContractRegistered", 1242 | "kind": "nested" 1243 | }, 1244 | { 1245 | "name": "ModelUpgraded", 1246 | "type": "dojo::world::world_contract::world::ModelUpgraded", 1247 | "kind": "nested" 1248 | }, 1249 | { 1250 | "name": "EventUpgraded", 1251 | "type": "dojo::world::world_contract::world::EventUpgraded", 1252 | "kind": "nested" 1253 | }, 1254 | { 1255 | "name": "ContractUpgraded", 1256 | "type": "dojo::world::world_contract::world::ContractUpgraded", 1257 | "kind": "nested" 1258 | }, 1259 | { 1260 | "name": "ContractInitialized", 1261 | "type": "dojo::world::world_contract::world::ContractInitialized", 1262 | "kind": "nested" 1263 | }, 1264 | { 1265 | "name": "LibraryRegistered", 1266 | "type": "dojo::world::world_contract::world::LibraryRegistered", 1267 | "kind": "nested" 1268 | }, 1269 | { 1270 | "name": "EventEmitted", 1271 | "type": "dojo::world::world_contract::world::EventEmitted", 1272 | "kind": "nested" 1273 | }, 1274 | { 1275 | "name": "MetadataUpdate", 1276 | "type": "dojo::world::world_contract::world::MetadataUpdate", 1277 | "kind": "nested" 1278 | }, 1279 | { 1280 | "name": "StoreSetRecord", 1281 | "type": "dojo::world::world_contract::world::StoreSetRecord", 1282 | "kind": "nested" 1283 | }, 1284 | { 1285 | "name": "StoreUpdateRecord", 1286 | "type": "dojo::world::world_contract::world::StoreUpdateRecord", 1287 | "kind": "nested" 1288 | }, 1289 | { 1290 | "name": "StoreUpdateMember", 1291 | "type": "dojo::world::world_contract::world::StoreUpdateMember", 1292 | "kind": "nested" 1293 | }, 1294 | { 1295 | "name": "StoreDelRecord", 1296 | "type": "dojo::world::world_contract::world::StoreDelRecord", 1297 | "kind": "nested" 1298 | }, 1299 | { 1300 | "name": "WriterUpdated", 1301 | "type": "dojo::world::world_contract::world::WriterUpdated", 1302 | "kind": "nested" 1303 | }, 1304 | { 1305 | "name": "OwnerUpdated", 1306 | "type": "dojo::world::world_contract::world::OwnerUpdated", 1307 | "kind": "nested" 1308 | } 1309 | ] 1310 | } 1311 | ] 1312 | }, 1313 | "contracts": [ 1314 | { 1315 | "address": "0x76461d50a37c5c6f8167cd14ddc641cb98b4ef608f36f67fdf6748338b2626c", 1316 | "class_hash": "0x3960b38c19aec8dfa20bac3625b3d63c1553601ec9db43197ed20910019f2a7", 1317 | "abi": [ 1318 | { 1319 | "type": "impl", 1320 | "name": "actions__ContractImpl", 1321 | "interface_name": "dojo::contract::interface::IContract" 1322 | }, 1323 | { 1324 | "type": "interface", 1325 | "name": "dojo::contract::interface::IContract", 1326 | "items": [] 1327 | }, 1328 | { 1329 | "type": "impl", 1330 | "name": "actions__DeployedContractImpl", 1331 | "interface_name": "dojo::meta::interface::IDeployedResource" 1332 | }, 1333 | { 1334 | "type": "struct", 1335 | "name": "core::byte_array::ByteArray", 1336 | "members": [ 1337 | { 1338 | "name": "data", 1339 | "type": "core::array::Array::" 1340 | }, 1341 | { 1342 | "name": "pending_word", 1343 | "type": "core::felt252" 1344 | }, 1345 | { 1346 | "name": "pending_word_len", 1347 | "type": "core::integer::u32" 1348 | } 1349 | ] 1350 | }, 1351 | { 1352 | "type": "interface", 1353 | "name": "dojo::meta::interface::IDeployedResource", 1354 | "items": [ 1355 | { 1356 | "type": "function", 1357 | "name": "dojo_name", 1358 | "inputs": [], 1359 | "outputs": [ 1360 | { 1361 | "type": "core::byte_array::ByteArray" 1362 | } 1363 | ], 1364 | "state_mutability": "view" 1365 | } 1366 | ] 1367 | }, 1368 | { 1369 | "type": "impl", 1370 | "name": "ActionsImpl", 1371 | "interface_name": "dojo_starter::systems::actions::IActions" 1372 | }, 1373 | { 1374 | "type": "enum", 1375 | "name": "dojo_starter::models::Direction", 1376 | "variants": [ 1377 | { 1378 | "name": "Left", 1379 | "type": "()" 1380 | }, 1381 | { 1382 | "name": "Right", 1383 | "type": "()" 1384 | }, 1385 | { 1386 | "name": "Up", 1387 | "type": "()" 1388 | }, 1389 | { 1390 | "name": "Down", 1391 | "type": "()" 1392 | } 1393 | ] 1394 | }, 1395 | { 1396 | "type": "interface", 1397 | "name": "dojo_starter::systems::actions::IActions", 1398 | "items": [ 1399 | { 1400 | "type": "function", 1401 | "name": "spawn", 1402 | "inputs": [], 1403 | "outputs": [], 1404 | "state_mutability": "external" 1405 | }, 1406 | { 1407 | "type": "function", 1408 | "name": "move", 1409 | "inputs": [ 1410 | { 1411 | "name": "direction", 1412 | "type": "dojo_starter::models::Direction" 1413 | } 1414 | ], 1415 | "outputs": [], 1416 | "state_mutability": "external" 1417 | } 1418 | ] 1419 | }, 1420 | { 1421 | "type": "function", 1422 | "name": "dojo_init", 1423 | "inputs": [], 1424 | "outputs": [], 1425 | "state_mutability": "view" 1426 | }, 1427 | { 1428 | "type": "impl", 1429 | "name": "WorldProviderImpl", 1430 | "interface_name": "dojo::contract::components::world_provider::IWorldProvider" 1431 | }, 1432 | { 1433 | "type": "struct", 1434 | "name": "dojo::world::iworld::IWorldDispatcher", 1435 | "members": [ 1436 | { 1437 | "name": "contract_address", 1438 | "type": "core::starknet::contract_address::ContractAddress" 1439 | } 1440 | ] 1441 | }, 1442 | { 1443 | "type": "interface", 1444 | "name": "dojo::contract::components::world_provider::IWorldProvider", 1445 | "items": [ 1446 | { 1447 | "type": "function", 1448 | "name": "world_dispatcher", 1449 | "inputs": [], 1450 | "outputs": [ 1451 | { 1452 | "type": "dojo::world::iworld::IWorldDispatcher" 1453 | } 1454 | ], 1455 | "state_mutability": "view" 1456 | } 1457 | ] 1458 | }, 1459 | { 1460 | "type": "impl", 1461 | "name": "UpgradeableImpl", 1462 | "interface_name": "dojo::contract::components::upgradeable::IUpgradeable" 1463 | }, 1464 | { 1465 | "type": "interface", 1466 | "name": "dojo::contract::components::upgradeable::IUpgradeable", 1467 | "items": [ 1468 | { 1469 | "type": "function", 1470 | "name": "upgrade", 1471 | "inputs": [ 1472 | { 1473 | "name": "new_class_hash", 1474 | "type": "core::starknet::class_hash::ClassHash" 1475 | } 1476 | ], 1477 | "outputs": [], 1478 | "state_mutability": "external" 1479 | } 1480 | ] 1481 | }, 1482 | { 1483 | "type": "constructor", 1484 | "name": "constructor", 1485 | "inputs": [] 1486 | }, 1487 | { 1488 | "type": "event", 1489 | "name": "dojo::contract::components::upgradeable::upgradeable_cpt::Upgraded", 1490 | "kind": "struct", 1491 | "members": [ 1492 | { 1493 | "name": "class_hash", 1494 | "type": "core::starknet::class_hash::ClassHash", 1495 | "kind": "data" 1496 | } 1497 | ] 1498 | }, 1499 | { 1500 | "type": "event", 1501 | "name": "dojo::contract::components::upgradeable::upgradeable_cpt::Event", 1502 | "kind": "enum", 1503 | "variants": [ 1504 | { 1505 | "name": "Upgraded", 1506 | "type": "dojo::contract::components::upgradeable::upgradeable_cpt::Upgraded", 1507 | "kind": "nested" 1508 | } 1509 | ] 1510 | }, 1511 | { 1512 | "type": "event", 1513 | "name": "dojo::contract::components::world_provider::world_provider_cpt::Event", 1514 | "kind": "enum", 1515 | "variants": [] 1516 | }, 1517 | { 1518 | "type": "event", 1519 | "name": "dojo_starter::systems::actions::actions::Event", 1520 | "kind": "enum", 1521 | "variants": [ 1522 | { 1523 | "name": "UpgradeableEvent", 1524 | "type": "dojo::contract::components::upgradeable::upgradeable_cpt::Event", 1525 | "kind": "nested" 1526 | }, 1527 | { 1528 | "name": "WorldProviderEvent", 1529 | "type": "dojo::contract::components::world_provider::world_provider_cpt::Event", 1530 | "kind": "nested" 1531 | } 1532 | ] 1533 | } 1534 | ], 1535 | "init_calldata": [], 1536 | "tag": "dojo_starter-actions", 1537 | "selector": "0x7a1c71029f2d0b38e3ac89b09931d08b6e48417e079c289ff19a8698d0cba33", 1538 | "systems": [ 1539 | "spawn", 1540 | "move", 1541 | "upgrade" 1542 | ] 1543 | } 1544 | ], 1545 | "libraries": [], 1546 | "models": [ 1547 | { 1548 | "members": [], 1549 | "class_hash": "0x46d4db177d7edf355bf1e51fa72023171232b928ef3b9467dbd541611da5f83", 1550 | "tag": "dojo_starter-DirectionsAvailable", 1551 | "selector": "0x77844f1facb51e60e546a9832d56c6bd04fa23be4fd5b57290caae5e9a3c1e4" 1552 | }, 1553 | { 1554 | "members": [], 1555 | "class_hash": "0x5a3dcd4bf5a0e6fff9ca88dcd77c6b49f1a33a1b9bbea8ce5aa5290e9470070", 1556 | "tag": "dojo_starter-Moves", 1557 | "selector": "0x2a29373f1af8348bd366a990eb3a342ef2cbe5e85160539eaca3441a673f468" 1558 | }, 1559 | { 1560 | "members": [], 1561 | "class_hash": "0x7231f1cec2b0ba37c39e6d919d35648d07d86a687680aa92ccb0d65fe5af17e", 1562 | "tag": "dojo_starter-Position", 1563 | "selector": "0x2ac8b4c190f7031b9fc44312e6b047a1dce0b3f2957c33a935ca7846a46dd5b" 1564 | }, 1565 | { 1566 | "members": [], 1567 | "class_hash": "0x4518971c1abf10a6c1c40f8f72fc34816dee4752d66f0f2b9d29a62f4fb3310", 1568 | "tag": "dojo_starter-PositionCount", 1569 | "selector": "0x44e8e8c3aea54e97e01563cacc08abb4a8ce8c468cd4d3a332bca12bfc2290d" 1570 | } 1571 | ], 1572 | "events": [ 1573 | { 1574 | "members": [], 1575 | "class_hash": "0x49f539cc331573abc29d729a65824485514906457af4049ff148ffe421520cb", 1576 | "tag": "dojo_starter-Moved", 1577 | "selector": "0x504403e5c02b6442527721fc464d9ea5fc8f1ee600ab5ccd5c0845d36fd45f1" 1578 | } 1579 | ], 1580 | "external_contracts": [] 1581 | } -------------------------------------------------------------------------------- /src/lib.cairo: -------------------------------------------------------------------------------- 1 | pub mod systems { 2 | pub mod actions; 3 | } 4 | 5 | pub mod models; 6 | 7 | pub mod tests { 8 | mod test_world; 9 | } 10 | -------------------------------------------------------------------------------- /src/models.cairo: -------------------------------------------------------------------------------- 1 | use starknet::{ContractAddress}; 2 | 3 | #[derive(Copy, Drop, Serde, Debug)] 4 | #[dojo::model] 5 | pub struct Moves { 6 | #[key] 7 | pub player: ContractAddress, 8 | pub remaining: u8, 9 | pub last_direction: Option, 10 | pub can_move: bool, 11 | } 12 | 13 | #[derive(Drop, Serde, Debug)] 14 | #[dojo::model] 15 | pub struct DirectionsAvailable { 16 | #[key] 17 | pub player: ContractAddress, 18 | pub directions: Array, 19 | } 20 | 21 | #[derive(Copy, Drop, Serde, Debug)] 22 | #[dojo::model] 23 | pub struct Position { 24 | #[key] 25 | pub player: ContractAddress, 26 | pub vec: Vec2, 27 | } 28 | 29 | #[derive(Copy, Drop, Serde, Debug)] 30 | #[dojo::model] 31 | pub struct PositionCount { 32 | #[key] 33 | pub identity: ContractAddress, 34 | pub position: Span<(u8, u128)>, 35 | } 36 | 37 | 38 | #[derive(Serde, Copy, Drop, Introspect, PartialEq, Debug)] 39 | pub enum Direction { 40 | Left, 41 | Right, 42 | Up, 43 | Down, 44 | } 45 | 46 | 47 | #[derive(Copy, Drop, Serde, IntrospectPacked, Debug)] 48 | pub struct Vec2 { 49 | pub x: u32, 50 | pub y: u32, 51 | } 52 | 53 | 54 | impl DirectionIntoFelt252 of Into { 55 | fn into(self: Direction) -> felt252 { 56 | match self { 57 | Direction::Left => 1, 58 | Direction::Right => 2, 59 | Direction::Up => 3, 60 | Direction::Down => 4, 61 | } 62 | } 63 | } 64 | 65 | impl OptionDirectionIntoFelt252 of Into, felt252> { 66 | fn into(self: Option) -> felt252 { 67 | match self { 68 | Option::None => 0, 69 | Option::Some(d) => d.into(), 70 | } 71 | } 72 | } 73 | 74 | #[generate_trait] 75 | impl Vec2Impl of Vec2Trait { 76 | fn is_zero(self: Vec2) -> bool { 77 | if self.x - self.y == 0 { 78 | return true; 79 | } 80 | false 81 | } 82 | 83 | fn is_equal(self: Vec2, b: Vec2) -> bool { 84 | self.x == b.x && self.y == b.y 85 | } 86 | } 87 | 88 | #[cfg(test)] 89 | mod tests { 90 | use super::{Vec2, Vec2Trait}; 91 | 92 | #[test] 93 | fn test_vec_is_zero() { 94 | assert(Vec2Trait::is_zero(Vec2 { x: 0, y: 0 }), 'not zero'); 95 | } 96 | 97 | #[test] 98 | fn test_vec_is_equal() { 99 | let position = Vec2 { x: 420, y: 0 }; 100 | assert(position.is_equal(Vec2 { x: 420, y: 0 }), 'not equal'); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/systems/actions.cairo: -------------------------------------------------------------------------------- 1 | use dojo_starter::models::{Direction, Position}; 2 | 3 | // define the interface 4 | #[starknet::interface] 5 | pub trait IActions { 6 | fn spawn(ref self: T); 7 | fn move(ref self: T, direction: Direction); 8 | } 9 | 10 | // dojo decorator 11 | #[dojo::contract] 12 | pub mod actions { 13 | use super::{IActions, Direction, Position, next_position}; 14 | use starknet::{ContractAddress, get_caller_address}; 15 | use dojo_starter::models::{Vec2, Moves}; 16 | 17 | use dojo::model::{ModelStorage}; 18 | use dojo::event::EventStorage; 19 | 20 | #[derive(Copy, Drop, Serde)] 21 | #[dojo::event] 22 | pub struct Moved { 23 | #[key] 24 | pub player: ContractAddress, 25 | pub direction: Direction, 26 | } 27 | 28 | #[abi(embed_v0)] 29 | impl ActionsImpl of IActions { 30 | fn spawn(ref self: ContractState) { 31 | // Get the default world. 32 | let mut world = self.world_default(); 33 | 34 | // Get the address of the current caller, possibly the player's address. 35 | let player = get_caller_address(); 36 | // Retrieve the player's current position from the world. 37 | let position: Position = world.read_model(player); 38 | 39 | // Update the world state with the new data. 40 | 41 | // 1. Move the player's position 10 units in both the x and y direction. 42 | let new_position = Position { 43 | player, vec: Vec2 { x: position.vec.x + 10, y: position.vec.y + 10 }, 44 | }; 45 | 46 | // Write the new position to the world. 47 | world.write_model(@new_position); 48 | 49 | // 2. Set the player's remaining moves to 100. 50 | let moves = Moves { 51 | player, remaining: 100, last_direction: Option::None, can_move: true, 52 | }; 53 | 54 | // Write the new moves to the world. 55 | world.write_model(@moves); 56 | } 57 | 58 | // Implementation of the move function for the ContractState struct. 59 | fn move(ref self: ContractState, direction: Direction) { 60 | // Get the address of the current caller, possibly the player's address. 61 | 62 | let mut world = self.world_default(); 63 | 64 | let player = get_caller_address(); 65 | 66 | // Retrieve the player's current position and moves data from the world. 67 | let position: Position = world.read_model(player); 68 | let mut moves: Moves = world.read_model(player); 69 | // if player hasn't spawn, read returns model default values. This leads to sub overflow 70 | // afterwards. 71 | // Plus it's generally considered as a good pratice to fast-return on matching 72 | // conditions. 73 | if !moves.can_move { 74 | return; 75 | } 76 | 77 | // Deduct one from the player's remaining moves. 78 | moves.remaining -= 1; 79 | 80 | // Update the last direction the player moved in. 81 | moves.last_direction = Option::Some(direction); 82 | 83 | // Calculate the player's next position based on the provided direction. 84 | let next = next_position(position, moves.last_direction); 85 | 86 | // Write the new position to the world. 87 | world.write_model(@next); 88 | 89 | // Write the new moves to the world. 90 | world.write_model(@moves); 91 | 92 | // Emit an event to the world to notify about the player's move. 93 | world.emit_event(@Moved { player, direction }); 94 | } 95 | } 96 | 97 | #[generate_trait] 98 | impl InternalImpl of InternalTrait { 99 | /// Use the default namespace "dojo_starter". This function is handy since the ByteArray 100 | /// can't be const. 101 | fn world_default(self: @ContractState) -> dojo::world::WorldStorage { 102 | self.world(@"dojo_starter") 103 | } 104 | } 105 | } 106 | 107 | // Define function like this: 108 | fn next_position(mut position: Position, direction: Option) -> Position { 109 | match direction { 110 | Option::None => { return position; }, 111 | Option::Some(d) => match d { 112 | Direction::Left => { position.vec.x -= 1; }, 113 | Direction::Right => { position.vec.x += 1; }, 114 | Direction::Up => { position.vec.y -= 1; }, 115 | Direction::Down => { position.vec.y += 1; }, 116 | }, 117 | }; 118 | position 119 | } 120 | -------------------------------------------------------------------------------- /src/tests/test_world.cairo: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use dojo_cairo_test::WorldStorageTestTrait; 4 | use dojo::model::{ModelStorage, ModelStorageTest}; 5 | use dojo::world::WorldStorageTrait; 6 | use dojo_cairo_test::{ 7 | spawn_test_world, NamespaceDef, TestResource, ContractDefTrait, ContractDef, 8 | }; 9 | 10 | use dojo_starter::systems::actions::{actions, IActionsDispatcher, IActionsDispatcherTrait}; 11 | use dojo_starter::models::{Position, m_Position, Moves, m_Moves, Direction}; 12 | 13 | fn namespace_def() -> NamespaceDef { 14 | let ndef = NamespaceDef { 15 | namespace: "dojo_starter", 16 | resources: [ 17 | TestResource::Model(m_Position::TEST_CLASS_HASH), 18 | TestResource::Model(m_Moves::TEST_CLASS_HASH), 19 | TestResource::Event(actions::e_Moved::TEST_CLASS_HASH), 20 | TestResource::Contract(actions::TEST_CLASS_HASH), 21 | ] 22 | .span(), 23 | }; 24 | 25 | ndef 26 | } 27 | 28 | fn contract_defs() -> Span { 29 | [ 30 | ContractDefTrait::new(@"dojo_starter", @"actions") 31 | .with_writer_of([dojo::utils::bytearray_hash(@"dojo_starter")].span()) 32 | ] 33 | .span() 34 | } 35 | 36 | #[test] 37 | fn test_world_test_set() { 38 | // Initialize test environment 39 | let caller = starknet::contract_address_const::<0x0>(); 40 | let ndef = namespace_def(); 41 | 42 | // Register the resources. 43 | let mut world = spawn_test_world([ndef].span()); 44 | 45 | // Ensures permissions and initializations are synced. 46 | world.sync_perms_and_inits(contract_defs()); 47 | 48 | // Test initial position 49 | let mut position: Position = world.read_model(caller); 50 | assert(position.vec.x == 0 && position.vec.y == 0, 'initial position wrong'); 51 | 52 | // Test write_model_test 53 | position.vec.x = 122; 54 | position.vec.y = 88; 55 | 56 | world.write_model_test(@position); 57 | 58 | let mut position: Position = world.read_model(caller); 59 | assert(position.vec.y == 88, 'write_value_from_id failed'); 60 | 61 | // Test model deletion 62 | world.erase_model(@position); 63 | let position: Position = world.read_model(caller); 64 | assert(position.vec.x == 0 && position.vec.y == 0, 'erase_model failed'); 65 | } 66 | 67 | #[test] 68 | #[available_gas(30000000)] 69 | fn test_move() { 70 | let caller = starknet::contract_address_const::<0x0>(); 71 | 72 | let ndef = namespace_def(); 73 | let mut world = spawn_test_world([ndef].span()); 74 | world.sync_perms_and_inits(contract_defs()); 75 | 76 | let (contract_address, _) = world.dns(@"actions").unwrap(); 77 | let actions_system = IActionsDispatcher { contract_address }; 78 | 79 | actions_system.spawn(); 80 | let initial_moves: Moves = world.read_model(caller); 81 | let initial_position: Position = world.read_model(caller); 82 | 83 | assert( 84 | initial_position.vec.x == 10 && initial_position.vec.y == 10, 'wrong initial position', 85 | ); 86 | 87 | actions_system.move(Direction::Right(()).into()); 88 | 89 | let moves: Moves = world.read_model(caller); 90 | let right_dir_felt: felt252 = Direction::Right(()).into(); 91 | 92 | assert(moves.remaining == initial_moves.remaining - 1, 'moves is wrong'); 93 | assert(moves.last_direction.unwrap().into() == right_dir_felt, 'last direction is wrong'); 94 | 95 | let new_position: Position = world.read_model(caller); 96 | assert(new_position.vec.x == initial_position.vec.x + 1, 'position x is wrong'); 97 | assert(new_position.vec.y == initial_position.vec.y, 'position y is wrong'); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /torii_dev.toml: -------------------------------------------------------------------------------- 1 | [indexing] 2 | contracts = [ 3 | "erc20:0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", # ETH fee token 4 | "erc20:0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", # STRK fee token 5 | ] 6 | [sql] 7 | historical = ["dojo_starter-Moves", "dojo_starter-Moved"] 8 | 9 | --------------------------------------------------------------------------------