diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 48e96820a3..0895fc1ad4 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -11,13 +11,14 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ RUN apt install -y gh libgmp3-dev -COPY rust-toolchain.toml . +# To allow independent workflow of the container, the rust-toolchain is explicitely given. +RUN echo "1.74.0" > rust_toolchain_version # Install cargo-binstall RUN curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash -RUN rustup toolchain install $(cat rust-toolchain.toml | grep channel | cut -d\" -f2) && \ - rustup default $(cat rust-toolchain.toml | grep channel | cut -d\" -f2) && \ +RUN rustup toolchain install $(cat rust_toolchain_version) && \ + rustup default $(cat rust_toolchain_version) && \ rustup component add clippy && \ rustup component add rustfmt @@ -37,14 +38,14 @@ RUN if [ "$TARGETPLATFORM" = "linux/arm64" ] ; then \ mv hurl-4.1.0-aarch64-unknown-linux-gnu/hurl /usr/local/bin/ && \ rm -r hurl-4.1.0-aarch64-unknown-linux-gnu && \ rm hurl.tar.gz && \ - rustup component add llvm-tools-preview --toolchain 1.74.0-aarch64-unknown-linux-gnu; \ + rustup component add llvm-tools-preview --toolchain $(cat rust_toolchain_version)-aarch64-unknown-linux-gnu; \ elif [ "$TARGETPLATFORM" = "linux/amd64" ] ; then \ curl -L https://github.com/Orange-OpenSource/hurl/releases/download/4.1.0/hurl-4.1.0-x86_64-unknown-linux-gnu.tar.gz -o hurl.tar.gz && \ tar -xzf hurl.tar.gz && \ mv hurl-4.1.0-x86_64-unknown-linux-gnu/hurl /usr/local/bin/ && \ rm -r hurl-4.1.0-x86_64-unknown-linux-gnu && \ rm hurl.tar.gz && \ - rustup component add llvm-tools-preview --toolchain 1.74.0-x86_64-unknown-linux-gnu && \ + rustup component add llvm-tools-preview --toolchain $(cat rust_toolchain_version)-x86_64-unknown-linux-gnu && \ rustup target add x86_64-fortanix-unknown-sgx --toolchain nightly; \ fi diff --git a/crates/dojo-world/src/metadata.rs b/crates/dojo-world/src/metadata.rs index 9726192215..a3c2c7d1ca 100644 --- a/crates/dojo-world/src/metadata.rs +++ b/crates/dojo-world/src/metadata.rs @@ -113,7 +113,6 @@ impl Environment { self.private_key.as_deref() } - #[allow(dead_code)] pub fn keystore_path(&self) -> Option<&str> { self.keystore_path.as_deref() } diff --git a/crates/katana/core/contracts/messaging/cairo/Makefile b/crates/katana/core/contracts/messaging/cairo/Makefile index 48d76a402b..aac32186a6 100644 --- a/crates/katana/core/contracts/messaging/cairo/Makefile +++ b/crates/katana/core/contracts/messaging/cairo/Makefile @@ -1,5 +1,5 @@ ACCOUNT_L2=./account_l2.json -ACCOUNT_L2_ADDR=0x9238c8ca6b3c6ab45a793593b13d98797ccd3bda179d313553e51fee114624 +ACCOUNT_L2_ADDR=0x6162896d1d7ab204c7ccac6dd5f8e9e7c25ecd5ae4fcb4ad32e57786bb46e03 L2_PRIVATE_KEY=0x1800000000300000180000000000030000000000003006001800006600 # Build files helpers. diff --git a/crates/katana/core/contracts/messaging/cairo/account_l2.json b/crates/katana/core/contracts/messaging/cairo/account_l2.json index 32f05e685d..788b31022a 100644 --- a/crates/katana/core/contracts/messaging/cairo/account_l2.json +++ b/crates/katana/core/contracts/messaging/cairo/account_l2.json @@ -8,6 +8,6 @@ "deployment": { "status": "deployed", "class_hash": "0x4d07e40e93398ed3c76981e72dd1fd22557a78ce36c0515f679e27f0bb5bc5f", - "address": "0x9238c8ca6b3c6ab45a793593b13d98797ccd3bda179d313553e51fee114624" + "address": "0x6162896d1d7ab204c7ccac6dd5f8e9e7c25ecd5ae4fcb4ad32e57786bb46e03" } } diff --git a/crates/katana/core/contracts/messaging/solidity/Makefile b/crates/katana/core/contracts/messaging/solidity/Makefile index 4baa800e98..1291370c05 100644 --- a/crates/katana/core/contracts/messaging/solidity/Makefile +++ b/crates/katana/core/contracts/messaging/solidity/Makefile @@ -9,7 +9,7 @@ export $(shell sed 's/=.*//' .env) # Addresses fixed here for easy testing. C_MSG_L2_ADDR=0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 -L2_ACCOUNT=0x9238c8ca6b3c6ab45a793593b13d98797ccd3bda179d313553e51fee114624 +L2_ACCOUNT=0x6162896d1d7ab204c7ccac6dd5f8e9e7c25ecd5ae4fcb4ad32e57786bb46e03 L2_CONTRACT_ADDR=0x0429a64d97c1422a37a09fc7406f35c264be59b744aaff5a79d59393eb1bc7e1 deploy_messaging_contracts: diff --git a/crates/katana/core/src/accounts.rs b/crates/katana/core/src/accounts.rs index 25ff933c12..f602a38e34 100644 --- a/crates/katana/core/src/accounts.rs +++ b/crates/katana/core/src/accounts.rs @@ -1,8 +1,6 @@ use std::fmt::Display; -use std::sync::Arc; use anyhow::Result; -use blockifier::execution::contract_class::ContractClass; use katana_primitives::contract::ContractAddress; use katana_primitives::FieldElement; use katana_provider::traits::state::StateWriter; @@ -14,9 +12,7 @@ use starknet::core::serde::unsigned_field_element::UfeHex; use starknet::core::utils::{get_contract_address, get_storage_var_address}; use starknet::signers::SigningKey; -use crate::constants::{ - FEE_TOKEN_ADDRESS, OZ_V1_ACCOUNT_CONTRACT_COMPILED, OZ_V1_ACCOUNT_CONTRACT_COMPILED_CLASS_HASH, -}; +use crate::constants::{FEE_TOKEN_ADDRESS, OZ_V1_ACCOUNT_CONTRACT_CLASS_HASH}; #[serde_as] #[derive(Debug, Clone, Serialize)] @@ -31,18 +27,11 @@ pub struct Account { pub address: FieldElement, #[serde_as(as = "UfeHex")] pub class_hash: FieldElement, - #[serde(skip_serializing)] - pub contract_class: Arc, } impl Account { #[must_use] - pub fn new( - private_key: FieldElement, - balance: FieldElement, - class_hash: FieldElement, - contract_class: Arc, - ) -> Self { + pub fn new(private_key: FieldElement, balance: FieldElement, class_hash: FieldElement) -> Self { let public_key = public_key_from_private_key(private_key); let address = get_contract_address( FieldElement::from(666u32), @@ -51,7 +40,7 @@ impl Account { FieldElement::ZERO, ); - Self { address, public_key, balance, class_hash, private_key, contract_class } + Self { address, public_key, balance, class_hash, private_key } } // TODO: separate fund logic from this struct - implement FeeToken type @@ -104,7 +93,6 @@ pub struct DevAccountGenerator { pub seed: [u8; 32], pub balance: FieldElement, pub class_hash: FieldElement, - pub contract_class: Arc, } impl DevAccountGenerator { @@ -114,8 +102,7 @@ impl DevAccountGenerator { total, seed: [0u8; 32], balance: FieldElement::ZERO, - class_hash: (*OZ_V1_ACCOUNT_CONTRACT_COMPILED_CLASS_HASH), - contract_class: Arc::new((*OZ_V1_ACCOUNT_CONTRACT_COMPILED).clone()), + class_hash: (*OZ_V1_ACCOUNT_CONTRACT_CLASS_HASH), } } @@ -127,10 +114,6 @@ impl DevAccountGenerator { Self { balance, ..self } } - pub fn with_class(self, class_hash: FieldElement, contract_class: Arc) -> Self { - Self { class_hash, contract_class, ..self } - } - /// Generate `total` number of accounts based on the `seed`. #[must_use] pub fn generate(&self) -> Vec { @@ -147,12 +130,7 @@ impl DevAccountGenerator { let private_key = FieldElement::from_bytes_be(&private_key_bytes) .expect("able to create FieldElement from bytes"); - Account::new( - private_key, - self.balance, - self.class_hash, - self.contract_class.clone(), - ) + Account::new(private_key, self.balance, self.class_hash) }) .collect() } diff --git a/crates/katana/core/src/service/messaging/starknet.rs b/crates/katana/core/src/service/messaging/starknet.rs index 2b7d2d3d8e..642f0de240 100644 --- a/crates/katana/core/src/service/messaging/starknet.rs +++ b/crates/katana/core/src/service/messaging/starknet.rs @@ -488,7 +488,7 @@ mod tests { let to_address = selector!("to_address"); let selector = selector!("selector"); let nonce = FieldElement::ONE; - let calldata = vec![from_address, FieldElement::THREE]; + let calldata = [from_address, FieldElement::THREE]; let transaction_hash = FieldElement::ZERO; let event = EmittedEvent { @@ -522,7 +522,7 @@ mod tests { let _to_address = selector!("to_address"); let _selector = selector!("selector"); let _nonce = FieldElement::ONE; - let _calldata = vec![from_address, FieldElement::THREE]; + let _calldata = [from_address, FieldElement::THREE]; let transaction_hash = FieldElement::ZERO; let event = EmittedEvent { diff --git a/crates/katana/core/src/utils/mod.rs b/crates/katana/core/src/utils/mod.rs index 26bae491be..91c5529a06 100644 --- a/crates/katana/core/src/utils/mod.rs +++ b/crates/katana/core/src/utils/mod.rs @@ -42,14 +42,14 @@ pub(super) fn get_genesis_states_for_testing() -> StateUpdatesWithDeclaredClasse ]); let declared_sierra_classes = HashMap::from([( - *OZ_V1_ACCOUNT_CONTRACT_COMPILED_CLASS_HASH, + *OZ_V1_ACCOUNT_CONTRACT_CLASS_HASH, OZ_V1_ACCOUNT_CONTRACT.clone().flatten().unwrap(), )]); let declared_compiled_classes = HashMap::from([ - (*UDC_COMPILED_CLASS_HASH, (*UDC_CONTRACT).clone()), - (*ERC20_CONTRACT_COMPILED_CLASS_HASH, (*ERC20_CONTRACT).clone()), - (*OZ_V1_ACCOUNT_CONTRACT_COMPILED_CLASS_HASH, (*OZ_V1_ACCOUNT_CONTRACT_COMPILED).clone()), + (*UDC_CLASS_HASH, (*UDC_CONTRACT).clone()), + (*ERC20_CONTRACT_CLASS_HASH, (*ERC20_CONTRACT).clone()), + (*OZ_V1_ACCOUNT_CONTRACT_CLASS_HASH, (*OZ_V1_ACCOUNT_CONTRACT_COMPILED).clone()), ]); StateUpdatesWithDeclaredClasses { diff --git a/crates/katana/storage/provider/tests/block.rs b/crates/katana/storage/provider/tests/block.rs index 1886b7caac..1128d89378 100644 --- a/crates/katana/storage/provider/tests/block.rs +++ b/crates/katana/storage/provider/tests/block.rs @@ -26,14 +26,6 @@ use fixtures::{ }; use utils::generate_dummy_blocks_and_receipts; -#[template] -#[rstest::rstest] -#[case::insert_1_block(1)] -#[case::insert_2_block(2)] -#[case::insert_5_block(5)] -#[case::insert_10_block(10)] -fn insert_block_cases(#[case] block_count: u64) {} - #[apply(insert_block_cases)] fn insert_block_with_in_memory_provider( #[from(in_memory_provider)] provider: BlockchainProvider, @@ -139,19 +131,6 @@ where Ok(()) } -#[template] -#[rstest::rstest] -#[case::state_update_at_block_1(1, mock_state_updates()[0].clone())] -#[case::state_update_at_block_2(2, mock_state_updates()[1].clone())] -#[case::state_update_at_block_3(3, StateUpdatesWithDeclaredClasses::default())] -#[case::state_update_at_block_5(5, mock_state_updates()[2].clone())] -fn test_read_state_update( - #[from(provider_with_states)] provider: BlockchainProvider, - #[case] block_num: BlockNumber, - #[case] expected_state_update: StateUpdatesWithDeclaredClasses, -) { -} - #[apply(test_read_state_update)] fn test_read_state_update_with_in_memory_provider( #[with(in_memory_provider())] provider: BlockchainProvider, @@ -193,3 +172,24 @@ where assert_eq!(actual_state_update, Some(expected_state_update.state_updates)); Ok(()) } + +#[template] +#[rstest::rstest] +#[case::insert_1_block(1)] +#[case::insert_2_block(2)] +#[case::insert_5_block(5)] +#[case::insert_10_block(10)] +fn insert_block_cases(#[case] block_count: u64) {} + +#[template] +#[rstest::rstest] +#[case::state_update_at_block_1(1, mock_state_updates()[0].clone())] +#[case::state_update_at_block_2(2, mock_state_updates()[1].clone())] +#[case::state_update_at_block_3(3, StateUpdatesWithDeclaredClasses::default())] +#[case::state_update_at_block_5(5, mock_state_updates()[2].clone())] +fn test_read_state_update( + #[from(provider_with_states)] provider: BlockchainProvider, + #[case] block_num: BlockNumber, + #[case] expected_state_update: StateUpdatesWithDeclaredClasses, +) { +} diff --git a/crates/sozo/src/commands/options/account.rs b/crates/sozo/src/commands/options/account.rs index ad91c21ce8..2afff4fddd 100644 --- a/crates/sozo/src/commands/options/account.rs +++ b/crates/sozo/src/commands/options/account.rs @@ -8,14 +8,22 @@ use starknet::core::types::FieldElement; use starknet::providers::Provider; use starknet::signers::{LocalWallet, SigningKey}; +use super::{ + DOJO_ACCOUNT_ADDRESS_ENV_VAR, DOJO_KEYSTORE_PASSWORD_ENV_VAR, DOJO_PRIVATE_KEY_ENV_VAR, +}; + #[derive(Debug, Args)] #[command(next_help_heading = "Account options")] +// INVARIANT: +// - For commandline: we can either specify `private_key` or `keystore_path` along with +// `keystore_password`. This is enforced by Clap. +// - For `Scarb.toml`: if both private_key and keystore are specified in `Scarb.toml` private_key +// will take priority pub struct AccountOptions { - #[arg(long)] + #[arg(long, env = DOJO_ACCOUNT_ADDRESS_ENV_VAR)] pub account_address: Option, - #[arg(long)] - #[arg(requires = "account_address")] + #[arg(long, env = DOJO_PRIVATE_KEY_ENV_VAR)] #[arg(conflicts_with = "keystore_path")] #[arg(help_heading = "Signer options - RAW")] #[arg(help = "The raw private key associated with the account contract.")] @@ -27,9 +35,8 @@ pub struct AccountOptions { #[arg(help = "Use the keystore in the given folder or file.")] pub keystore_path: Option, - #[arg(long = "password")] + #[arg(long = "password", env = DOJO_KEYSTORE_PASSWORD_ENV_VAR)] #[arg(value_name = "PASSWORD")] - #[arg(requires = "keystore_path")] #[arg(help_heading = "Signer options - KEYSTORE")] #[arg(help = "The keystore password. Used with --keystore.")] pub keystore_password: Option, @@ -60,23 +67,23 @@ impl AccountOptions { } fn signer(&self, env_metadata: Option<&Environment>) -> Result { - if let Some(private_key) = self - .private_key - .as_deref() - .or_else(|| env_metadata.and_then(|env| env.private_key())) - .or(std::env::var("DOJO_PRIVATE_KEY").ok().as_deref()) + if let Some(private_key) = + self.private_key.as_deref().or_else(|| env_metadata.and_then(|env| env.private_key())) { return Ok(LocalWallet::from_signing_key(SigningKey::from_secret_scalar( FieldElement::from_str(private_key)?, ))); } - if let Some(path) = &self.keystore_path { + if let Some(path) = &self + .keystore_path + .as_deref() + .or_else(|| env_metadata.and_then(|env| env.keystore_path())) + { if let Some(password) = self .keystore_password .as_deref() .or_else(|| env_metadata.and_then(|env| env.keystore_password())) - .or(std::env::var("DOJO_KEYSTORE_PASSWORD").ok().as_deref()) { return Ok(LocalWallet::from_signing_key(SigningKey::from_keystore( path, password, @@ -95,10 +102,7 @@ impl AccountOptions { fn account_address(&self, env_metadata: Option<&Environment>) -> Result { if let Some(address) = self.account_address { Ok(address) - } else if let Some(address) = env_metadata - .and_then(|env| env.account_address()) - .or(std::env::var("DOJO_ACCOUNT_ADDRESS").ok().as_deref()) - { + } else if let Some(address) = env_metadata.and_then(|env| env.account_address()) { Ok(FieldElement::from_str(address)?) } else { Err(anyhow!( @@ -108,3 +112,214 @@ impl AccountOptions { } } } + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use clap::Parser; + use starknet::signers::{LocalWallet, Signer, SigningKey}; + use starknet_crypto::FieldElement; + + use super::{ + AccountOptions, DOJO_ACCOUNT_ADDRESS_ENV_VAR, DOJO_KEYSTORE_PASSWORD_ENV_VAR, + DOJO_PRIVATE_KEY_ENV_VAR, + }; + + #[derive(clap::Parser, Debug)] + struct Command { + #[clap(flatten)] + pub account: AccountOptions, + } + + #[test] + fn account_address_read_from_env_variable() { + std::env::set_var(DOJO_ACCOUNT_ADDRESS_ENV_VAR, "0x0"); + + let cmd = Command::parse_from([""]); + assert_eq!(cmd.account.account_address, Some(FieldElement::from_hex_be("0x0").unwrap())); + } + + #[test] + fn private_key_read_from_env_variable() { + std::env::set_var(DOJO_PRIVATE_KEY_ENV_VAR, "private_key"); + + let cmd = Command::parse_from(["sozo", "--account-address", "0x0"]); + assert_eq!(cmd.account.private_key, Some("private_key".to_owned())); + } + + #[test] + fn keystore_path_read_from_env_variable() { + std::env::set_var(DOJO_KEYSTORE_PASSWORD_ENV_VAR, "keystore_password"); + + let cmd = Command::parse_from(["sozo", "--keystore", "./some/path"]); + assert_eq!(cmd.account.keystore_password, Some("keystore_password".to_owned())); + } + + #[test] + fn account_address_from_args() { + let env_metadata = dojo_world::metadata::Environment::default(); + + let cmd = Command::parse_from(["sozo", "--account-address", "0x0"]); + assert_eq!( + cmd.account.account_address(Some(&env_metadata)).unwrap(), + FieldElement::from_hex_be("0x0").unwrap() + ); + } + + #[test] + fn account_address_from_env_metadata() { + let env_metadata = dojo_world::metadata::Environment { + account_address: Some("0x0".to_owned()), + ..Default::default() + }; + + let cmd = Command::parse_from([""]); + assert_eq!( + cmd.account.account_address(Some(&env_metadata)).unwrap(), + FieldElement::from_hex_be("0x0").unwrap() + ); + } + + #[test] + fn account_address_from_both() { + let env_metadata = dojo_world::metadata::Environment { + account_address: Some("0x0".to_owned()), + ..Default::default() + }; + + let cmd = Command::parse_from(["sozo", "--account-address", "0x1"]); + assert_eq!( + cmd.account.account_address(Some(&env_metadata)).unwrap(), + FieldElement::from_hex_be("0x1").unwrap() + ); + } + + #[test] + fn account_address_from_neither() { + let env_metadata = dojo_world::metadata::Environment::default(); + + let cmd = Command::parse_from([""]); + assert!(cmd.account.account_address(Some(&env_metadata)).is_err()); + } + + #[tokio::test] + async fn private_key_from_args() { + let env_metadata = dojo_world::metadata::Environment::default(); + let private_key = "0x1"; + + let cmd = + Command::parse_from(["sozo", "--account-address", "0x0", "--private-key", private_key]); + let result_wallet = cmd.account.signer(Some(&env_metadata)).unwrap(); + let expected_wallet = LocalWallet::from_signing_key(SigningKey::from_secret_scalar( + FieldElement::from_str(private_key).unwrap(), + )); + + let result_public_key = result_wallet.get_public_key().await.unwrap(); + let expected_public_key = expected_wallet.get_public_key().await.unwrap(); + assert!(result_public_key.scalar() == expected_public_key.scalar()); + } + + #[tokio::test] + async fn private_key_from_env_metadata() { + let private_key = "0x1"; + let env_metadata = dojo_world::metadata::Environment { + private_key: Some(private_key.to_owned()), + ..Default::default() + }; + + let cmd = Command::parse_from(["sozo", "--account-address", "0x0"]); + let result_wallet = cmd.account.signer(Some(&env_metadata)).unwrap(); + let expected_wallet = LocalWallet::from_signing_key(SigningKey::from_secret_scalar( + FieldElement::from_str(private_key).unwrap(), + )); + + let result_public_key = result_wallet.get_public_key().await.unwrap(); + let expected_public_key = expected_wallet.get_public_key().await.unwrap(); + assert!(result_public_key.scalar() == expected_public_key.scalar()); + } + + #[tokio::test] + async fn keystore_path_and_keystore_password_from_args() { + let keystore_path = "./tests/test_data/keystore/test.json"; + let keystore_password = "dojoftw"; + let private_key = "0x1"; + let env_metadata = dojo_world::metadata::Environment::default(); + + let cmd = Command::parse_from([ + "sozo", + "--keystore", + keystore_path, + "--password", + keystore_password, + ]); + let result_wallet = cmd.account.signer(Some(&env_metadata)).unwrap(); + let expected_wallet = LocalWallet::from_signing_key(SigningKey::from_secret_scalar( + FieldElement::from_str(private_key).unwrap(), + )); + + let result_public_key = result_wallet.get_public_key().await.unwrap(); + let expected_public_key = expected_wallet.get_public_key().await.unwrap(); + assert!(result_public_key.scalar() == expected_public_key.scalar()); + } + + #[tokio::test] + async fn keystore_path_from_env_metadata() { + let keystore_path = "./tests/test_data/keystore/test.json"; + let keystore_password = "dojoftw"; + + let private_key = "0x1"; + let env_metadata = dojo_world::metadata::Environment { + keystore_path: Some(keystore_path.to_owned()), + ..Default::default() + }; + + let cmd = Command::parse_from(["sozo", "--password", keystore_password]); + let result_wallet = cmd.account.signer(Some(&env_metadata)).unwrap(); + let expected_wallet = LocalWallet::from_signing_key(SigningKey::from_secret_scalar( + FieldElement::from_str(private_key).unwrap(), + )); + + let result_public_key = result_wallet.get_public_key().await.unwrap(); + let expected_public_key = expected_wallet.get_public_key().await.unwrap(); + assert!(result_public_key.scalar() == expected_public_key.scalar()); + } + + #[tokio::test] + async fn keystore_password_from_env_metadata() { + let keystore_path = "./tests/test_data/keystore/test.json"; + let keystore_password = "dojoftw"; + let private_key = "0x1"; + + let env_metadata = dojo_world::metadata::Environment { + keystore_password: Some(keystore_password.to_owned()), + ..Default::default() + }; + + let cmd = Command::parse_from(["sozo", "--keystore", keystore_path]); + let result_wallet = cmd.account.signer(Some(&env_metadata)).unwrap(); + let expected_wallet = LocalWallet::from_signing_key(SigningKey::from_secret_scalar( + FieldElement::from_str(private_key).unwrap(), + )); + + let result_public_key = result_wallet.get_public_key().await.unwrap(); + let expected_public_key = expected_wallet.get_public_key().await.unwrap(); + assert!(result_public_key.scalar() == expected_public_key.scalar()); + } + + #[test] + fn dont_allow_both_private_key_and_keystore() { + let keystore_path = "./tests/test_data/keystore/test.json"; + let private_key = "0x1"; + assert!( + Command::try_parse_from([ + "sozo", + "--keystore", + keystore_path, + "--private_key", + private_key, + ]) + .is_err() + ); + } +} diff --git a/crates/sozo/src/commands/options/mod.rs b/crates/sozo/src/commands/options/mod.rs index e7d2645387..40ec922b9f 100644 --- a/crates/sozo/src/commands/options/mod.rs +++ b/crates/sozo/src/commands/options/mod.rs @@ -2,3 +2,8 @@ pub mod account; pub mod starknet; pub mod transaction; pub mod world; + +const STARKNET_RPC_URL_ENV_VAR: &str = "STARKNET_RPC_URL"; +const DOJO_PRIVATE_KEY_ENV_VAR: &str = "DOJO_PRIVATE_KEY"; +const DOJO_KEYSTORE_PASSWORD_ENV_VAR: &str = "DOJO_KEYSTORE_PASSWORD"; +const DOJO_ACCOUNT_ADDRESS_ENV_VAR: &str = "DOJO_ACCOUNT_ADDRESS"; diff --git a/crates/sozo/src/commands/options/starknet.rs b/crates/sozo/src/commands/options/starknet.rs index 9f024f20b3..011b04ae9e 100644 --- a/crates/sozo/src/commands/options/starknet.rs +++ b/crates/sozo/src/commands/options/starknet.rs @@ -5,15 +5,15 @@ use starknet::providers::jsonrpc::HttpTransport; use starknet::providers::JsonRpcClient; use url::Url; -const STARKNET_RPC_URL_ENV_VAR: &str = "STARKNET_RPC_URL"; +use super::STARKNET_RPC_URL_ENV_VAR; #[derive(Debug, Args)] #[command(next_help_heading = "Starknet options")] pub struct StarknetOptions { - #[arg(long, env = STARKNET_RPC_URL_ENV_VAR, default_value = "http://localhost:5050")] + #[arg(long, env = STARKNET_RPC_URL_ENV_VAR)] #[arg(value_name = "URL")] #[arg(help = "The Starknet RPC endpoint.")] - pub rpc_url: Url, + pub rpc_url: Option, } impl StarknetOptions { @@ -26,11 +26,13 @@ impl StarknetOptions { // we dont check the env var because that would be handled by `clap` fn url(&self, env_metadata: Option<&Environment>) -> Result { - Ok(if let Some(url) = env_metadata.and_then(|env| env.rpc_url()) { - Url::parse(url)? + if let Some(url) = self.rpc_url.as_ref() { + Ok(url.clone()) + } else if let Some(url) = env_metadata.and_then(|env| env.rpc_url()) { + Ok(Url::parse(url)?) } else { - self.rpc_url.clone() - }) + Ok(Url::parse("http://localhost:5050").unwrap()) + } } } @@ -39,10 +41,11 @@ mod tests { use clap::Parser; use super::StarknetOptions; - use crate::commands::options::starknet::STARKNET_RPC_URL_ENV_VAR; + use crate::commands::options::STARKNET_RPC_URL_ENV_VAR; const ENV_RPC: &str = "http://localhost:7474/"; const METADATA_RPC: &str = "http://localhost:6060/"; + const DEFAULT_RPC: &str = "http://localhost:5050/"; #[derive(clap::Parser)] struct Command { @@ -51,7 +54,15 @@ mod tests { } #[test] - fn url_exist_in_env_metadata_but_env_doesnt() { + fn url_read_from_env_variable() { + std::env::set_var(STARKNET_RPC_URL_ENV_VAR, ENV_RPC); + + let cmd = Command::parse_from([""]); + assert_eq!(cmd.options.url(None).unwrap().as_str(), ENV_RPC); + } + + #[test] + fn url_exist_in_env_but_not_in_args() { let env_metadata = dojo_world::metadata::Environment { rpc_url: Some(METADATA_RPC.into()), ..Default::default() @@ -62,21 +73,28 @@ mod tests { } #[test] - fn url_doesnt_exist_in_env_metadata_but_env_does() { - std::env::set_var(STARKNET_RPC_URL_ENV_VAR, ENV_RPC); + fn url_doesnt_exist_in_env_but_exist_in_args() { let env_metadata = dojo_world::metadata::Environment::default(); - let cmd = Command::parse_from([""]); + let cmd = Command::parse_from(["sozo", "--rpc-url", ENV_RPC]); + assert_eq!(cmd.options.url(Some(&env_metadata)).unwrap().as_str(), ENV_RPC); } #[test] - fn exists_in_both() { - std::env::set_var(STARKNET_RPC_URL_ENV_VAR, ENV_RPC); + fn url_exists_in_both() { let env_metadata = dojo_world::metadata::Environment { rpc_url: Some(METADATA_RPC.into()), ..Default::default() }; + + let cmd = Command::parse_from(["sozo", "--rpc-url", ENV_RPC]); + assert_eq!(cmd.options.url(Some(&env_metadata)).unwrap().as_str(), ENV_RPC); + } + + #[test] + fn url_exists_in_neither() { + let env_metadata = dojo_world::metadata::Environment::default(); let cmd = Command::parse_from([""]); - assert_eq!(cmd.options.url(Some(&env_metadata)).unwrap().as_str(), METADATA_RPC); + assert_eq!(cmd.options.url(Some(&env_metadata)).unwrap().as_str(), DEFAULT_RPC); } } diff --git a/crates/sozo/tests/test_data/keystore/test.json b/crates/sozo/tests/test_data/keystore/test.json new file mode 100644 index 0000000000..afcf956282 --- /dev/null +++ b/crates/sozo/tests/test_data/keystore/test.json @@ -0,0 +1 @@ +{"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"86dcdc44db46801dd2df660e2242926c"},"ciphertext":"75c93de54b0d29c9d5ecce255478cfb52ce6c82752af0f4f1e353be91ab93f2a","kdf":"scrypt","kdfparams":{"dklen":32,"n":8192,"p":1,"r":8,"salt":"e9342c34144d65f40c5ecee338cea267f96049e9795fa52d1d9cb96923fce998"},"mac":"35252658d371ead5aa890b15a6a4cdfde427561208d2c1e84978d107217faa0b"},"id":"f10cdaf9-0f8f-44df-a906-4285f2ba798d","version":3} \ No newline at end of file diff --git a/crates/torii/graphql/src/schema.rs b/crates/torii/graphql/src/schema.rs index 32db9f090a..1d08bfe0f2 100644 --- a/crates/torii/graphql/src/schema.rs +++ b/crates/torii/graphql/src/schema.rs @@ -2,6 +2,7 @@ use anyhow::Result; use async_graphql::dynamic::{ Field, Object, Scalar, Schema, Subscription, SubscriptionField, Union, }; +use convert_case::{Case, Casing}; use sqlx::SqlitePool; use torii_core::types::Model; @@ -126,7 +127,7 @@ async fn build_objects(pool: &SqlitePool) -> Result<(Vec>, let type_mapping = type_mapping_query(&mut conn, &model.id).await?; if !type_mapping.is_empty() { - let field_name = model.name.to_lowercase(); + let field_name = model.name.to_case(Case::Camel); let type_name = model.name; union = union.possible_type(&type_name); diff --git a/crates/torii/graphql/src/tests/models_ordering_test.rs b/crates/torii/graphql/src/tests/models_ordering_test.rs index 3ac52d1ff9..9a93ab39c7 100644 --- a/crates/torii/graphql/src/tests/models_ordering_test.rs +++ b/crates/torii/graphql/src/tests/models_ordering_test.rs @@ -23,7 +23,7 @@ mod tests { createdAt }} }} - pageInfo{{ + pageInfo {{ startCursor hasPreviousPage hasNextPage diff --git a/crates/torii/graphql/src/tests/models_test.rs b/crates/torii/graphql/src/tests/models_test.rs index 75e2b7c07b..cc04ded6d2 100644 --- a/crates/torii/graphql/src/tests/models_test.rs +++ b/crates/torii/graphql/src/tests/models_test.rs @@ -318,6 +318,23 @@ mod tests { let connection: Connection = serde_json::from_value(records).unwrap(); assert_eq!(connection.edges.len(), 0); + let result = run_graphql_query( + &schema, + r#" + { + recordSiblingModels { + edges { + node { + __typename + } + } + } + } + "#, + ) + .await; + assert!(result.get("recordSiblingModels").is_some()); + Ok(()) } } diff --git a/crates/torii/types-test/Scarb.toml b/crates/torii/types-test/Scarb.toml index 261261212c..192864a255 100644 --- a/crates/torii/types-test/Scarb.toml +++ b/crates/torii/types-test/Scarb.toml @@ -21,6 +21,6 @@ build-external-contracts = [ ] # socials.x = "https://twitter.com/dojostarknet" [tool.dojo.env] -account_address = "0x9238c8ca6b3c6ab45a793593b13d98797ccd3bda179d313553e51fee114624" +account_address = "0x6162896d1d7ab204c7ccac6dd5f8e9e7c25ecd5ae4fcb4ad32e57786bb46e03" private_key = "0x1800000000300000180000000000030000000000003006001800006600" rpc_url = "http://localhost:5050/" diff --git a/examples/rpc/starknet/starknet_getClass.hurl b/examples/rpc/starknet/starknet_getClass.hurl index 1d76919b52..38de6935a1 100644 --- a/examples/rpc/starknet/starknet_getClass.hurl +++ b/examples/rpc/starknet/starknet_getClass.hurl @@ -5,7 +5,7 @@ Content-Type: application/json "method": "starknet_getClass", "params": [ "latest", - "0x016c6081eb34ad1e0c5513234ed0c025b3c7f305902d291bad534cd6474c85bc" + "0x05400e90f7e0ae78bd02c77cd75527280470e2fe19c54970dd79dc37a9d3645c" ], "id":1 } diff --git a/examples/rpc/starknet/starknet_getClassAt.hurl b/examples/rpc/starknet/starknet_getClassAt.hurl index fe0a0a4ff0..fe08b17864 100644 --- a/examples/rpc/starknet/starknet_getClassAt.hurl +++ b/examples/rpc/starknet/starknet_getClassAt.hurl @@ -5,7 +5,7 @@ Content-Type: application/json "method": "starknet_getClassAt", "params": [ "latest", - "0x9238c8ca6b3c6ab45a793593b13d98797ccd3bda179d313553e51fee114624" + "0x6162896d1d7ab204c7ccac6dd5f8e9e7c25ecd5ae4fcb4ad32e57786bb46e03" ], "id":1 } diff --git a/examples/rpc/starknet/starknet_getClassHashAt.hurl b/examples/rpc/starknet/starknet_getClassHashAt.hurl index 83238f1469..3df06a3733 100644 --- a/examples/rpc/starknet/starknet_getClassHashAt.hurl +++ b/examples/rpc/starknet/starknet_getClassHashAt.hurl @@ -5,7 +5,7 @@ Content-Type: application/json "method": "starknet_getClassHashAt", "params": [ "pending", - "0x9238c8ca6b3c6ab45a793593b13d98797ccd3bda179d313553e51fee114624" + "0x6162896d1d7ab204c7ccac6dd5f8e9e7c25ecd5ae4fcb4ad32e57786bb46e03" ], "id": 1 } diff --git a/examples/rpc/starknet/starknet_getNonce.hurl b/examples/rpc/starknet/starknet_getNonce.hurl index 57a08672e8..736c1cb15b 100644 --- a/examples/rpc/starknet/starknet_getNonce.hurl +++ b/examples/rpc/starknet/starknet_getNonce.hurl @@ -5,7 +5,7 @@ Content-Type: application/json "method": "starknet_getNonce", "params": [ "latest", - "0x9238c8ca6b3c6ab45a793593b13d98797ccd3bda179d313553e51fee114624" + "0x6162896d1d7ab204c7ccac6dd5f8e9e7c25ecd5ae4fcb4ad32e57786bb46e03" ], "id":1 } diff --git a/examples/spawn-and-move/Scarb.toml b/examples/spawn-and-move/Scarb.toml index 7662632bfb..ecc01f66c9 100644 --- a/examples/spawn-and-move/Scarb.toml +++ b/examples/spawn-and-move/Scarb.toml @@ -23,6 +23,6 @@ name = "example" rpc_url = "http://localhost:5050/" # Default account for katana with seed = 0 -account_address = "0x9238c8ca6b3c6ab45a793593b13d98797ccd3bda179d313553e51fee114624" +account_address = "0x6162896d1d7ab204c7ccac6dd5f8e9e7c25ecd5ae4fcb4ad32e57786bb46e03" private_key = "0x1800000000300000180000000000030000000000003006001800006600" world_address = "0x5010c31f127114c6198df8a5239e2b7a5151e1156fb43791e37e7385faa8138"