diff --git a/crates/sncast/src/starknet_commands/declare.rs b/crates/sncast/src/starknet_commands/declare.rs index 17161d623e..06b4171b9c 100644 --- a/crates/sncast/src/starknet_commands/declare.rs +++ b/crates/sncast/src/starknet_commands/declare.rs @@ -9,11 +9,13 @@ use sncast::helpers::rpc::RpcArgs; use sncast::response::declare::{ AlreadyDeclaredResponse, DeclareResponse, DeclareTransactionResponse, }; -use sncast::response::errors::StarknetCommandError; +use sncast::response::errors::{SNCastProviderError, SNCastStarknetError, StarknetCommandError}; use sncast::{ErrorData, WaitForTx, apply_optional_fields, handle_wait_for_tx}; use starknet::accounts::AccountError::Provider; use starknet::accounts::{ConnectedAccount, DeclarationV3}; -use starknet::core::types::{DeclareTransactionResult, StarknetError}; +use starknet::core::types::{ + ContractExecutionError, DeclareTransactionResult, StarknetError, TransactionExecutionErrorData, +}; use starknet::providers::ProviderError; use starknet::{ accounts::{Account, SingleOwnerAccount}, @@ -157,6 +159,22 @@ pub async fn declare_with_artifacts( class_hash: class_hash.into_(), })) } + Err(Provider(ProviderError::StarknetError(StarknetError::TransactionExecutionError( + TransactionExecutionErrorData { + execution_error: ContractExecutionError::Message(message), + .. + }, + )))) if message.contains("is already declared") => { + if skip_on_already_declared { + Ok(DeclareResponse::AlreadyDeclared(AlreadyDeclaredResponse { + class_hash: class_hash.into_(), + })) + } else { + Err(StarknetCommandError::ProviderError( + SNCastProviderError::StarknetError(SNCastStarknetError::ClassAlreadyDeclared), + )) + } + } Err(Provider(error)) => Err(StarknetCommandError::ProviderError(error.into())), Err(error) => Err(anyhow!(format!("Unexpected error occurred: {error}")).into()), } diff --git a/crates/sncast/tests/e2e/declare.rs b/crates/sncast/tests/e2e/declare.rs index 5ee26948ae..28f478f3fd 100644 --- a/crates/sncast/tests/e2e/declare.rs +++ b/crates/sncast/tests/e2e/declare.rs @@ -315,6 +315,45 @@ async fn test_contract_already_declared() { ); } +#[tokio::test] +async fn test_contract_already_declared_estimate_fee() { + let contract_path = duplicate_contract_directory_with_salt( + CONTRACTS_DIR.to_string() + "/map", + "put", + "74362345", + ); + let tempdir = create_and_deploy_oz_account().await; + join_tempdirs(&contract_path, &tempdir); + + let args = vec![ + "--accounts-file", + "accounts.json", + "--account", + "my_account", + "declare", + "--url", + URL, + "--contract-name", + "Map", + ]; + // Commented out because we explicitly do not want to set any resource bounds. + // Transaction has to go through estimate fee endpoint first because it throws different errors + // than the normal declare endpoint and we want to test them. + + runner(&args).current_dir(tempdir.path()).assert().success(); + + let snapbox = runner(&args).current_dir(tempdir.path()); + let output = snapbox.assert().success(); + + assert_stderr_contains( + output, + indoc! {r" + Command: declare + Error: Contract with the same class hash is already declared + "}, + ); +} + #[tokio::test] async fn test_invalid_nonce() { let contract_path =