diff --git a/README.md b/README.md index 3a391010..76c649f7 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ **Complete Starknet library in Rust[™](https://www.reddit.com/r/rust/comments/12e7tdb/rust_trademark_policy_feedback_form/)** ![starknet-version-v0.13.0](https://img.shields.io/badge/Starknet_Version-v0.13.0-2ea44f?logo=ethereum) -[![jsonrpc-spec-v0.5.1](https://img.shields.io/badge/JSON--RPC-v0.5.1-2ea44f?logo=ethereum)](https://github.com/starkware-libs/starknet-specs/tree/v0.5.1) +[![jsonrpc-spec-v0.6.0](https://img.shields.io/badge/JSON--RPC-v0.6.0-2ea44f?logo=ethereum)](https://github.com/starkware-libs/starknet-specs/tree/v0.6.0) [![linting-badge](https://github.com/xJonathanLEI/starknet-rs/actions/workflows/lint.yaml/badge.svg?branch=master)](https://github.com/xJonathanLEI/starknet-rs/actions/workflows/lint.yaml) [![crates-badge](https://img.shields.io/crates/v/starknet.svg)](https://crates.io/crates/starknet) diff --git a/starknet-accounts/src/account/declaration.rs b/starknet-accounts/src/account/declaration.rs index 283cf3fa..9f39a2ba 100644 --- a/starknet-accounts/src/account/declaration.rs +++ b/starknet-accounts/src/account/declaration.rs @@ -152,7 +152,10 @@ where Some(value) => value, None => { let fee_estimate = self.estimate_fee_with_nonce(nonce).await?; - ((fee_estimate.overall_fee as f64 * self.fee_estimate_multiplier) as u64).into() + ((((TryInto::::try_into(fee_estimate.overall_fee) + .map_err(|_| AccountError::FeeOutOfRange)?) as f64) + * self.fee_estimate_multiplier) as u64) + .into() } }; @@ -186,6 +189,7 @@ where .provider() .estimate_fee_single( BroadcastedTransaction::Declare(BroadcastedDeclareTransaction::V2(declare)), + [], self.account.block_id(), ) .await @@ -339,7 +343,10 @@ where Some(value) => value, None => { let fee_estimate = self.estimate_fee_with_nonce(nonce).await?; - ((fee_estimate.overall_fee as f64 * self.fee_estimate_multiplier) as u64).into() + ((((TryInto::::try_into(fee_estimate.overall_fee) + .map_err(|_| AccountError::FeeOutOfRange)?) as f64) + * self.fee_estimate_multiplier) as u64) + .into() } }; @@ -371,6 +378,7 @@ where .provider() .estimate_fee_single( BroadcastedTransaction::Declare(BroadcastedDeclareTransaction::V1(declare)), + [], self.account.block_id(), ) .await diff --git a/starknet-accounts/src/account/execution.rs b/starknet-accounts/src/account/execution.rs index 8f9f958a..8160b84a 100644 --- a/starknet-accounts/src/account/execution.rs +++ b/starknet-accounts/src/account/execution.rs @@ -7,8 +7,8 @@ use crate::{Call, ExecutionEncoder}; use starknet_core::{ crypto::compute_hash_on_elements, types::{ - BroadcastedInvokeTransaction, BroadcastedTransaction, FeeEstimate, FieldElement, - InvokeTransactionResult, SimulatedTransaction, SimulationFlag, + BroadcastedInvokeTransaction, BroadcastedInvokeTransactionV1, BroadcastedTransaction, + FeeEstimate, FieldElement, InvokeTransactionResult, SimulatedTransaction, SimulationFlag, }, }; use starknet_providers::Provider; @@ -135,7 +135,10 @@ where Some(value) => value, None => { let fee_estimate = self.estimate_fee_with_nonce(nonce).await?; - ((fee_estimate.overall_fee as f64 * self.fee_estimate_multiplier) as u64).into() + ((((TryInto::::try_into(fee_estimate.overall_fee) + .map_err(|_| AccountError::FeeOutOfRange)?) as f64) + * self.fee_estimate_multiplier) as u64) + .into() } }; @@ -170,6 +173,7 @@ where .provider() .estimate_fee_single( BroadcastedTransaction::Invoke(invoke), + [], self.account.block_id(), ) .await @@ -285,13 +289,15 @@ where ) -> Result { let signature = self.account.sign_execution(&self.inner, query_only).await?; - Ok(BroadcastedInvokeTransaction { - max_fee: self.inner.max_fee, - signature, - nonce: self.inner.nonce, - sender_address: self.account.address(), - calldata: self.account.encode_calls(&self.inner.calls), - is_query: query_only, - }) + Ok(BroadcastedInvokeTransaction::V1( + BroadcastedInvokeTransactionV1 { + max_fee: self.inner.max_fee, + signature, + nonce: self.inner.nonce, + sender_address: self.account.address(), + calldata: self.account.encode_calls(&self.inner.calls), + is_query: query_only, + }, + )) } } diff --git a/starknet-accounts/src/account/mod.rs b/starknet-accounts/src/account/mod.rs index 599929e6..3ac2b8a6 100644 --- a/starknet-accounts/src/account/mod.rs +++ b/starknet-accounts/src/account/mod.rs @@ -177,6 +177,8 @@ pub enum AccountError { ClassHashCalculation(ComputeClassHashError), #[error(transparent)] ClassCompression(CompressProgramError), + #[error("fee calculation overflow")] + FeeOutOfRange, } #[cfg_attr(not(target_arch = "wasm32"), async_trait)] diff --git a/starknet-accounts/src/factory/mod.rs b/starknet-accounts/src/factory/mod.rs index 3737be5a..4c88f5d2 100644 --- a/starknet-accounts/src/factory/mod.rs +++ b/starknet-accounts/src/factory/mod.rs @@ -4,7 +4,8 @@ use async_trait::async_trait; use starknet_core::{ crypto::compute_hash_on_elements, types::{ - BlockId, BlockTag, BroadcastedDeployAccountTransaction, BroadcastedTransaction, + BlockId, BlockTag, BroadcastedDeployAccountTransaction, + BroadcastedDeployAccountTransactionV1, BroadcastedTransaction, DeployAccountTransactionResult, FeeEstimate, FieldElement, SimulatedTransaction, SimulationFlag, StarknetError, }, @@ -103,6 +104,8 @@ pub enum AccountFactoryError { Signing(S), #[error(transparent)] Provider(ProviderError), + #[error("fee calculation overflow")] + FeeOutOfRange, } impl<'f, F> AccountDeployment<'f, F> { @@ -237,7 +240,10 @@ where Some(value) => value, None => { let fee_estimate = self.estimate_fee_with_nonce(nonce).await?; - ((fee_estimate.overall_fee as f64 * self.fee_estimate_multiplier) as u64).into() + ((((TryInto::::try_into(fee_estimate.overall_fee) + .map_err(|_| AccountFactoryError::FeeOutOfRange)?) as f64) + * self.fee_estimate_multiplier) as u64) + .into() } }; @@ -272,6 +278,7 @@ where .provider() .estimate_fee_single( BroadcastedTransaction::DeployAccount(deploy), + [], self.factory.block_id(), ) .await @@ -375,16 +382,18 @@ where ) -> Result { let signature = self.factory.sign_deployment(&self.inner).await?; - Ok(BroadcastedDeployAccountTransaction { - max_fee: self.inner.max_fee, - signature, - nonce: self.inner.nonce, - contract_address_salt: self.inner.salt, - constructor_calldata: self.factory.calldata(), - class_hash: self.factory.class_hash(), - // TODO: make use of query version tx for estimating fees - is_query: false, - }) + Ok(BroadcastedDeployAccountTransaction::V1( + BroadcastedDeployAccountTransactionV1 { + max_fee: self.inner.max_fee, + signature, + nonce: self.inner.nonce, + contract_address_salt: self.inner.salt, + constructor_calldata: self.factory.calldata(), + class_hash: self.factory.class_hash(), + // TODO: make use of query version tx for estimating fees + is_query: false, + }, + )) } } diff --git a/starknet-accounts/tests/single_owner_account.rs b/starknet-accounts/tests/single_owner_account.rs index 7cd56941..28d51879 100644 --- a/starknet-accounts/tests/single_owner_account.rs +++ b/starknet-accounts/tests/single_owner_account.rs @@ -25,8 +25,8 @@ fn create_sequencer_client() -> SequencerGatewayProvider { } fn create_jsonrpc_client() -> JsonRpcClient { - let rpc_url = - std::env::var("STARKNET_RPC").unwrap_or("https://rpc-goerli-1.starknet.rs/rpc/v0.5".into()); + let rpc_url = std::env::var("STARKNET_RPC") + .unwrap_or("https://juno.rpc.goerli.starknet.rs/rpc/v0_6".into()); JsonRpcClient::new(HttpTransport::new(url::Url::parse(&rpc_url).unwrap())) } @@ -205,7 +205,7 @@ async fn can_estimate_fee_inner(provider: P, address: .await .unwrap(); - assert!(fee_estimate.overall_fee > 0); + assert!(fee_estimate.overall_fee > FieldElement::ZERO); } async fn can_parse_fee_estimation_error_inner( @@ -248,9 +248,9 @@ async fn can_parse_fee_estimation_error_inner( { Ok(_) => panic!("unexpected successful fee estimation"), Err(AccountError::Provider(ProviderError::StarknetError( - StarknetError::ContractError(err_data), + StarknetError::TransactionExecutionError(err_data), ))) => { - assert!(!err_data.revert_error.is_empty()); + assert!(!err_data.execution_error.is_empty()); } _ => panic!("unexpected error type"), } diff --git a/starknet-contract/tests/contract_deployment.rs b/starknet-contract/tests/contract_deployment.rs index b1543290..427413eb 100644 --- a/starknet-contract/tests/contract_deployment.rs +++ b/starknet-contract/tests/contract_deployment.rs @@ -11,8 +11,8 @@ use url::Url; #[tokio::test] async fn can_deploy_contract_to_alpha_goerli() { - let rpc_url = - std::env::var("STARKNET_RPC").unwrap_or("https://rpc-goerli-1.starknet.rs/rpc/v0.5".into()); + let rpc_url = std::env::var("STARKNET_RPC") + .unwrap_or("https://juno.rpc.goerli.starknet.rs/rpc/v0_6".into()); let provider = JsonRpcClient::new(HttpTransport::new(Url::parse(&rpc_url).unwrap())); let signer = LocalWallet::from(SigningKey::from_secret_scalar( FieldElement::from_hex_be( diff --git a/starknet-core/src/types/codegen.rs b/starknet-core/src/types/codegen.rs index fb2fb69e..dcbf5f3c 100644 --- a/starknet-core/src/types/codegen.rs +++ b/starknet-core/src/types/codegen.rs @@ -3,15 +3,18 @@ // https://github.com/xJonathanLEI/starknet-jsonrpc-codegen // Code generated with version: -// https://github.com/xJonathanLEI/starknet-jsonrpc-codegen#bddc1b829c33b14440d22a85bc937e3d16e32ed1 +// https://github.com/xJonathanLEI/starknet-jsonrpc-codegen#1c8e5c6b5b12771ff714ddfd5978f80d96e067c1 // Code generation requested but not implemented for these types: // - `BLOCK_ID` // - `BROADCASTED_DECLARE_TXN` +// - `BROADCASTED_DEPLOY_ACCOUNT_TXN` +// - `BROADCASTED_INVOKE_TXN` // - `BROADCASTED_TXN` // - `CONTRACT_ABI_ENTRY` // - `CONTRACT_CLASS` // - `DECLARE_TXN` +// - `DEPLOY_ACCOUNT_TXN` // - `EXECUTE_INVOCATION` // - `INVOKE_TXN` // - `PENDING_TXN_RECEIPT` @@ -174,11 +177,42 @@ pub struct BroadcastedDeclareTransactionV2 { pub is_query: bool, } +/// Broadcasted declare transaction v3. +/// +/// Broadcasted declare contract transaction v3. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct BroadcastedDeclareTransactionV3 { + /// The address of the account contract sending the declaration transaction + pub sender_address: FieldElement, + /// The hash of the cairo assembly resulting from the sierra compilation + pub compiled_class_hash: FieldElement, + /// Signature + pub signature: Vec, + /// Nonce + pub nonce: FieldElement, + /// The class to be declared + pub contract_class: OwnedPtr, + /// Resource bounds for the transaction execution + pub resource_bounds: ResourceBoundsMapping, + /// The tip for the transaction + pub tip: u64, + /// Data needed to allow the paymaster to pay for the transaction in native tokens + pub paymaster_data: Vec, + /// Data needed to deploy the account contract from which this tx will be initiated + pub account_deployment_data: Vec, + /// The storage domain of the account's nonce (an account has a nonce per da mode) + pub nonce_data_availability_mode: DataAvailabilityMode, + /// The storage domain of the account's balance from which fee will be charged + pub fee_data_availability_mode: DataAvailabilityMode, + /// If set to `true`, uses a query-only transaction version that's invalid for execution + pub is_query: bool, +} + /// Deploy account transaction. /// /// Deploys an account contract, charges fee from the pre-funded account addresses. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct BroadcastedDeployAccountTransaction { +pub struct BroadcastedDeployAccountTransactionV1 { /// The maximal fee that can be charged for including the transaction pub max_fee: FieldElement, /// Signature @@ -195,11 +229,40 @@ pub struct BroadcastedDeployAccountTransaction { pub is_query: bool, } +/// Deploy account transaction. +/// +/// Deploys an account contract, charges fee from the pre-funded account addresses. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct BroadcastedDeployAccountTransactionV3 { + /// Signature + pub signature: Vec, + /// Nonce + pub nonce: FieldElement, + /// The salt for the address of the deployed contract + pub contract_address_salt: FieldElement, + /// The parameters passed to the constructor + pub constructor_calldata: Vec, + /// The hash of the deployed contract's class + pub class_hash: FieldElement, + /// Resource bounds for the transaction execution + pub resource_bounds: ResourceBoundsMapping, + /// The tip for the transaction + pub tip: u64, + /// Data needed to allow the paymaster to pay for the transaction in native tokens + pub paymaster_data: Vec, + /// The storage domain of the account's nonce (an account has a nonce per da mode) + pub nonce_data_availability_mode: DataAvailabilityMode, + /// The storage domain of the account's balance from which fee will be charged + pub fee_data_availability_mode: DataAvailabilityMode, + /// If set to `true`, uses a query-only transaction version that's invalid for execution + pub is_query: bool, +} + /// Invoke transaction v1. /// /// Initiates a transaction from a given account. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct BroadcastedInvokeTransaction { +pub struct BroadcastedInvokeTransactionV1 { /// Sender address pub sender_address: FieldElement, /// The data expected by the account's `execute` function (in most usecases, this includes the @@ -215,19 +278,49 @@ pub struct BroadcastedInvokeTransaction { pub is_query: bool, } +/// Invoke transaction v3. +/// +/// Initiates a transaction from a given account. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct BroadcastedInvokeTransactionV3 { + /// Sender address + pub sender_address: FieldElement, + /// The data expected by the account's `execute` function (in most usecases, this includes the + /// called contract address and a function selector) + pub calldata: Vec, + /// Signature + pub signature: Vec, + /// Nonce + pub nonce: FieldElement, + /// Resource bounds for the transaction execution + pub resource_bounds: ResourceBoundsMapping, + /// The tip for the transaction + pub tip: u64, + /// Data needed to allow the paymaster to pay for the transaction in native tokens + pub paymaster_data: Vec, + /// Data needed to deploy the account contract from which this tx will be initiated + pub account_deployment_data: Vec, + /// The storage domain of the account's nonce (an account has a nonce per da mode) + pub nonce_data_availability_mode: DataAvailabilityMode, + /// The storage domain of the account's balance from which fee will be charged + pub fee_data_availability_mode: DataAvailabilityMode, + /// If set to `true`, uses a query-only transaction version that's invalid for execution + pub is_query: bool, +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum CallType { - #[serde(rename = "DELEGATE")] - Delegate, #[serde(rename = "LIBRARY_CALL")] LibraryCall, #[serde(rename = "CALL")] Call, + #[serde(rename = "DELEGATE")] + Delegate, } /// Deprecated contract class. /// -/// The definition of a legacy (cairo 0) Starknet contract class. +/// The definition of a Starknet contract class. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct CompressedLegacyContractClass { @@ -279,7 +372,7 @@ pub struct DeclareTransactionReceipt { /// The hash identifying the transaction pub transaction_hash: FieldElement, /// The fee that was charged by the sequencer - pub actual_fee: FieldElement, + pub actual_fee: FeePayment, /// Finality status pub finality_status: TransactionFinalityStatus, /// Block hash @@ -362,6 +455,37 @@ pub struct DeclareTransactionV2 { pub class_hash: FieldElement, } +/// Declare transaction v3. +/// +/// Declare contract transaction v3. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct DeclareTransactionV3 { + /// Transaction hash + pub transaction_hash: FieldElement, + /// The address of the account contract sending the declaration transaction + pub sender_address: FieldElement, + /// The hash of the cairo assembly resulting from the sierra compilation + pub compiled_class_hash: FieldElement, + /// Signature + pub signature: Vec, + /// Nonce + pub nonce: FieldElement, + /// The hash of the declared class + pub class_hash: FieldElement, + /// Resource bounds for the transaction execution + pub resource_bounds: ResourceBoundsMapping, + /// The tip for the transaction + pub tip: u64, + /// Data needed to allow the paymaster to pay for the transaction in native tokens + pub paymaster_data: Vec, + /// Data needed to deploy the account contract from which this tx will be initiated + pub account_deployment_data: Vec, + /// The storage domain of the account's nonce (an account has a nonce per da mode) + pub nonce_data_availability_mode: DataAvailabilityMode, + /// The storage domain of the account's balance from which fee will be charged + pub fee_data_availability_mode: DataAvailabilityMode, +} + /// New classes. /// /// The declared class hash and compiled class hash. @@ -377,34 +501,13 @@ pub struct DeclaredClassItem { pub compiled_class_hash: FieldElement, } -/// Deploy account transaction. -/// -/// Deploys an account contract, charges fee from the pre-funded account addresses. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct DeployAccountTransaction { - /// Transaction hash - pub transaction_hash: FieldElement, - /// The maximal fee that can be charged for including the transaction - pub max_fee: FieldElement, - /// Signature - pub signature: Vec, - /// Nonce - pub nonce: FieldElement, - /// The salt for the address of the deployed contract - pub contract_address_salt: FieldElement, - /// The parameters passed to the constructor - pub constructor_calldata: Vec, - /// The hash of the deployed contract's class - pub class_hash: FieldElement, -} - /// Deploy account transaction receipt. #[derive(Debug, Clone, PartialEq, Eq)] pub struct DeployAccountTransactionReceipt { /// The hash identifying the transaction pub transaction_hash: FieldElement, /// The fee that was charged by the sequencer - pub actual_fee: FieldElement, + pub actual_fee: FeePayment, /// Finality status pub finality_status: TransactionFinalityStatus, /// Block hash @@ -435,6 +538,56 @@ pub struct DeployAccountTransactionTrace { pub state_diff: Option, } +/// Deploy account transaction. +/// +/// Deploys an account contract, charges fee from the pre-funded account addresses. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct DeployAccountTransactionV1 { + /// Transaction hash + pub transaction_hash: FieldElement, + /// The maximal fee that can be charged for including the transaction + pub max_fee: FieldElement, + /// Signature + pub signature: Vec, + /// Nonce + pub nonce: FieldElement, + /// The salt for the address of the deployed contract + pub contract_address_salt: FieldElement, + /// The parameters passed to the constructor + pub constructor_calldata: Vec, + /// The hash of the deployed contract's class + pub class_hash: FieldElement, +} + +/// Deploy account transaction. +/// +/// Deploys an account contract, charges fee from the pre-funded account addresses. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct DeployAccountTransactionV3 { + /// Transaction hash + pub transaction_hash: FieldElement, + /// Signature + pub signature: Vec, + /// Nonce + pub nonce: FieldElement, + /// The salt for the address of the deployed contract + pub contract_address_salt: FieldElement, + /// The parameters passed to the constructor + pub constructor_calldata: Vec, + /// The hash of the deployed contract's class + pub class_hash: FieldElement, + /// Resource bounds for the transaction execution + pub resource_bounds: ResourceBoundsMapping, + /// The tip for the transaction + pub tip: u64, + /// Data needed to allow the paymaster to pay for the transaction in native tokens + pub paymaster_data: Vec, + /// The storage domain of the account's nonce (an account has a nonce per da mode) + pub nonce_data_availability_mode: DataAvailabilityMode, + /// The storage domain of the account's balance from which fee will be charged + pub fee_data_availability_mode: DataAvailabilityMode, +} + /// Deploy contract transaction. /// /// The structure of a deploy transaction. Note that this transaction type is deprecated and will no @@ -444,7 +597,7 @@ pub struct DeployTransaction { /// Transaction hash pub transaction_hash: FieldElement, /// Version of the transaction scheme - pub version: u64, + pub version: FieldElement, /// The salt for the address of the deployed contract pub contract_address_salt: FieldElement, /// The parameters passed to the constructor @@ -459,7 +612,7 @@ pub struct DeployTransactionReceipt { /// The hash identifying the transaction pub transaction_hash: FieldElement, /// The fee that was charged by the sequencer - pub actual_fee: FieldElement, + pub actual_fee: FeePayment, /// Finality status pub finality_status: TransactionFinalityStatus, /// Block hash @@ -509,10 +662,12 @@ pub struct EmittedEvent { #[serde_as(as = "Vec")] pub data: Vec, /// The hash of the block in which the event was emitted - #[serde_as(as = "UfeHex")] - pub block_hash: FieldElement, + #[serde(skip_serializing_if = "Option::is_none")] + #[serde_as(as = "Option")] + pub block_hash: Option, /// The number of the block in which the event was emitted - pub block_number: u64, + #[serde(skip_serializing_if = "Option::is_none")] + pub block_number: Option, /// The transaction that emitted the event #[serde_as(as = "UfeHex")] pub transaction_hash: FieldElement, @@ -608,39 +763,39 @@ pub struct EventsChunk { /// Execution resources. /// -/// The resources consumed by the transaction. -#[serde_as] +/// The resources consumed by the vm. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct ExecutionResources { /// The number of cairo steps used - #[serde_as(as = "NumAsHex")] pub steps: u64, /// The number of unused memory cells (each cell is roughly equivalent to a step) #[serde(skip_serializing_if = "Option::is_none")] - #[serde_as(as = "Option")] pub memory_holes: Option, /// The number of range_check builtin instances - #[serde_as(as = "NumAsHex")] - pub range_check_builtin_applications: u64, + #[serde(skip_serializing_if = "Option::is_none")] + pub range_check_builtin_applications: Option, /// The number of pedersen builtin instances - #[serde_as(as = "NumAsHex")] - pub pedersen_builtin_applications: u64, + #[serde(skip_serializing_if = "Option::is_none")] + pub pedersen_builtin_applications: Option, /// The number of poseidon builtin instances - #[serde_as(as = "NumAsHex")] - pub poseidon_builtin_applications: u64, + #[serde(skip_serializing_if = "Option::is_none")] + pub poseidon_builtin_applications: Option, /// The number of ec_op builtin instances - #[serde_as(as = "NumAsHex")] - pub ec_op_builtin_applications: u64, + #[serde(skip_serializing_if = "Option::is_none")] + pub ec_op_builtin_applications: Option, /// The number of ecdsa builtin instances - #[serde_as(as = "NumAsHex")] - pub ecdsa_builtin_applications: u64, + #[serde(skip_serializing_if = "Option::is_none")] + pub ecdsa_builtin_applications: Option, /// The number of bitwise builtin instances - #[serde_as(as = "NumAsHex")] - pub bitwise_builtin_applications: u64, + #[serde(skip_serializing_if = "Option::is_none")] + pub bitwise_builtin_applications: Option, /// The number of keccak builtin instances - #[serde_as(as = "NumAsHex")] - pub keccak_builtin_applications: u64, + #[serde(skip_serializing_if = "Option::is_none")] + pub keccak_builtin_applications: Option, + /// The number of accesses to the segment arena + #[serde(skip_serializing_if = "Option::is_none")] + pub segment_arena_builtin: Option, } /// Fee estimation. @@ -650,14 +805,32 @@ pub struct ExecutionResources { pub struct FeeEstimate { /// The Ethereum gas cost of the transaction (see /// https://docs.starknet.io/docs/fees/fee-mechanism for more info) - #[serde_as(as = "NumAsHex")] - pub gas_consumed: u64, - /// The gas price (in gwei) that was used in the cost estimation - #[serde_as(as = "NumAsHex")] - pub gas_price: u64, - /// The estimated fee for the transaction (in gwei), product of gas_consumed and gas_price - #[serde_as(as = "NumAsHex")] - pub overall_fee: u64, + #[serde_as(as = "UfeHex")] + pub gas_consumed: FieldElement, + /// The gas price (in gwei or fri, depending on the tx version) that was used in the cost + /// estimation + #[serde_as(as = "UfeHex")] + pub gas_price: FieldElement, + /// The estimated fee for the transaction (in gwei or fri, depending on the tx version), product + /// of gas_consumed and gas_price + #[serde_as(as = "UfeHex")] + pub overall_fee: FieldElement, + /// Units in which the fee is given + pub unit: PriceUnit, +} + +/// Fee payment. +/// +/// Fee payment info as it appears in receipts. +#[serde_as] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] +pub struct FeePayment { + /// Amount paid + #[serde_as(as = "UfeHex")] + pub amount: FieldElement, + /// Units in which the fee is given + pub unit: PriceUnit, } /// The definition of a sierra Starknet contract class. @@ -724,6 +897,8 @@ pub struct FunctionInvocation { pub events: Vec, /// The messages sent by this invocation to L1 pub messages: Vec, + /// Resources consumed by the internal call + pub execution_resources: ExecutionResources, } /// Function state mutability type. @@ -739,7 +914,7 @@ pub struct InvokeTransactionReceipt { /// The hash identifying the transaction pub transaction_hash: FieldElement, /// The fee that was charged by the sequencer - pub actual_fee: FieldElement, + pub actual_fee: FeePayment, /// Finality status pub finality_status: TransactionFinalityStatus, /// Block hash @@ -805,13 +980,43 @@ pub struct InvokeTransactionV1 { pub nonce: FieldElement, } +/// Invoke transaction v3. +/// +/// Initiates a transaction from a given account. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InvokeTransactionV3 { + /// Transaction hash + pub transaction_hash: FieldElement, + /// Sender address + pub sender_address: FieldElement, + /// The data expected by the account's `execute` function (in most usecases, this includes the + /// called contract address and a function selector) + pub calldata: Vec, + /// Signature + pub signature: Vec, + /// Nonce + pub nonce: FieldElement, + /// Resource bounds for the transaction execution + pub resource_bounds: ResourceBoundsMapping, + /// The tip for the transaction + pub tip: u64, + /// Data needed to allow the paymaster to pay for the transaction in native tokens + pub paymaster_data: Vec, + /// Data needed to deploy the account contract from which this tx will be initiated + pub account_deployment_data: Vec, + /// The storage domain of the account's nonce (an account has a nonce per da mode) + pub nonce_data_availability_mode: DataAvailabilityMode, + /// The storage domain of the account's balance from which fee will be charged + pub fee_data_availability_mode: DataAvailabilityMode, +} + /// L1 handler transaction. #[derive(Debug, Clone, PartialEq, Eq)] pub struct L1HandlerTransaction { /// Transaction hash pub transaction_hash: FieldElement, /// Version of the transaction scheme - pub version: u64, + pub version: FieldElement, /// The L1->L2 message nonce field of the sn core L1 contract at the time the transaction was /// sent pub nonce: u64, @@ -833,7 +1038,7 @@ pub struct L1HandlerTransactionReceipt { /// The hash identifying the transaction pub transaction_hash: FieldElement, /// The fee that was charged by the sequencer - pub actual_fee: FieldElement, + pub actual_fee: FeePayment, /// Finality status pub finality_status: TransactionFinalityStatus, /// Block hash @@ -1130,7 +1335,7 @@ pub struct PendingDeclareTransactionReceipt { /// The hash identifying the transaction pub transaction_hash: FieldElement, /// The fee that was charged by the sequencer - pub actual_fee: FieldElement, + pub actual_fee: FeePayment, /// Messages sent pub messages_sent: Vec, /// The events emitted as part of this transaction @@ -1147,7 +1352,7 @@ pub struct PendingDeployAccountTransactionReceipt { /// The hash identifying the transaction pub transaction_hash: FieldElement, /// The fee that was charged by the sequencer - pub actual_fee: FieldElement, + pub actual_fee: FeePayment, /// Messages sent pub messages_sent: Vec, /// The events emitted as part of this transaction @@ -1166,7 +1371,7 @@ pub struct PendingInvokeTransactionReceipt { /// The hash identifying the transaction pub transaction_hash: FieldElement, /// The fee that was charged by the sequencer - pub actual_fee: FieldElement, + pub actual_fee: FeePayment, /// Messages sent pub messages_sent: Vec, /// The events emitted as part of this transaction @@ -1187,7 +1392,7 @@ pub struct PendingL1HandlerTransactionReceipt { /// The hash identifying the transaction pub transaction_hash: FieldElement, /// The fee that was charged by the sequencer - pub actual_fee: FieldElement, + pub actual_fee: FeePayment, /// Messages sent pub messages_sent: Vec, /// The events emitted as part of this transaction @@ -1212,6 +1417,15 @@ pub struct PendingStateUpdate { pub state_diff: StateDiff, } +/// Price unit. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum PriceUnit { + #[serde(rename = "WEI")] + Wei, + #[serde(rename = "FRI")] + Fri, +} + /// Replaced class. /// /// The list of contracts whose class was replaced. @@ -1230,26 +1444,34 @@ pub struct ReplacedClassItem { #[serde_as] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] -pub struct ResourceLimits { +pub struct ResourceBounds { /// The max amount of the resource that can be used in the tx #[serde_as(as = "NumAsHex")] pub max_amount: u64, /// The max price per unit of this resource for this tx #[serde_as(as = "NumAsHex")] - pub max_price_per_unit: u64, + pub max_price_per_unit: u128, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] +pub struct ResourceBoundsMapping { + /// The max amount and max price per unit of L1 gas used in this tx + pub l1_gas: ResourceBounds, + /// The max amount and max price per unit of L2 gas used in this tx + pub l2_gas: ResourceBounds, } #[serde_as] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct ResourcePrice { - /// The price of one unit of the given resource, denominated in strk - #[serde(skip_serializing_if = "Option::is_none")] - #[serde_as(as = "Option")] - pub price_in_strk: Option, + /// The price of one unit of the given resource, denominated in fri (10^-18 strk) + #[serde_as(as = "UfeHex")] + pub price_in_fri: FieldElement, /// The price of one unit of the given resource, denominated in wei - #[serde_as(as = "NumAsHex")] - pub price_in_wei: u64, + #[serde_as(as = "UfeHex")] + pub price_in_wei: FieldElement, } /// Result page request. @@ -1320,6 +1542,14 @@ pub enum SimulationFlag { SkipFeeCharge, } +/// Flags that indicate how to simulate a given transaction. By default, the sequencer behavior is +/// replicated locally. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum SimulationFlagForEstimateFee { + #[serde(rename = "SKIP_VALIDATE")] + SkipValidate, +} + /// JSON-RPC error codes #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum StarknetError { @@ -1345,6 +1575,8 @@ pub enum StarknetError { TooManyKeysInFilter, /// Contract error ContractError(ContractErrorData), + /// Transaction execution error + TransactionExecutionError(TransactionExecutionErrorData), /// Class already declared ClassAlreadyDeclared, /// Invalid transaction nonce @@ -1354,7 +1586,7 @@ pub enum StarknetError { /// Account balance is smaller than the transaction's max_fee InsufficientAccountBalance, /// Account validation failed - ValidationFailure, + ValidationFailure(String), /// Compilation failed CompilationFailed, /// Contract class size it too large @@ -1373,8 +1605,6 @@ pub enum StarknetError { UnexpectedError(String), /// No trace available for transaction NoTraceAvailable(NoTraceAvailableErrorData), - /// Invalid transaction hash - InvalidTransactionHash, } #[cfg(feature = "std")] @@ -1394,11 +1624,12 @@ impl core::fmt::Display for StarknetError { Self::InvalidContinuationToken => write!(f, "InvalidContinuationToken"), Self::TooManyKeysInFilter => write!(f, "TooManyKeysInFilter"), Self::ContractError(_) => write!(f, "ContractError"), + Self::TransactionExecutionError(_) => write!(f, "TransactionExecutionError"), Self::ClassAlreadyDeclared => write!(f, "ClassAlreadyDeclared"), Self::InvalidTransactionNonce => write!(f, "InvalidTransactionNonce"), Self::InsufficientMaxFee => write!(f, "InsufficientMaxFee"), Self::InsufficientAccountBalance => write!(f, "InsufficientAccountBalance"), - Self::ValidationFailure => write!(f, "ValidationFailure"), + Self::ValidationFailure(_) => write!(f, "ValidationFailure"), Self::CompilationFailed => write!(f, "CompilationFailed"), Self::ContractClassSizeIsTooLarge => write!(f, "ContractClassSizeIsTooLarge"), Self::NonAccount => write!(f, "NonAccount"), @@ -1408,7 +1639,6 @@ impl core::fmt::Display for StarknetError { Self::UnsupportedContractClassVersion => write!(f, "UnsupportedContractClassVersion"), Self::UnexpectedError(_) => write!(f, "UnexpectedError"), Self::NoTraceAvailable(_) => write!(f, "NoTraceAvailable"), - Self::InvalidTransactionHash => write!(f, "InvalidTransactionHash"), } } } @@ -1427,11 +1657,12 @@ impl StarknetError { Self::InvalidContinuationToken => "The supplied continuation token is invalid or unknown", Self::TooManyKeysInFilter => "Too many keys provided in a filter", Self::ContractError(_) => "Contract error", + Self::TransactionExecutionError(_) => "Transaction execution error", Self::ClassAlreadyDeclared => "Class already declared", Self::InvalidTransactionNonce => "Invalid transaction nonce", Self::InsufficientMaxFee => "Max fee is smaller than the minimal transaction cost (validation plus fee transfer)", Self::InsufficientAccountBalance => "Account balance is smaller than the transaction's max_fee", - Self::ValidationFailure => "Account validation failed", + Self::ValidationFailure(_) => "Account validation failed", Self::CompilationFailed => "Compilation failed", Self::ContractClassSizeIsTooLarge => "Contract class size it too large", Self::NonAccount => "Sender address in not an account contract", @@ -1441,7 +1672,6 @@ impl StarknetError { Self::UnsupportedContractClassVersion => "the contract class version is not supported", Self::UnexpectedError(_) => "An unexpected error occurred", Self::NoTraceAvailable(_) => "No trace available for transaction", - Self::InvalidTransactionHash => "Invalid transaction hash", } } } @@ -1522,6 +1752,16 @@ pub struct SyncStatus { pub highest_block_num: u64, } +/// More data about the execution failure. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] +pub struct TransactionExecutionErrorData { + /// The index of the first transaction failing in a sequence of given transactions + pub transaction_index: u64, + /// A string encoding the execution trace up to the point of failure + pub execution_error: String, +} + /// Execution status. /// /// The execution status of the transaction. @@ -1625,6 +1865,8 @@ pub struct ChainIdRequest; #[derive(Debug, Clone, PartialEq, Eq)] pub struct EstimateFeeRequest { pub request: Vec, + /// describes what parts of the transaction should be executed + pub simulation_flags: Vec, /// The hash of the requested block, or number (height) of the requested block, or a block tag, /// for the block referencing the state or call the transaction on. pub block_id: BlockId, @@ -1634,6 +1876,7 @@ pub struct EstimateFeeRequest { #[derive(Debug, Clone, PartialEq, Eq)] pub struct EstimateFeeRequestRef<'a> { pub request: &'a [BroadcastedTransaction], + pub simulation_flags: &'a [SimulationFlagForEstimateFee], pub block_id: &'a BlockId, } @@ -2087,52 +2330,63 @@ impl<'de> Deserialize<'de> for BroadcastedDeclareTransactionV2 { } } -impl Serialize for BroadcastedDeployAccountTransaction { +impl Serialize for BroadcastedDeclareTransactionV3 { fn serialize(&self, serializer: S) -> Result { #[serde_as] #[derive(Serialize)] struct Tagged<'a> { pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub max_fee: &'a FieldElement, + pub sender_address: &'a FieldElement, + #[serde_as(as = "UfeHex")] + pub compiled_class_hash: &'a FieldElement, #[serde_as(as = "UfeHex")] pub version: &'a FieldElement, #[serde_as(as = "[UfeHex]")] pub signature: &'a [FieldElement], #[serde_as(as = "UfeHex")] pub nonce: &'a FieldElement, - #[serde_as(as = "UfeHex")] - pub contract_address_salt: &'a FieldElement, + pub contract_class: &'a FlattenedSierraClass, + pub resource_bounds: &'a ResourceBoundsMapping, + #[serde_as(as = "NumAsHex")] + pub tip: &'a u64, #[serde_as(as = "[UfeHex]")] - pub constructor_calldata: &'a [FieldElement], - #[serde_as(as = "UfeHex")] - pub class_hash: &'a FieldElement, + pub paymaster_data: &'a [FieldElement], + #[serde_as(as = "[UfeHex]")] + pub account_deployment_data: &'a [FieldElement], + pub nonce_data_availability_mode: &'a DataAvailabilityMode, + pub fee_data_availability_mode: &'a DataAvailabilityMode, } - let r#type = "DEPLOY_ACCOUNT"; + let r#type = "DECLARE"; let version = &(if self.is_query { - FieldElement::ONE + QUERY_VERSION_OFFSET + FieldElement::THREE + QUERY_VERSION_OFFSET } else { - FieldElement::ONE + FieldElement::THREE }); let tagged = Tagged { r#type, - max_fee: &self.max_fee, + sender_address: &self.sender_address, + compiled_class_hash: &self.compiled_class_hash, version, signature: &self.signature, nonce: &self.nonce, - contract_address_salt: &self.contract_address_salt, - constructor_calldata: &self.constructor_calldata, - class_hash: &self.class_hash, + contract_class: &self.contract_class, + resource_bounds: &self.resource_bounds, + tip: &self.tip, + paymaster_data: &self.paymaster_data, + account_deployment_data: &self.account_deployment_data, + nonce_data_availability_mode: &self.nonce_data_availability_mode, + fee_data_availability_mode: &self.fee_data_availability_mode, }; Tagged::serialize(&tagged, serializer) } } -impl<'de> Deserialize<'de> for BroadcastedDeployAccountTransaction { +impl<'de> Deserialize<'de> for BroadcastedDeclareTransactionV3 { fn deserialize>(deserializer: D) -> Result { #[serde_as] #[derive(Deserialize)] @@ -2140,60 +2394,67 @@ impl<'de> Deserialize<'de> for BroadcastedDeployAccountTransaction { struct Tagged { pub r#type: Option, #[serde_as(as = "UfeHex")] - pub max_fee: FieldElement, + pub sender_address: FieldElement, + #[serde_as(as = "UfeHex")] + pub compiled_class_hash: FieldElement, #[serde_as(as = "UfeHex")] pub version: FieldElement, #[serde_as(as = "Vec")] pub signature: Vec, #[serde_as(as = "UfeHex")] pub nonce: FieldElement, - #[serde_as(as = "UfeHex")] - pub contract_address_salt: FieldElement, + pub contract_class: FlattenedSierraClass, + pub resource_bounds: ResourceBoundsMapping, + #[serde_as(as = "NumAsHex")] + pub tip: u64, #[serde_as(as = "Vec")] - pub constructor_calldata: Vec, - #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub paymaster_data: Vec, + #[serde_as(as = "Vec")] + pub account_deployment_data: Vec, + pub nonce_data_availability_mode: DataAvailabilityMode, + pub fee_data_availability_mode: DataAvailabilityMode, } let tagged = Tagged::deserialize(deserializer)?; if let Some(tag_field) = &tagged.r#type { - if tag_field != "DEPLOY_ACCOUNT" { + if tag_field != "DECLARE" { return Err(serde::de::Error::custom("invalid `type` value")); } } - let is_query = if tagged.version == FieldElement::ONE { + let is_query = if tagged.version == FieldElement::THREE { false - } else if tagged.version == FieldElement::ONE + QUERY_VERSION_OFFSET { + } else if tagged.version == FieldElement::THREE + QUERY_VERSION_OFFSET { true } else { return Err(serde::de::Error::custom("invalid `version` value")); }; Ok(Self { - max_fee: tagged.max_fee, + sender_address: tagged.sender_address, + compiled_class_hash: tagged.compiled_class_hash, signature: tagged.signature, nonce: tagged.nonce, - contract_address_salt: tagged.contract_address_salt, - constructor_calldata: tagged.constructor_calldata, - class_hash: tagged.class_hash, + contract_class: OwnedPtr::new(tagged.contract_class), + resource_bounds: tagged.resource_bounds, + tip: tagged.tip, + paymaster_data: tagged.paymaster_data, + account_deployment_data: tagged.account_deployment_data, + nonce_data_availability_mode: tagged.nonce_data_availability_mode, + fee_data_availability_mode: tagged.fee_data_availability_mode, is_query, }) } } -impl Serialize for BroadcastedInvokeTransaction { +impl Serialize for BroadcastedDeployAccountTransactionV1 { fn serialize(&self, serializer: S) -> Result { #[serde_as] #[derive(Serialize)] struct Tagged<'a> { pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub sender_address: &'a FieldElement, - #[serde_as(as = "[UfeHex]")] - pub calldata: &'a [FieldElement], - #[serde_as(as = "UfeHex")] pub max_fee: &'a FieldElement, #[serde_as(as = "UfeHex")] pub version: &'a FieldElement, @@ -2201,7 +2462,221 @@ impl Serialize for BroadcastedInvokeTransaction { pub signature: &'a [FieldElement], #[serde_as(as = "UfeHex")] pub nonce: &'a FieldElement, - } + #[serde_as(as = "UfeHex")] + pub contract_address_salt: &'a FieldElement, + #[serde_as(as = "[UfeHex]")] + pub constructor_calldata: &'a [FieldElement], + #[serde_as(as = "UfeHex")] + pub class_hash: &'a FieldElement, + } + + let r#type = "DEPLOY_ACCOUNT"; + + let version = &(if self.is_query { + FieldElement::ONE + QUERY_VERSION_OFFSET + } else { + FieldElement::ONE + }); + + let tagged = Tagged { + r#type, + max_fee: &self.max_fee, + version, + signature: &self.signature, + nonce: &self.nonce, + contract_address_salt: &self.contract_address_salt, + constructor_calldata: &self.constructor_calldata, + class_hash: &self.class_hash, + }; + + Tagged::serialize(&tagged, serializer) + } +} + +impl<'de> Deserialize<'de> for BroadcastedDeployAccountTransactionV1 { + fn deserialize>(deserializer: D) -> Result { + #[serde_as] + #[derive(Deserialize)] + #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] + struct Tagged { + pub r#type: Option, + #[serde_as(as = "UfeHex")] + pub max_fee: FieldElement, + #[serde_as(as = "UfeHex")] + pub version: FieldElement, + #[serde_as(as = "Vec")] + pub signature: Vec, + #[serde_as(as = "UfeHex")] + pub nonce: FieldElement, + #[serde_as(as = "UfeHex")] + pub contract_address_salt: FieldElement, + #[serde_as(as = "Vec")] + pub constructor_calldata: Vec, + #[serde_as(as = "UfeHex")] + pub class_hash: FieldElement, + } + + let tagged = Tagged::deserialize(deserializer)?; + + if let Some(tag_field) = &tagged.r#type { + if tag_field != "DEPLOY_ACCOUNT" { + return Err(serde::de::Error::custom("invalid `type` value")); + } + } + + let is_query = if tagged.version == FieldElement::ONE { + false + } else if tagged.version == FieldElement::ONE + QUERY_VERSION_OFFSET { + true + } else { + return Err(serde::de::Error::custom("invalid `version` value")); + }; + + Ok(Self { + max_fee: tagged.max_fee, + signature: tagged.signature, + nonce: tagged.nonce, + contract_address_salt: tagged.contract_address_salt, + constructor_calldata: tagged.constructor_calldata, + class_hash: tagged.class_hash, + is_query, + }) + } +} + +impl Serialize for BroadcastedDeployAccountTransactionV3 { + fn serialize(&self, serializer: S) -> Result { + #[serde_as] + #[derive(Serialize)] + struct Tagged<'a> { + pub r#type: &'a str, + #[serde_as(as = "UfeHex")] + pub version: &'a FieldElement, + #[serde_as(as = "[UfeHex]")] + pub signature: &'a [FieldElement], + #[serde_as(as = "UfeHex")] + pub nonce: &'a FieldElement, + #[serde_as(as = "UfeHex")] + pub contract_address_salt: &'a FieldElement, + #[serde_as(as = "[UfeHex]")] + pub constructor_calldata: &'a [FieldElement], + #[serde_as(as = "UfeHex")] + pub class_hash: &'a FieldElement, + pub resource_bounds: &'a ResourceBoundsMapping, + #[serde_as(as = "NumAsHex")] + pub tip: &'a u64, + #[serde_as(as = "[UfeHex]")] + pub paymaster_data: &'a [FieldElement], + pub nonce_data_availability_mode: &'a DataAvailabilityMode, + pub fee_data_availability_mode: &'a DataAvailabilityMode, + } + + let r#type = "DEPLOY_ACCOUNT"; + + let version = &(if self.is_query { + FieldElement::THREE + QUERY_VERSION_OFFSET + } else { + FieldElement::THREE + }); + + let tagged = Tagged { + r#type, + version, + signature: &self.signature, + nonce: &self.nonce, + contract_address_salt: &self.contract_address_salt, + constructor_calldata: &self.constructor_calldata, + class_hash: &self.class_hash, + resource_bounds: &self.resource_bounds, + tip: &self.tip, + paymaster_data: &self.paymaster_data, + nonce_data_availability_mode: &self.nonce_data_availability_mode, + fee_data_availability_mode: &self.fee_data_availability_mode, + }; + + Tagged::serialize(&tagged, serializer) + } +} + +impl<'de> Deserialize<'de> for BroadcastedDeployAccountTransactionV3 { + fn deserialize>(deserializer: D) -> Result { + #[serde_as] + #[derive(Deserialize)] + #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] + struct Tagged { + pub r#type: Option, + #[serde_as(as = "UfeHex")] + pub version: FieldElement, + #[serde_as(as = "Vec")] + pub signature: Vec, + #[serde_as(as = "UfeHex")] + pub nonce: FieldElement, + #[serde_as(as = "UfeHex")] + pub contract_address_salt: FieldElement, + #[serde_as(as = "Vec")] + pub constructor_calldata: Vec, + #[serde_as(as = "UfeHex")] + pub class_hash: FieldElement, + pub resource_bounds: ResourceBoundsMapping, + #[serde_as(as = "NumAsHex")] + pub tip: u64, + #[serde_as(as = "Vec")] + pub paymaster_data: Vec, + pub nonce_data_availability_mode: DataAvailabilityMode, + pub fee_data_availability_mode: DataAvailabilityMode, + } + + let tagged = Tagged::deserialize(deserializer)?; + + if let Some(tag_field) = &tagged.r#type { + if tag_field != "DEPLOY_ACCOUNT" { + return Err(serde::de::Error::custom("invalid `type` value")); + } + } + + let is_query = if tagged.version == FieldElement::THREE { + false + } else if tagged.version == FieldElement::THREE + QUERY_VERSION_OFFSET { + true + } else { + return Err(serde::de::Error::custom("invalid `version` value")); + }; + + Ok(Self { + signature: tagged.signature, + nonce: tagged.nonce, + contract_address_salt: tagged.contract_address_salt, + constructor_calldata: tagged.constructor_calldata, + class_hash: tagged.class_hash, + resource_bounds: tagged.resource_bounds, + tip: tagged.tip, + paymaster_data: tagged.paymaster_data, + nonce_data_availability_mode: tagged.nonce_data_availability_mode, + fee_data_availability_mode: tagged.fee_data_availability_mode, + is_query, + }) + } +} + +impl Serialize for BroadcastedInvokeTransactionV1 { + fn serialize(&self, serializer: S) -> Result { + #[serde_as] + #[derive(Serialize)] + struct Tagged<'a> { + pub r#type: &'a str, + #[serde_as(as = "UfeHex")] + pub sender_address: &'a FieldElement, + #[serde_as(as = "[UfeHex]")] + pub calldata: &'a [FieldElement], + #[serde_as(as = "UfeHex")] + pub max_fee: &'a FieldElement, + #[serde_as(as = "UfeHex")] + pub version: &'a FieldElement, + #[serde_as(as = "[UfeHex]")] + pub signature: &'a [FieldElement], + #[serde_as(as = "UfeHex")] + pub nonce: &'a FieldElement, + } let r#type = "INVOKE"; @@ -2225,7 +2700,7 @@ impl Serialize for BroadcastedInvokeTransaction { } } -impl<'de> Deserialize<'de> for BroadcastedInvokeTransaction { +impl<'de> Deserialize<'de> for BroadcastedInvokeTransactionV1 { fn deserialize>(deserializer: D) -> Result { #[serde_as] #[derive(Deserialize)] @@ -2273,6 +2748,120 @@ impl<'de> Deserialize<'de> for BroadcastedInvokeTransaction { } } +impl Serialize for BroadcastedInvokeTransactionV3 { + fn serialize(&self, serializer: S) -> Result { + #[serde_as] + #[derive(Serialize)] + struct Tagged<'a> { + pub r#type: &'a str, + #[serde_as(as = "UfeHex")] + pub sender_address: &'a FieldElement, + #[serde_as(as = "[UfeHex]")] + pub calldata: &'a [FieldElement], + #[serde_as(as = "UfeHex")] + pub version: &'a FieldElement, + #[serde_as(as = "[UfeHex]")] + pub signature: &'a [FieldElement], + #[serde_as(as = "UfeHex")] + pub nonce: &'a FieldElement, + pub resource_bounds: &'a ResourceBoundsMapping, + #[serde_as(as = "NumAsHex")] + pub tip: &'a u64, + #[serde_as(as = "[UfeHex]")] + pub paymaster_data: &'a [FieldElement], + #[serde_as(as = "[UfeHex]")] + pub account_deployment_data: &'a [FieldElement], + pub nonce_data_availability_mode: &'a DataAvailabilityMode, + pub fee_data_availability_mode: &'a DataAvailabilityMode, + } + + let r#type = "INVOKE"; + + let version = &(if self.is_query { + FieldElement::THREE + QUERY_VERSION_OFFSET + } else { + FieldElement::THREE + }); + + let tagged = Tagged { + r#type, + sender_address: &self.sender_address, + calldata: &self.calldata, + version, + signature: &self.signature, + nonce: &self.nonce, + resource_bounds: &self.resource_bounds, + tip: &self.tip, + paymaster_data: &self.paymaster_data, + account_deployment_data: &self.account_deployment_data, + nonce_data_availability_mode: &self.nonce_data_availability_mode, + fee_data_availability_mode: &self.fee_data_availability_mode, + }; + + Tagged::serialize(&tagged, serializer) + } +} + +impl<'de> Deserialize<'de> for BroadcastedInvokeTransactionV3 { + fn deserialize>(deserializer: D) -> Result { + #[serde_as] + #[derive(Deserialize)] + #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] + struct Tagged { + pub r#type: Option, + #[serde_as(as = "UfeHex")] + pub sender_address: FieldElement, + #[serde_as(as = "Vec")] + pub calldata: Vec, + #[serde_as(as = "UfeHex")] + pub version: FieldElement, + #[serde_as(as = "Vec")] + pub signature: Vec, + #[serde_as(as = "UfeHex")] + pub nonce: FieldElement, + pub resource_bounds: ResourceBoundsMapping, + #[serde_as(as = "NumAsHex")] + pub tip: u64, + #[serde_as(as = "Vec")] + pub paymaster_data: Vec, + #[serde_as(as = "Vec")] + pub account_deployment_data: Vec, + pub nonce_data_availability_mode: DataAvailabilityMode, + pub fee_data_availability_mode: DataAvailabilityMode, + } + + let tagged = Tagged::deserialize(deserializer)?; + + if let Some(tag_field) = &tagged.r#type { + if tag_field != "INVOKE" { + return Err(serde::de::Error::custom("invalid `type` value")); + } + } + + let is_query = if tagged.version == FieldElement::THREE { + false + } else if tagged.version == FieldElement::THREE + QUERY_VERSION_OFFSET { + true + } else { + return Err(serde::de::Error::custom("invalid `version` value")); + }; + + Ok(Self { + sender_address: tagged.sender_address, + calldata: tagged.calldata, + signature: tagged.signature, + nonce: tagged.nonce, + resource_bounds: tagged.resource_bounds, + tip: tagged.tip, + paymaster_data: tagged.paymaster_data, + account_deployment_data: tagged.account_deployment_data, + nonce_data_availability_mode: tagged.nonce_data_availability_mode, + fee_data_availability_mode: tagged.fee_data_availability_mode, + is_query, + }) + } +} + impl Serialize for DeclareTransactionReceipt { fn serialize(&self, serializer: S) -> Result { #[serde_as] @@ -2281,8 +2870,7 @@ impl Serialize for DeclareTransactionReceipt { pub r#type: &'a str, #[serde_as(as = "UfeHex")] pub transaction_hash: &'a FieldElement, - #[serde_as(as = "UfeHex")] - pub actual_fee: &'a FieldElement, + pub actual_fee: &'a FeePayment, pub finality_status: &'a TransactionFinalityStatus, #[serde_as(as = "UfeHex")] pub block_hash: &'a FieldElement, @@ -2322,8 +2910,7 @@ impl<'de> Deserialize<'de> for DeclareTransactionReceipt { pub r#type: Option, #[serde_as(as = "UfeHex")] pub transaction_hash: FieldElement, - #[serde_as(as = "UfeHex")] - pub actual_fee: FieldElement, + pub actual_fee: FeePayment, pub finality_status: TransactionFinalityStatus, #[serde_as(as = "UfeHex")] pub block_hash: FieldElement, @@ -2680,7 +3267,7 @@ impl<'de> Deserialize<'de> for DeclareTransactionV2 { } } -impl Serialize for DeployAccountTransaction { +impl Serialize for DeclareTransactionV3 { fn serialize(&self, serializer: S) -> Result { #[serde_as] #[derive(Serialize)] @@ -2689,7 +3276,9 @@ impl Serialize for DeployAccountTransaction { pub transaction_hash: &'a FieldElement, pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub max_fee: &'a FieldElement, + pub sender_address: &'a FieldElement, + #[serde_as(as = "UfeHex")] + pub compiled_class_hash: &'a FieldElement, #[serde_as(as = "NumAsHex")] pub version: &'a u64, #[serde_as(as = "[UfeHex]")] @@ -2697,34 +3286,44 @@ impl Serialize for DeployAccountTransaction { #[serde_as(as = "UfeHex")] pub nonce: &'a FieldElement, #[serde_as(as = "UfeHex")] - pub contract_address_salt: &'a FieldElement, - #[serde_as(as = "[UfeHex]")] - pub constructor_calldata: &'a [FieldElement], - #[serde_as(as = "UfeHex")] pub class_hash: &'a FieldElement, + pub resource_bounds: &'a ResourceBoundsMapping, + #[serde_as(as = "NumAsHex")] + pub tip: &'a u64, + #[serde_as(as = "[UfeHex]")] + pub paymaster_data: &'a [FieldElement], + #[serde_as(as = "[UfeHex]")] + pub account_deployment_data: &'a [FieldElement], + pub nonce_data_availability_mode: &'a DataAvailabilityMode, + pub fee_data_availability_mode: &'a DataAvailabilityMode, } - let r#type = "DEPLOY_ACCOUNT"; + let r#type = "DECLARE"; - let version = &1; + let version = &3; let tagged = Tagged { transaction_hash: &self.transaction_hash, r#type, - max_fee: &self.max_fee, + sender_address: &self.sender_address, + compiled_class_hash: &self.compiled_class_hash, version, signature: &self.signature, nonce: &self.nonce, - contract_address_salt: &self.contract_address_salt, - constructor_calldata: &self.constructor_calldata, class_hash: &self.class_hash, + resource_bounds: &self.resource_bounds, + tip: &self.tip, + paymaster_data: &self.paymaster_data, + account_deployment_data: &self.account_deployment_data, + nonce_data_availability_mode: &self.nonce_data_availability_mode, + fee_data_availability_mode: &self.fee_data_availability_mode, }; Tagged::serialize(&tagged, serializer) } } -impl<'de> Deserialize<'de> for DeployAccountTransaction { +impl<'de> Deserialize<'de> for DeclareTransactionV3 { fn deserialize>(deserializer: D) -> Result { #[serde_as] #[derive(Deserialize)] @@ -2734,7 +3333,9 @@ impl<'de> Deserialize<'de> for DeployAccountTransaction { pub transaction_hash: FieldElement, pub r#type: Option, #[serde_as(as = "UfeHex")] - pub max_fee: FieldElement, + pub sender_address: FieldElement, + #[serde_as(as = "UfeHex")] + pub compiled_class_hash: FieldElement, #[serde_as(as = "Option")] pub version: Option, #[serde_as(as = "Vec")] @@ -2742,35 +3343,45 @@ impl<'de> Deserialize<'de> for DeployAccountTransaction { #[serde_as(as = "UfeHex")] pub nonce: FieldElement, #[serde_as(as = "UfeHex")] - pub contract_address_salt: FieldElement, - #[serde_as(as = "Vec")] - pub constructor_calldata: Vec, - #[serde_as(as = "UfeHex")] pub class_hash: FieldElement, + pub resource_bounds: ResourceBoundsMapping, + #[serde_as(as = "NumAsHex")] + pub tip: u64, + #[serde_as(as = "Vec")] + pub paymaster_data: Vec, + #[serde_as(as = "Vec")] + pub account_deployment_data: Vec, + pub nonce_data_availability_mode: DataAvailabilityMode, + pub fee_data_availability_mode: DataAvailabilityMode, } let tagged = Tagged::deserialize(deserializer)?; if let Some(tag_field) = &tagged.r#type { - if tag_field != "DEPLOY_ACCOUNT" { + if tag_field != "DECLARE" { return Err(serde::de::Error::custom("invalid `type` value")); } } if let Some(tag_field) = &tagged.version { - if tag_field != &1 { + if tag_field != &3 { return Err(serde::de::Error::custom("invalid `version` value")); } } Ok(Self { transaction_hash: tagged.transaction_hash, - max_fee: tagged.max_fee, + sender_address: tagged.sender_address, + compiled_class_hash: tagged.compiled_class_hash, signature: tagged.signature, nonce: tagged.nonce, - contract_address_salt: tagged.contract_address_salt, - constructor_calldata: tagged.constructor_calldata, class_hash: tagged.class_hash, + resource_bounds: tagged.resource_bounds, + tip: tagged.tip, + paymaster_data: tagged.paymaster_data, + account_deployment_data: tagged.account_deployment_data, + nonce_data_availability_mode: tagged.nonce_data_availability_mode, + fee_data_availability_mode: tagged.fee_data_availability_mode, }) } } @@ -2782,8 +3393,7 @@ impl Serialize for DeployAccountTransactionReceipt { struct Tagged<'a> { #[serde_as(as = "UfeHex")] pub transaction_hash: &'a FieldElement, - #[serde_as(as = "UfeHex")] - pub actual_fee: &'a FieldElement, + pub actual_fee: &'a FeePayment, pub finality_status: &'a TransactionFinalityStatus, #[serde_as(as = "UfeHex")] pub block_hash: &'a FieldElement, @@ -2826,20 +3436,171 @@ impl<'de> Deserialize<'de> for DeployAccountTransactionReceipt { struct Tagged { #[serde_as(as = "UfeHex")] pub transaction_hash: FieldElement, + pub actual_fee: FeePayment, + pub finality_status: TransactionFinalityStatus, + #[serde_as(as = "UfeHex")] + pub block_hash: FieldElement, + pub block_number: u64, + pub messages_sent: Vec, + pub events: Vec, + pub execution_resources: ExecutionResources, + #[serde(flatten)] + pub execution_result: ExecutionResult, + pub r#type: Option, + #[serde_as(as = "UfeHex")] + pub contract_address: FieldElement, + } + + let tagged = Tagged::deserialize(deserializer)?; + + if let Some(tag_field) = &tagged.r#type { + if tag_field != "DEPLOY_ACCOUNT" { + return Err(serde::de::Error::custom("invalid `type` value")); + } + } + + Ok(Self { + transaction_hash: tagged.transaction_hash, + actual_fee: tagged.actual_fee, + finality_status: tagged.finality_status, + block_hash: tagged.block_hash, + block_number: tagged.block_number, + messages_sent: tagged.messages_sent, + events: tagged.events, + execution_resources: tagged.execution_resources, + execution_result: tagged.execution_result, + contract_address: tagged.contract_address, + }) + } +} + +impl Serialize for DeployAccountTransactionTrace { + fn serialize(&self, serializer: S) -> Result { + #[derive(Serialize)] + struct Tagged<'a> { + #[serde(skip_serializing_if = "Option::is_none")] + pub validate_invocation: &'a Option, + pub constructor_invocation: &'a FunctionInvocation, + #[serde(skip_serializing_if = "Option::is_none")] + pub fee_transfer_invocation: &'a Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub state_diff: &'a Option, + pub r#type: &'a str, + } + + let r#type = "DEPLOY_ACCOUNT"; + + let tagged = Tagged { + validate_invocation: &self.validate_invocation, + constructor_invocation: &self.constructor_invocation, + fee_transfer_invocation: &self.fee_transfer_invocation, + state_diff: &self.state_diff, + r#type, + }; + + Tagged::serialize(&tagged, serializer) + } +} + +impl<'de> Deserialize<'de> for DeployAccountTransactionTrace { + fn deserialize>(deserializer: D) -> Result { + #[derive(Deserialize)] + #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] + struct Tagged { + #[serde(skip_serializing_if = "Option::is_none")] + pub validate_invocation: Option, + pub constructor_invocation: FunctionInvocation, + #[serde(skip_serializing_if = "Option::is_none")] + pub fee_transfer_invocation: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub state_diff: Option, + pub r#type: Option, + } + + let tagged = Tagged::deserialize(deserializer)?; + + if let Some(tag_field) = &tagged.r#type { + if tag_field != "DEPLOY_ACCOUNT" { + return Err(serde::de::Error::custom("invalid `type` value")); + } + } + + Ok(Self { + validate_invocation: tagged.validate_invocation, + constructor_invocation: tagged.constructor_invocation, + fee_transfer_invocation: tagged.fee_transfer_invocation, + state_diff: tagged.state_diff, + }) + } +} + +impl Serialize for DeployAccountTransactionV1 { + fn serialize(&self, serializer: S) -> Result { + #[serde_as] + #[derive(Serialize)] + struct Tagged<'a> { + #[serde_as(as = "UfeHex")] + pub transaction_hash: &'a FieldElement, + pub r#type: &'a str, + #[serde_as(as = "UfeHex")] + pub max_fee: &'a FieldElement, + #[serde_as(as = "NumAsHex")] + pub version: &'a u64, + #[serde_as(as = "[UfeHex]")] + pub signature: &'a [FieldElement], + #[serde_as(as = "UfeHex")] + pub nonce: &'a FieldElement, + #[serde_as(as = "UfeHex")] + pub contract_address_salt: &'a FieldElement, + #[serde_as(as = "[UfeHex]")] + pub constructor_calldata: &'a [FieldElement], + #[serde_as(as = "UfeHex")] + pub class_hash: &'a FieldElement, + } + + let r#type = "DEPLOY_ACCOUNT"; + + let version = &1; + + let tagged = Tagged { + transaction_hash: &self.transaction_hash, + r#type, + max_fee: &self.max_fee, + version, + signature: &self.signature, + nonce: &self.nonce, + contract_address_salt: &self.contract_address_salt, + constructor_calldata: &self.constructor_calldata, + class_hash: &self.class_hash, + }; + + Tagged::serialize(&tagged, serializer) + } +} + +impl<'de> Deserialize<'de> for DeployAccountTransactionV1 { + fn deserialize>(deserializer: D) -> Result { + #[serde_as] + #[derive(Deserialize)] + #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] + struct Tagged { + #[serde_as(as = "UfeHex")] + pub transaction_hash: FieldElement, + pub r#type: Option, + #[serde_as(as = "UfeHex")] + pub max_fee: FieldElement, + #[serde_as(as = "Option")] + pub version: Option, + #[serde_as(as = "Vec")] + pub signature: Vec, #[serde_as(as = "UfeHex")] - pub actual_fee: FieldElement, - pub finality_status: TransactionFinalityStatus, + pub nonce: FieldElement, #[serde_as(as = "UfeHex")] - pub block_hash: FieldElement, - pub block_number: u64, - pub messages_sent: Vec, - pub events: Vec, - pub execution_resources: ExecutionResources, - #[serde(flatten)] - pub execution_result: ExecutionResult, - pub r#type: Option, + pub contract_address_salt: FieldElement, + #[serde_as(as = "Vec")] + pub constructor_calldata: Vec, #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub class_hash: FieldElement, } let tagged = Tagged::deserialize(deserializer)?; @@ -2850,62 +3611,105 @@ impl<'de> Deserialize<'de> for DeployAccountTransactionReceipt { } } + if let Some(tag_field) = &tagged.version { + if tag_field != &1 { + return Err(serde::de::Error::custom("invalid `version` value")); + } + } + Ok(Self { transaction_hash: tagged.transaction_hash, - actual_fee: tagged.actual_fee, - finality_status: tagged.finality_status, - block_hash: tagged.block_hash, - block_number: tagged.block_number, - messages_sent: tagged.messages_sent, - events: tagged.events, - execution_resources: tagged.execution_resources, - execution_result: tagged.execution_result, - contract_address: tagged.contract_address, + max_fee: tagged.max_fee, + signature: tagged.signature, + nonce: tagged.nonce, + contract_address_salt: tagged.contract_address_salt, + constructor_calldata: tagged.constructor_calldata, + class_hash: tagged.class_hash, }) } } -impl Serialize for DeployAccountTransactionTrace { +impl Serialize for DeployAccountTransactionV3 { fn serialize(&self, serializer: S) -> Result { + #[serde_as] #[derive(Serialize)] struct Tagged<'a> { - #[serde(skip_serializing_if = "Option::is_none")] - pub validate_invocation: &'a Option, - pub constructor_invocation: &'a FunctionInvocation, - #[serde(skip_serializing_if = "Option::is_none")] - pub fee_transfer_invocation: &'a Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub state_diff: &'a Option, + #[serde_as(as = "UfeHex")] + pub transaction_hash: &'a FieldElement, pub r#type: &'a str, + #[serde_as(as = "NumAsHex")] + pub version: &'a u64, + #[serde_as(as = "[UfeHex]")] + pub signature: &'a [FieldElement], + #[serde_as(as = "UfeHex")] + pub nonce: &'a FieldElement, + #[serde_as(as = "UfeHex")] + pub contract_address_salt: &'a FieldElement, + #[serde_as(as = "[UfeHex]")] + pub constructor_calldata: &'a [FieldElement], + #[serde_as(as = "UfeHex")] + pub class_hash: &'a FieldElement, + pub resource_bounds: &'a ResourceBoundsMapping, + #[serde_as(as = "NumAsHex")] + pub tip: &'a u64, + #[serde_as(as = "[UfeHex]")] + pub paymaster_data: &'a [FieldElement], + pub nonce_data_availability_mode: &'a DataAvailabilityMode, + pub fee_data_availability_mode: &'a DataAvailabilityMode, } let r#type = "DEPLOY_ACCOUNT"; + let version = &3; + let tagged = Tagged { - validate_invocation: &self.validate_invocation, - constructor_invocation: &self.constructor_invocation, - fee_transfer_invocation: &self.fee_transfer_invocation, - state_diff: &self.state_diff, + transaction_hash: &self.transaction_hash, r#type, + version, + signature: &self.signature, + nonce: &self.nonce, + contract_address_salt: &self.contract_address_salt, + constructor_calldata: &self.constructor_calldata, + class_hash: &self.class_hash, + resource_bounds: &self.resource_bounds, + tip: &self.tip, + paymaster_data: &self.paymaster_data, + nonce_data_availability_mode: &self.nonce_data_availability_mode, + fee_data_availability_mode: &self.fee_data_availability_mode, }; Tagged::serialize(&tagged, serializer) } } -impl<'de> Deserialize<'de> for DeployAccountTransactionTrace { +impl<'de> Deserialize<'de> for DeployAccountTransactionV3 { fn deserialize>(deserializer: D) -> Result { + #[serde_as] #[derive(Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] struct Tagged { - #[serde(skip_serializing_if = "Option::is_none")] - pub validate_invocation: Option, - pub constructor_invocation: FunctionInvocation, - #[serde(skip_serializing_if = "Option::is_none")] - pub fee_transfer_invocation: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub state_diff: Option, + #[serde_as(as = "UfeHex")] + pub transaction_hash: FieldElement, pub r#type: Option, + #[serde_as(as = "Option")] + pub version: Option, + #[serde_as(as = "Vec")] + pub signature: Vec, + #[serde_as(as = "UfeHex")] + pub nonce: FieldElement, + #[serde_as(as = "UfeHex")] + pub contract_address_salt: FieldElement, + #[serde_as(as = "Vec")] + pub constructor_calldata: Vec, + #[serde_as(as = "UfeHex")] + pub class_hash: FieldElement, + pub resource_bounds: ResourceBoundsMapping, + #[serde_as(as = "NumAsHex")] + pub tip: u64, + #[serde_as(as = "Vec")] + pub paymaster_data: Vec, + pub nonce_data_availability_mode: DataAvailabilityMode, + pub fee_data_availability_mode: DataAvailabilityMode, } let tagged = Tagged::deserialize(deserializer)?; @@ -2916,11 +3720,24 @@ impl<'de> Deserialize<'de> for DeployAccountTransactionTrace { } } + if let Some(tag_field) = &tagged.version { + if tag_field != &3 { + return Err(serde::de::Error::custom("invalid `version` value")); + } + } + Ok(Self { - validate_invocation: tagged.validate_invocation, - constructor_invocation: tagged.constructor_invocation, - fee_transfer_invocation: tagged.fee_transfer_invocation, - state_diff: tagged.state_diff, + transaction_hash: tagged.transaction_hash, + signature: tagged.signature, + nonce: tagged.nonce, + contract_address_salt: tagged.contract_address_salt, + constructor_calldata: tagged.constructor_calldata, + class_hash: tagged.class_hash, + resource_bounds: tagged.resource_bounds, + tip: tagged.tip, + paymaster_data: tagged.paymaster_data, + nonce_data_availability_mode: tagged.nonce_data_availability_mode, + fee_data_availability_mode: tagged.fee_data_availability_mode, }) } } @@ -2932,8 +3749,8 @@ impl Serialize for DeployTransaction { struct Tagged<'a> { #[serde_as(as = "UfeHex")] pub transaction_hash: &'a FieldElement, - #[serde_as(as = "NumAsHex")] - pub version: &'a u64, + #[serde_as(as = "UfeHex")] + pub version: &'a FieldElement, pub r#type: &'a str, #[serde_as(as = "UfeHex")] pub contract_address_salt: &'a FieldElement, @@ -2966,8 +3783,8 @@ impl<'de> Deserialize<'de> for DeployTransaction { struct Tagged { #[serde_as(as = "UfeHex")] pub transaction_hash: FieldElement, - #[serde_as(as = "NumAsHex")] - pub version: u64, + #[serde_as(as = "UfeHex")] + pub version: FieldElement, pub r#type: Option, #[serde_as(as = "UfeHex")] pub contract_address_salt: FieldElement, @@ -3002,8 +3819,7 @@ impl Serialize for DeployTransactionReceipt { struct Tagged<'a> { #[serde_as(as = "UfeHex")] pub transaction_hash: &'a FieldElement, - #[serde_as(as = "UfeHex")] - pub actual_fee: &'a FieldElement, + pub actual_fee: &'a FeePayment, pub finality_status: &'a TransactionFinalityStatus, #[serde_as(as = "UfeHex")] pub block_hash: &'a FieldElement, @@ -3046,8 +3862,7 @@ impl<'de> Deserialize<'de> for DeployTransactionReceipt { struct Tagged { #[serde_as(as = "UfeHex")] pub transaction_hash: FieldElement, - #[serde_as(as = "UfeHex")] - pub actual_fee: FieldElement, + pub actual_fee: FeePayment, pub finality_status: TransactionFinalityStatus, #[serde_as(as = "UfeHex")] pub block_hash: FieldElement, @@ -3093,8 +3908,7 @@ impl Serialize for InvokeTransactionReceipt { pub r#type: &'a str, #[serde_as(as = "UfeHex")] pub transaction_hash: &'a FieldElement, - #[serde_as(as = "UfeHex")] - pub actual_fee: &'a FieldElement, + pub actual_fee: &'a FeePayment, pub finality_status: &'a TransactionFinalityStatus, #[serde_as(as = "UfeHex")] pub block_hash: &'a FieldElement, @@ -3134,8 +3948,7 @@ impl<'de> Deserialize<'de> for InvokeTransactionReceipt { pub r#type: Option, #[serde_as(as = "UfeHex")] pub transaction_hash: FieldElement, - #[serde_as(as = "UfeHex")] - pub actual_fee: FieldElement, + pub actual_fee: FeePayment, pub finality_status: TransactionFinalityStatus, #[serde_as(as = "UfeHex")] pub block_hash: FieldElement, @@ -3407,15 +4220,128 @@ impl<'de> Deserialize<'de> for InvokeTransactionV1 { } } -impl Serialize for L1HandlerTransaction { +impl Serialize for InvokeTransactionV3 { fn serialize(&self, serializer: S) -> Result { #[serde_as] #[derive(Serialize)] struct Tagged<'a> { #[serde_as(as = "UfeHex")] pub transaction_hash: &'a FieldElement, + pub r#type: &'a str, + #[serde_as(as = "UfeHex")] + pub sender_address: &'a FieldElement, + #[serde_as(as = "[UfeHex]")] + pub calldata: &'a [FieldElement], #[serde_as(as = "NumAsHex")] pub version: &'a u64, + #[serde_as(as = "[UfeHex]")] + pub signature: &'a [FieldElement], + #[serde_as(as = "UfeHex")] + pub nonce: &'a FieldElement, + pub resource_bounds: &'a ResourceBoundsMapping, + #[serde_as(as = "NumAsHex")] + pub tip: &'a u64, + #[serde_as(as = "[UfeHex]")] + pub paymaster_data: &'a [FieldElement], + #[serde_as(as = "[UfeHex]")] + pub account_deployment_data: &'a [FieldElement], + pub nonce_data_availability_mode: &'a DataAvailabilityMode, + pub fee_data_availability_mode: &'a DataAvailabilityMode, + } + + let r#type = "INVOKE"; + + let version = &3; + + let tagged = Tagged { + transaction_hash: &self.transaction_hash, + r#type, + sender_address: &self.sender_address, + calldata: &self.calldata, + version, + signature: &self.signature, + nonce: &self.nonce, + resource_bounds: &self.resource_bounds, + tip: &self.tip, + paymaster_data: &self.paymaster_data, + account_deployment_data: &self.account_deployment_data, + nonce_data_availability_mode: &self.nonce_data_availability_mode, + fee_data_availability_mode: &self.fee_data_availability_mode, + }; + + Tagged::serialize(&tagged, serializer) + } +} + +impl<'de> Deserialize<'de> for InvokeTransactionV3 { + fn deserialize>(deserializer: D) -> Result { + #[serde_as] + #[derive(Deserialize)] + #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] + struct Tagged { + #[serde_as(as = "UfeHex")] + pub transaction_hash: FieldElement, + pub r#type: Option, + #[serde_as(as = "UfeHex")] + pub sender_address: FieldElement, + #[serde_as(as = "Vec")] + pub calldata: Vec, + #[serde_as(as = "Option")] + pub version: Option, + #[serde_as(as = "Vec")] + pub signature: Vec, + #[serde_as(as = "UfeHex")] + pub nonce: FieldElement, + pub resource_bounds: ResourceBoundsMapping, + #[serde_as(as = "NumAsHex")] + pub tip: u64, + #[serde_as(as = "Vec")] + pub paymaster_data: Vec, + #[serde_as(as = "Vec")] + pub account_deployment_data: Vec, + pub nonce_data_availability_mode: DataAvailabilityMode, + pub fee_data_availability_mode: DataAvailabilityMode, + } + + let tagged = Tagged::deserialize(deserializer)?; + + if let Some(tag_field) = &tagged.r#type { + if tag_field != "INVOKE" { + return Err(serde::de::Error::custom("invalid `type` value")); + } + } + + if let Some(tag_field) = &tagged.version { + if tag_field != &3 { + return Err(serde::de::Error::custom("invalid `version` value")); + } + } + + Ok(Self { + transaction_hash: tagged.transaction_hash, + sender_address: tagged.sender_address, + calldata: tagged.calldata, + signature: tagged.signature, + nonce: tagged.nonce, + resource_bounds: tagged.resource_bounds, + tip: tagged.tip, + paymaster_data: tagged.paymaster_data, + account_deployment_data: tagged.account_deployment_data, + nonce_data_availability_mode: tagged.nonce_data_availability_mode, + fee_data_availability_mode: tagged.fee_data_availability_mode, + }) + } +} + +impl Serialize for L1HandlerTransaction { + fn serialize(&self, serializer: S) -> Result { + #[serde_as] + #[derive(Serialize)] + struct Tagged<'a> { + #[serde_as(as = "UfeHex")] + pub transaction_hash: &'a FieldElement, + #[serde_as(as = "UfeHex")] + pub version: &'a FieldElement, pub r#type: &'a str, #[serde_as(as = "NumAsHex")] pub nonce: &'a u64, @@ -3451,8 +4377,8 @@ impl<'de> Deserialize<'de> for L1HandlerTransaction { struct Tagged { #[serde_as(as = "UfeHex")] pub transaction_hash: FieldElement, - #[serde_as(as = "NumAsHex")] - pub version: u64, + #[serde_as(as = "UfeHex")] + pub version: FieldElement, pub r#type: Option, #[serde_as(as = "NumAsHex")] pub nonce: u64, @@ -3492,8 +4418,7 @@ impl Serialize for L1HandlerTransactionReceipt { pub message_hash: &'a Hash256, #[serde_as(as = "UfeHex")] pub transaction_hash: &'a FieldElement, - #[serde_as(as = "UfeHex")] - pub actual_fee: &'a FieldElement, + pub actual_fee: &'a FeePayment, pub finality_status: &'a TransactionFinalityStatus, #[serde_as(as = "UfeHex")] pub block_hash: &'a FieldElement, @@ -3535,8 +4460,7 @@ impl<'de> Deserialize<'de> for L1HandlerTransactionReceipt { pub message_hash: Hash256, #[serde_as(as = "UfeHex")] pub transaction_hash: FieldElement, - #[serde_as(as = "UfeHex")] - pub actual_fee: FieldElement, + pub actual_fee: FeePayment, pub finality_status: TransactionFinalityStatus, #[serde_as(as = "UfeHex")] pub block_hash: FieldElement, @@ -3627,8 +4551,7 @@ impl Serialize for PendingDeclareTransactionReceipt { pub r#type: &'a str, #[serde_as(as = "UfeHex")] pub transaction_hash: &'a FieldElement, - #[serde_as(as = "UfeHex")] - pub actual_fee: &'a FieldElement, + pub actual_fee: &'a FeePayment, pub messages_sent: &'a [MsgToL1], pub events: &'a [Event], pub finality_status: &'a TransactionFinalityStatus, @@ -3665,8 +4588,7 @@ impl<'de> Deserialize<'de> for PendingDeclareTransactionReceipt { pub r#type: Option, #[serde_as(as = "UfeHex")] pub transaction_hash: FieldElement, - #[serde_as(as = "UfeHex")] - pub actual_fee: FieldElement, + pub actual_fee: FeePayment, pub messages_sent: Vec, pub events: Vec, pub finality_status: TransactionFinalityStatus, @@ -3705,8 +4627,7 @@ impl Serialize for PendingDeployAccountTransactionReceipt { struct Tagged<'a> { #[serde_as(as = "UfeHex")] pub transaction_hash: &'a FieldElement, - #[serde_as(as = "UfeHex")] - pub actual_fee: &'a FieldElement, + pub actual_fee: &'a FeePayment, pub messages_sent: &'a [MsgToL1], pub events: &'a [Event], pub finality_status: &'a TransactionFinalityStatus, @@ -3746,8 +4667,7 @@ impl<'de> Deserialize<'de> for PendingDeployAccountTransactionReceipt { struct Tagged { #[serde_as(as = "UfeHex")] pub transaction_hash: FieldElement, - #[serde_as(as = "UfeHex")] - pub actual_fee: FieldElement, + pub actual_fee: FeePayment, pub messages_sent: Vec, pub events: Vec, pub finality_status: TransactionFinalityStatus, @@ -3791,8 +4711,7 @@ impl Serialize for PendingInvokeTransactionReceipt { pub r#type: &'a str, #[serde_as(as = "UfeHex")] pub transaction_hash: &'a FieldElement, - #[serde_as(as = "UfeHex")] - pub actual_fee: &'a FieldElement, + pub actual_fee: &'a FeePayment, pub messages_sent: &'a [MsgToL1], pub events: &'a [Event], pub finality_status: &'a TransactionFinalityStatus, @@ -3829,8 +4748,7 @@ impl<'de> Deserialize<'de> for PendingInvokeTransactionReceipt { pub r#type: Option, #[serde_as(as = "UfeHex")] pub transaction_hash: FieldElement, - #[serde_as(as = "UfeHex")] - pub actual_fee: FieldElement, + pub actual_fee: FeePayment, pub messages_sent: Vec, pub events: Vec, pub finality_status: TransactionFinalityStatus, @@ -3871,8 +4789,7 @@ impl Serialize for PendingL1HandlerTransactionReceipt { pub message_hash: &'a Hash256, #[serde_as(as = "UfeHex")] pub transaction_hash: &'a FieldElement, - #[serde_as(as = "UfeHex")] - pub actual_fee: &'a FieldElement, + pub actual_fee: &'a FeePayment, pub messages_sent: &'a [MsgToL1], pub events: &'a [Event], pub finality_status: &'a TransactionFinalityStatus, @@ -3911,8 +4828,7 @@ impl<'de> Deserialize<'de> for PendingL1HandlerTransactionReceipt { pub message_hash: Hash256, #[serde_as(as = "UfeHex")] pub transaction_hash: FieldElement, - #[serde_as(as = "UfeHex")] - pub actual_fee: FieldElement, + pub actual_fee: FeePayment, pub messages_sent: Vec, pub events: Vec, pub finality_status: TransactionFinalityStatus, @@ -4354,6 +5270,12 @@ impl Serialize for EstimateFeeRequest { #[derive(Serialize)] #[serde(transparent)] struct Field1<'a> { + pub simulation_flags: &'a [SimulationFlagForEstimateFee], + } + + #[derive(Serialize)] + #[serde(transparent)] + struct Field2<'a> { pub block_id: &'a BlockId, } @@ -4365,6 +5287,9 @@ impl Serialize for EstimateFeeRequest { request: &self.request, })?; seq.serialize_element(&Field1 { + simulation_flags: &self.simulation_flags, + })?; + seq.serialize_element(&Field2 { block_id: &self.block_id, })?; @@ -4383,6 +5308,12 @@ impl<'a> Serialize for EstimateFeeRequestRef<'a> { #[derive(Serialize)] #[serde(transparent)] struct Field1<'a> { + pub simulation_flags: &'a [SimulationFlagForEstimateFee], + } + + #[derive(Serialize)] + #[serde(transparent)] + struct Field2<'a> { pub block_id: &'a BlockId, } @@ -4394,6 +5325,9 @@ impl<'a> Serialize for EstimateFeeRequestRef<'a> { request: self.request, })?; seq.serialize_element(&Field1 { + simulation_flags: self.simulation_flags, + })?; + seq.serialize_element(&Field2 { block_id: self.block_id, })?; @@ -4407,6 +5341,7 @@ impl<'de> Deserialize<'de> for EstimateFeeRequest { #[derive(Deserialize)] struct AsObject { pub request: Vec, + pub simulation_flags: Vec, pub block_id: BlockId, } @@ -4419,12 +5354,24 @@ impl<'de> Deserialize<'de> for EstimateFeeRequest { #[derive(Deserialize)] #[serde(transparent)] struct Field1 { + pub simulation_flags: Vec, + } + + #[derive(Deserialize)] + #[serde(transparent)] + struct Field2 { pub block_id: BlockId, } let temp = serde_json::Value::deserialize(deserializer)?; if let Ok(mut elements) = Vec::::deserialize(&temp) { + let field2 = serde_json::from_value::( + elements + .pop() + .ok_or_else(|| serde::de::Error::custom("invalid sequence length"))?, + ) + .map_err(|err| serde::de::Error::custom(format!("failed to parse element: {}", err)))?; let field1 = serde_json::from_value::( elements .pop() @@ -4440,11 +5387,13 @@ impl<'de> Deserialize<'de> for EstimateFeeRequest { Ok(Self { request: field0.request, - block_id: field1.block_id, + simulation_flags: field1.simulation_flags, + block_id: field2.block_id, }) } else if let Ok(object) = AsObject::deserialize(&temp) { Ok(Self { request: object.request, + simulation_flags: object.simulation_flags, block_id: object.block_id, }) } else { diff --git a/starknet-core/src/types/mod.rs b/starknet-core/src/types/mod.rs index 7c3e4eba..3cef6596 100644 --- a/starknet-core/src/types/mod.rs +++ b/starknet-core/src/types/mod.rs @@ -15,16 +15,18 @@ mod serde_impls; mod codegen; pub use codegen::{ BlockStatus, BlockTag, BlockWithTxHashes, BlockWithTxs, BroadcastedDeclareTransactionV1, - BroadcastedDeclareTransactionV2, BroadcastedDeployAccountTransaction, - BroadcastedInvokeTransaction, CallType, CompressedLegacyContractClass, ContractErrorData, - ContractStorageDiffItem, DataAvailabilityMode, DeclareTransactionReceipt, - DeclareTransactionTrace, DeclareTransactionV0, DeclareTransactionV1, DeclareTransactionV2, - DeclaredClassItem, DeployAccountTransaction, DeployAccountTransactionReceipt, - DeployAccountTransactionTrace, DeployTransaction, DeployTransactionReceipt, - DeployedContractItem, EmittedEvent, EntryPointType, EntryPointsByType, Event, EventFilter, - EventFilterWithPage, EventsChunk, ExecutionResources, FeeEstimate, FlattenedSierraClass, - FunctionCall, FunctionInvocation, FunctionStateMutability, InvokeTransactionReceipt, - InvokeTransactionTrace, InvokeTransactionV0, InvokeTransactionV1, L1HandlerTransaction, + BroadcastedDeclareTransactionV2, BroadcastedDeclareTransactionV3, + BroadcastedDeployAccountTransactionV1, BroadcastedDeployAccountTransactionV3, + BroadcastedInvokeTransactionV1, BroadcastedInvokeTransactionV3, CallType, + CompressedLegacyContractClass, ContractErrorData, ContractStorageDiffItem, + DataAvailabilityMode, DeclareTransactionReceipt, DeclareTransactionTrace, DeclareTransactionV0, + DeclareTransactionV1, DeclareTransactionV2, DeclareTransactionV3, DeclaredClassItem, + DeployAccountTransactionReceipt, DeployAccountTransactionTrace, DeployAccountTransactionV1, + DeployAccountTransactionV3, DeployTransaction, DeployTransactionReceipt, DeployedContractItem, + EmittedEvent, EntryPointType, EntryPointsByType, Event, EventFilter, EventFilterWithPage, + EventsChunk, ExecutionResources, FeeEstimate, FeePayment, FlattenedSierraClass, FunctionCall, + FunctionInvocation, FunctionStateMutability, InvokeTransactionReceipt, InvokeTransactionTrace, + InvokeTransactionV0, InvokeTransactionV1, InvokeTransactionV3, L1HandlerTransaction, L1HandlerTransactionReceipt, L1HandlerTransactionTrace, LegacyContractEntryPoint, LegacyEntryPointsByType, LegacyEventAbiEntry, LegacyEventAbiType, LegacyFunctionAbiEntry, LegacyFunctionAbiType, LegacyStructAbiEntry, LegacyStructAbiType, LegacyStructMember, @@ -32,10 +34,11 @@ pub use codegen::{ OrderedMessage, PendingBlockWithTxHashes, PendingBlockWithTxs, PendingDeclareTransactionReceipt, PendingDeployAccountTransactionReceipt, PendingInvokeTransactionReceipt, PendingL1HandlerTransactionReceipt, PendingStateUpdate, - ReplacedClassItem, ResourceLimits, ResourcePrice, ResultPageRequest, RevertedInvocation, - SequencerTransactionStatus, SierraEntryPoint, SimulatedTransaction, SimulationFlag, - StarknetError, StateDiff, StateUpdate, StorageEntry, SyncStatus, TransactionExecutionStatus, - TransactionFinalityStatus, TransactionTraceWithHash, + PriceUnit, ReplacedClassItem, ResourceBounds, ResourceBoundsMapping, ResourcePrice, + ResultPageRequest, RevertedInvocation, SequencerTransactionStatus, SierraEntryPoint, + SimulatedTransaction, SimulationFlag, SimulationFlagForEstimateFee, StarknetError, StateDiff, + StateUpdate, StorageEntry, SyncStatus, TransactionExecutionErrorData, + TransactionExecutionStatus, TransactionFinalityStatus, TransactionTraceWithHash, }; pub mod eth_address; @@ -204,6 +207,8 @@ pub enum InvokeTransaction { V0(InvokeTransactionV0), #[serde(rename = "0x1")] V1(InvokeTransactionV1), + #[serde(rename = "0x3")] + V3(InvokeTransactionV3), } #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] @@ -215,6 +220,24 @@ pub enum DeclareTransaction { V1(DeclareTransactionV1), #[serde(rename = "0x2")] V2(DeclareTransactionV2), + #[serde(rename = "0x3")] + V3(DeclareTransactionV3), +} + +#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] +#[serde(tag = "version")] +pub enum DeployAccountTransaction { + #[serde(rename = "0x1")] + V1(DeployAccountTransactionV1), + #[serde(rename = "0x3")] + V3(DeployAccountTransactionV3), +} + +#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] +#[serde(untagged)] +pub enum BroadcastedInvokeTransaction { + V1(BroadcastedInvokeTransactionV1), + V3(BroadcastedInvokeTransactionV3), } #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] @@ -222,6 +245,14 @@ pub enum DeclareTransaction { pub enum BroadcastedDeclareTransaction { V1(BroadcastedDeclareTransactionV1), V2(BroadcastedDeclareTransactionV2), + V3(BroadcastedDeclareTransactionV3), +} + +#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] +#[serde(untagged)] +pub enum BroadcastedDeployAccountTransaction { + V1(BroadcastedDeployAccountTransactionV1), + V3(BroadcastedDeployAccountTransactionV3), } #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] @@ -346,7 +377,7 @@ impl Transaction { Transaction::L1Handler(tx) => &tx.transaction_hash, Transaction::Declare(tx) => tx.transaction_hash(), Transaction::Deploy(tx) => &tx.transaction_hash, - Transaction::DeployAccount(tx) => &tx.transaction_hash, + Transaction::DeployAccount(tx) => tx.transaction_hash(), } } } @@ -356,6 +387,7 @@ impl InvokeTransaction { match self { InvokeTransaction::V0(tx) => &tx.transaction_hash, InvokeTransaction::V1(tx) => &tx.transaction_hash, + InvokeTransaction::V3(tx) => &tx.transaction_hash, } } } @@ -366,6 +398,16 @@ impl DeclareTransaction { DeclareTransaction::V0(tx) => &tx.transaction_hash, DeclareTransaction::V1(tx) => &tx.transaction_hash, DeclareTransaction::V2(tx) => &tx.transaction_hash, + DeclareTransaction::V3(tx) => &tx.transaction_hash, + } + } +} + +impl DeployAccountTransaction { + pub fn transaction_hash(&self) -> &FieldElement { + match self { + DeployAccountTransaction::V1(tx) => &tx.transaction_hash, + DeployAccountTransaction::V3(tx) => &tx.transaction_hash, } } } @@ -526,7 +568,7 @@ mod tests { fn test_broadcasted_invoke_v1_non_query_deser() { let raw = include_str!("../../test-data/serde/broadcasted_invoke_v1_non_query.json"); - let parsed_object = serde_json::from_str::(raw).unwrap(); + let parsed_object = serde_json::from_str::(raw).unwrap(); assert!(!parsed_object.is_query); } @@ -535,7 +577,7 @@ mod tests { fn test_broadcasted_invoke_v1_query_deser() { let raw = include_str!("../../test-data/serde/broadcasted_invoke_v1_query.json"); - let parsed_object = serde_json::from_str::(raw).unwrap(); + let parsed_object = serde_json::from_str::(raw).unwrap(); assert!(parsed_object.is_query); } @@ -547,7 +589,7 @@ mod tests { "0x374286ae28f201e61ffbc5b022cc9701208640b405ea34ea9799f97d5d2d23c", ) .unwrap(), - version: 0, + version: FieldElement::ZERO, nonce: 775628, contract_address: FieldElement::from_hex_be( "0x73314940630fd6dcda0d772d4c972c4e0a9946bef9dabf4ef84eda8ef542b82", diff --git a/starknet-core/src/types/serde_impls.rs b/starknet-core/src/types/serde_impls.rs index 76b5aac9..81d98889 100644 --- a/starknet-core/src/types/serde_impls.rs +++ b/starknet-core/src/types/serde_impls.rs @@ -7,7 +7,8 @@ use super::{SyncStatus, SyncStatusType}; pub(crate) struct NumAsHex; -struct NumAsHexVisitor; +struct NumAsHexVisitorU64; +struct NumAsHexVisitorU128; impl SerializeAs for NumAsHex { fn serialize_as(value: &u64, serializer: S) -> Result @@ -18,16 +19,43 @@ impl SerializeAs for NumAsHex { } } +impl SerializeAs<&u64> for NumAsHex { + fn serialize_as(value: &&u64, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(&format!("{value:#x}")) + } +} + impl<'de> DeserializeAs<'de, u64> for NumAsHex { fn deserialize_as(deserializer: D) -> Result where D: Deserializer<'de>, { - deserializer.deserialize_any(NumAsHexVisitor) + deserializer.deserialize_any(NumAsHexVisitorU64) } } -impl<'de> Visitor<'de> for NumAsHexVisitor { +impl SerializeAs for NumAsHex { + fn serialize_as(value: &u128, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(&format!("{value:#x}")) + } +} + +impl<'de> DeserializeAs<'de, u128> for NumAsHex { + fn deserialize_as(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(NumAsHexVisitorU128) + } +} + +impl<'de> Visitor<'de> for NumAsHexVisitorU64 { type Value = u64; fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { @@ -67,6 +95,26 @@ impl<'de> Visitor<'de> for NumAsHexVisitor { } } +impl<'de> Visitor<'de> for NumAsHexVisitorU128 { + type Value = u128; + + fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { + write!(formatter, "string or number") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + match u128::from_str_radix(v.trim_start_matches("0x"), 16) { + Ok(value) => Ok(value), + Err(err) => Err(serde::de::Error::custom(format!( + "invalid hex string: {err}" + ))), + } + } +} + #[derive(Deserialize)] #[serde(untagged)] enum SyncStatusTypeDe { @@ -262,6 +310,7 @@ mod enum_ser_impls { match self { Self::V0(variant) => variant.serialize(serializer), Self::V1(variant) => variant.serialize(serializer), + Self::V3(variant) => variant.serialize(serializer), } } } @@ -272,6 +321,25 @@ mod enum_ser_impls { Self::V0(variant) => variant.serialize(serializer), Self::V1(variant) => variant.serialize(serializer), Self::V2(variant) => variant.serialize(serializer), + Self::V3(variant) => variant.serialize(serializer), + } + } + } + + impl Serialize for DeployAccountTransaction { + fn serialize(&self, serializer: S) -> Result { + match self { + Self::V1(variant) => variant.serialize(serializer), + Self::V3(variant) => variant.serialize(serializer), + } + } + } + + impl Serialize for BroadcastedInvokeTransaction { + fn serialize(&self, serializer: S) -> Result { + match self { + Self::V1(variant) => variant.serialize(serializer), + Self::V3(variant) => variant.serialize(serializer), } } } @@ -281,6 +349,16 @@ mod enum_ser_impls { match self { Self::V1(variant) => variant.serialize(serializer), Self::V2(variant) => variant.serialize(serializer), + Self::V3(variant) => variant.serialize(serializer), + } + } + } + + impl Serialize for BroadcastedDeployAccountTransaction { + fn serialize(&self, serializer: S) -> Result { + match self { + Self::V1(variant) => variant.serialize(serializer), + Self::V3(variant) => variant.serialize(serializer), } } } diff --git a/starknet-providers/src/any.rs b/starknet-providers/src/any.rs index f625ae3a..0369dbab 100644 --- a/starknet-providers/src/any.rs +++ b/starknet-providers/src/any.rs @@ -6,7 +6,8 @@ use starknet_core::types::{ EventsPage, FeeEstimate, FieldElement, FunctionCall, InvokeTransactionResult, MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, MaybePendingStateUpdate, MaybePendingTransactionReceipt, MsgFromL1, SimulatedTransaction, SimulationFlag, - SyncStatusType, Transaction, TransactionStatus, TransactionTrace, TransactionTraceWithHash, + SimulationFlagForEstimateFee, SyncStatusType, Transaction, TransactionStatus, TransactionTrace, + TransactionTraceWithHash, }; use crate::{ @@ -342,22 +343,35 @@ impl Provider for AnyProvider { } } - async fn estimate_fee( + async fn estimate_fee( &self, request: R, + simulation_flags: S, block_id: B, ) -> Result, ProviderError> where R: AsRef<[BroadcastedTransaction]> + Send + Sync, + S: AsRef<[SimulationFlagForEstimateFee]> + Send + Sync, B: AsRef + Send + Sync, { match self { Self::JsonRpcHttp(inner) => { - as Provider>::estimate_fee(inner, request, block_id) - .await + as Provider>::estimate_fee( + inner, + request, + simulation_flags, + block_id, + ) + .await } Self::SequencerGateway(inner) => { - ::estimate_fee(inner, request, block_id).await + ::estimate_fee( + inner, + request, + simulation_flags, + block_id, + ) + .await } } } diff --git a/starknet-providers/src/jsonrpc/mod.rs b/starknet-providers/src/jsonrpc/mod.rs index e67507be..66232291 100644 --- a/starknet-providers/src/jsonrpc/mod.rs +++ b/starknet-providers/src/jsonrpc/mod.rs @@ -13,7 +13,8 @@ use starknet_core::{ InvokeTransactionResult, MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, MaybePendingStateUpdate, MaybePendingTransactionReceipt, MsgFromL1, NoTraceAvailableErrorData, ResultPageRequest, SimulatedTransaction, SimulationFlag, - StarknetError, SyncStatusType, Transaction, TransactionStatus, TransactionTrace, + SimulationFlagForEstimateFee, StarknetError, SyncStatusType, Transaction, + TransactionExecutionErrorData, TransactionStatus, TransactionTrace, TransactionTraceWithHash, }, }; @@ -456,19 +457,22 @@ where } /// Estimate the fee for a given Starknet transaction - async fn estimate_fee( + async fn estimate_fee( &self, request: R, + simulation_flags: S, block_id: B, ) -> Result, ProviderError> where R: AsRef<[BroadcastedTransaction]> + Send + Sync, + S: AsRef<[SimulationFlagForEstimateFee]> + Send + Sync, B: AsRef + Send + Sync, { self.send_request( JsonRpcMethod::EstimateFee, EstimateFeeRequestRef { request: request.as_ref(), + simulation_flags: simulation_flags.as_ref(), block_id: block_id.as_ref(), }, ) @@ -635,7 +639,11 @@ where } /// Simulate a given sequence of transactions on the requested state, and generate the execution - /// traces. If one of the transactions is reverted, raises CONTRACT_ERROR. + /// traces. Note that some of the transactions may revert, in which case no error is thrown, but + /// revert details can be seen on the returned trace object. . Note that some of the + /// transactions may revert, this will be reflected by the revert_error property in the trace. + /// Other types of failures (e.g. unexpected error or failure in the validation phase) will + /// result in TRANSACTION_EXECUTION_ERROR. async fn simulate_transactions( &self, block_id: B, @@ -872,11 +880,30 @@ impl TryFrom<&JsonRpcError> for StarknetError { .map_err(|_| JsonRpcErrorConversionError::DataParsingFailure)?; Ok(StarknetError::ContractError(data)) } + 41 => { + let data = TransactionExecutionErrorData::deserialize( + value + .data + .as_ref() + .ok_or(JsonRpcErrorConversionError::MissingData)?, + ) + .map_err(|_| JsonRpcErrorConversionError::DataParsingFailure)?; + Ok(StarknetError::TransactionExecutionError(data)) + } 51 => Ok(StarknetError::ClassAlreadyDeclared), 52 => Ok(StarknetError::InvalidTransactionNonce), 53 => Ok(StarknetError::InsufficientMaxFee), 54 => Ok(StarknetError::InsufficientAccountBalance), - 55 => Ok(StarknetError::ValidationFailure), + 55 => { + let data = String::deserialize( + value + .data + .as_ref() + .ok_or(JsonRpcErrorConversionError::MissingData)?, + ) + .map_err(|_| JsonRpcErrorConversionError::DataParsingFailure)?; + Ok(StarknetError::ValidationFailure(data)) + } 56 => Ok(StarknetError::CompilationFailed), 57 => Ok(StarknetError::ContractClassSizeIsTooLarge), 58 => Ok(StarknetError::NonAccount), @@ -904,7 +931,6 @@ impl TryFrom<&JsonRpcError> for StarknetError { .map_err(|_| JsonRpcErrorConversionError::DataParsingFailure)?; Ok(StarknetError::NoTraceAvailable(data)) } - 25 => Ok(StarknetError::InvalidTransactionHash), _ => Err(JsonRpcErrorConversionError::UnknownCode), } } diff --git a/starknet-providers/src/provider.rs b/starknet-providers/src/provider.rs index 2214cb88..256b5429 100644 --- a/starknet-providers/src/provider.rs +++ b/starknet-providers/src/provider.rs @@ -6,8 +6,9 @@ use starknet_core::types::{ ContractClass, DeclareTransactionResult, DeployAccountTransactionResult, EventFilter, EventsPage, FeeEstimate, FieldElement, FunctionCall, InvokeTransactionResult, MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, MaybePendingStateUpdate, - MaybePendingTransactionReceipt, MsgFromL1, SimulatedTransaction, SimulationFlag, StarknetError, - SyncStatusType, Transaction, TransactionStatus, TransactionTrace, TransactionTraceWithHash, + MaybePendingTransactionReceipt, MsgFromL1, SimulatedTransaction, SimulationFlag, + SimulationFlagForEstimateFee, StarknetError, SyncStatusType, Transaction, TransactionStatus, + TransactionTrace, TransactionTraceWithHash, }; use std::{any::Any, error::Error, fmt::Debug}; @@ -130,13 +131,15 @@ pub trait Provider { B: AsRef + Send + Sync; /// Estimate the fee for a given Starknet transaction - async fn estimate_fee( + async fn estimate_fee( &self, request: R, + simulation_flags: S, block_id: B, ) -> Result, ProviderError> where R: AsRef<[BroadcastedTransaction]> + Send + Sync, + S: AsRef<[SimulationFlagForEstimateFee]> + Send + Sync, B: AsRef + Send + Sync; async fn estimate_message_fee( @@ -212,7 +215,11 @@ pub trait Provider { H: AsRef + Send + Sync; /// Simulate a given sequence of transactions on the requested state, and generate the execution - /// traces. If one of the transactions is reverted, raises CONTRACT_ERROR. + /// traces. Note that some of the transactions may revert, in which case no error is thrown, but + /// revert details can be seen on the returned trace object. . Note that some of the + /// transactions may revert, this will be reflected by the revert_error property in the trace. + /// Other types of failures (e.g. unexpected error or failure in the validation phase) will + /// result in TRANSACTION_EXECUTION_ERROR. async fn simulate_transactions( &self, block_id: B, @@ -233,17 +240,19 @@ pub trait Provider { B: AsRef + Send + Sync; /// Same as [estimate_fee], but only with one estimate. - async fn estimate_fee_single( + async fn estimate_fee_single( &self, request: R, + simulation_flags: S, block_id: B, ) -> Result where R: AsRef + Send + Sync, + S: AsRef<[SimulationFlagForEstimateFee]> + Send + Sync, B: AsRef + Send + Sync, { let mut result = self - .estimate_fee([request.as_ref().to_owned()], block_id) + .estimate_fee([request.as_ref().to_owned()], simulation_flags, block_id) .await?; if result.len() == 1 { diff --git a/starknet-providers/src/sequencer/mod.rs b/starknet-providers/src/sequencer/mod.rs index 95b19eb4..1fdc97d8 100644 --- a/starknet-providers/src/sequencer/mod.rs +++ b/starknet-providers/src/sequencer/mod.rs @@ -450,7 +450,9 @@ impl From for ProviderError { ErrorCode::BlockNotFound => Some(StarknetError::BlockNotFound), ErrorCode::EntryPointNotFoundInContract => None, ErrorCode::InvalidProgram => None, - ErrorCode::TransactionFailed => Some(StarknetError::ValidationFailure), + ErrorCode::TransactionFailed => { + Some(StarknetError::ValidationFailure(value.message.clone())) + } ErrorCode::TransactionNotFound => Some(StarknetError::ContractNotFound), ErrorCode::UninitializedContract => Some(StarknetError::ContractNotFound), ErrorCode::MalformedRequest => None, diff --git a/starknet-providers/src/sequencer/models/conversions.rs b/starknet-providers/src/sequencer/models/conversions.rs index 739cc829..167eb2ba 100644 --- a/starknet-providers/src/sequencer/models/conversions.rs +++ b/starknet-providers/src/sequencer/models/conversions.rs @@ -8,6 +8,7 @@ use super::{ CallType, FunctionInvocation, OrderedEventResponse, OrderedL2ToL1MessageResponse, TransactionTraceWithHash, }, + transaction::{DataAvailabilityMode, ResourceBounds, ResourceBoundsMapping}, *, }; @@ -47,16 +48,8 @@ impl TryFrom for core::MaybePendingBlockWithTxHashes { timestamp: value.timestamp, sequencer_address: value.sequencer_address.unwrap_or_default(), l1_gas_price: core::ResourcePrice { - price_in_strk: Some( - value - .strk_l1_gas_price - .try_into() - .map_err(|_| ConversionError)?, - ), - price_in_wei: value - .eth_l1_gas_price - .try_into() - .map_err(|_| ConversionError)?, + price_in_fri: value.strk_l1_gas_price, + price_in_wei: value.eth_l1_gas_price, }, starknet_version: value.starknet_version.ok_or(ConversionError)?, transactions: value @@ -77,16 +70,8 @@ impl TryFrom for core::MaybePendingBlockWithTxHashes { sequencer_address: value.sequencer_address.unwrap_or_default(), parent_hash: value.parent_block_hash, l1_gas_price: core::ResourcePrice { - price_in_strk: Some( - value - .strk_l1_gas_price - .try_into() - .map_err(|_| ConversionError)?, - ), - price_in_wei: value - .eth_l1_gas_price - .try_into() - .map_err(|_| ConversionError)?, + price_in_fri: value.strk_l1_gas_price, + price_in_wei: value.eth_l1_gas_price, }, starknet_version: value.starknet_version.ok_or(ConversionError)?, })), @@ -112,16 +97,8 @@ impl TryFrom for core::MaybePendingBlockWithTxs { timestamp: value.timestamp, sequencer_address: value.sequencer_address.unwrap_or_default(), l1_gas_price: core::ResourcePrice { - price_in_strk: Some( - value - .strk_l1_gas_price - .try_into() - .map_err(|_| ConversionError)?, - ), - price_in_wei: value - .eth_l1_gas_price - .try_into() - .map_err(|_| ConversionError)?, + price_in_fri: value.strk_l1_gas_price, + price_in_wei: value.eth_l1_gas_price, }, starknet_version: value.starknet_version.ok_or(ConversionError)?, transactions: value @@ -142,16 +119,8 @@ impl TryFrom for core::MaybePendingBlockWithTxs { sequencer_address: value.sequencer_address.unwrap_or_default(), parent_hash: value.parent_block_hash, l1_gas_price: core::ResourcePrice { - price_in_strk: Some( - value - .strk_l1_gas_price - .try_into() - .map_err(|_| ConversionError)?, - ), - price_in_wei: value - .eth_l1_gas_price - .try_into() - .map_err(|_| ConversionError)?, + price_in_fri: value.strk_l1_gas_price, + price_in_wei: value.eth_l1_gas_price, }, starknet_version: value.starknet_version.ok_or(ConversionError)?, })), @@ -220,6 +189,27 @@ impl TryFrom for core::DeclareTransaction { compiled_class_hash: value.compiled_class_hash.ok_or(ConversionError)?, sender_address: value.sender_address, })) + } else if value.version == FieldElement::THREE { + Ok(Self::V3(core::DeclareTransactionV3 { + transaction_hash: value.transaction_hash, + sender_address: value.sender_address, + compiled_class_hash: value.compiled_class_hash.ok_or(ConversionError)?, + signature: value.signature, + nonce: value.nonce, + class_hash: value.class_hash, + resource_bounds: value.resource_bounds.ok_or(ConversionError)?.into(), + tip: value.tip.ok_or(ConversionError)?, + paymaster_data: value.paymaster_data.ok_or(ConversionError)?, + account_deployment_data: value.account_deployment_data.ok_or(ConversionError)?, + nonce_data_availability_mode: value + .nonce_data_availability_mode + .ok_or(ConversionError)? + .into(), + fee_data_availability_mode: value + .fee_data_availability_mode + .ok_or(ConversionError)? + .into(), + })) } else { Err(ConversionError) } @@ -233,7 +223,7 @@ impl TryFrom for core::DeployTransaction { Ok(Self { transaction_hash: value.transaction_hash, class_hash: value.class_hash, - version: value.version.try_into().map_err(|_| ConversionError)?, + version: value.version, contract_address_salt: value.contract_address_salt, constructor_calldata: value.constructor_calldata, }) @@ -244,15 +234,39 @@ impl TryFrom for core::DeployAccountTransaction { type Error = ConversionError; fn try_from(value: DeployAccountTransaction) -> Result { - Ok(Self { - transaction_hash: value.transaction_hash, - max_fee: value.max_fee.ok_or(ConversionError)?, - signature: value.signature, - nonce: value.nonce, - contract_address_salt: value.contract_address_salt, - constructor_calldata: value.constructor_calldata, - class_hash: value.class_hash, - }) + if value.version == FieldElement::ONE { + Ok(Self::V1(core::DeployAccountTransactionV1 { + transaction_hash: value.transaction_hash, + max_fee: value.max_fee.ok_or(ConversionError)?, + signature: value.signature, + nonce: value.nonce, + contract_address_salt: value.contract_address_salt, + constructor_calldata: value.constructor_calldata, + class_hash: value.class_hash, + })) + } else if value.version == FieldElement::THREE { + Ok(Self::V3(core::DeployAccountTransactionV3 { + transaction_hash: value.transaction_hash, + signature: value.signature, + nonce: value.nonce, + contract_address_salt: value.contract_address_salt, + constructor_calldata: value.constructor_calldata, + class_hash: value.class_hash, + resource_bounds: value.resource_bounds.ok_or(ConversionError)?.into(), + tip: value.tip.ok_or(ConversionError)?, + paymaster_data: value.paymaster_data.ok_or(ConversionError)?, + nonce_data_availability_mode: value + .nonce_data_availability_mode + .ok_or(ConversionError)? + .into(), + fee_data_availability_mode: value + .fee_data_availability_mode + .ok_or(ConversionError)? + .into(), + })) + } else { + Err(ConversionError) + } } } @@ -278,6 +292,26 @@ impl TryFrom for core::InvokeTransaction { sender_address: value.sender_address, calldata: value.calldata, })) + } else if value.version == FieldElement::THREE { + Ok(Self::V3(core::InvokeTransactionV3 { + transaction_hash: value.transaction_hash, + sender_address: value.sender_address, + calldata: value.calldata, + signature: value.signature, + nonce: value.nonce.ok_or(ConversionError)?, + resource_bounds: value.resource_bounds.ok_or(ConversionError)?.into(), + tip: value.tip.ok_or(ConversionError)?, + paymaster_data: value.paymaster_data.ok_or(ConversionError)?, + account_deployment_data: value.account_deployment_data.ok_or(ConversionError)?, + nonce_data_availability_mode: value + .nonce_data_availability_mode + .ok_or(ConversionError)? + .into(), + fee_data_availability_mode: value + .fee_data_availability_mode + .ok_or(ConversionError)? + .into(), + })) } else { Err(ConversionError) } @@ -290,7 +324,7 @@ impl TryFrom for core::L1HandlerTransaction { fn try_from(value: L1HandlerTransaction) -> Result { Ok(Self { transaction_hash: value.transaction_hash, - version: value.version.try_into().map_err(|_| ConversionError)?, + version: value.version, nonce: value .nonce .unwrap_or_default() @@ -303,6 +337,60 @@ impl TryFrom for core::L1HandlerTransaction { } } +impl From for core::ResourceBoundsMapping { + fn from(value: ResourceBoundsMapping) -> Self { + Self { + l1_gas: value.l1_gas.into(), + l2_gas: value.l2_gas.into(), + } + } +} + +impl From for ResourceBoundsMapping { + fn from(value: core::ResourceBoundsMapping) -> Self { + Self { + l1_gas: value.l1_gas.into(), + l2_gas: value.l2_gas.into(), + } + } +} + +impl From for core::ResourceBounds { + fn from(value: ResourceBounds) -> Self { + Self { + max_amount: value.max_amount, + max_price_per_unit: value.max_price_per_unit, + } + } +} + +impl From for ResourceBounds { + fn from(value: core::ResourceBounds) -> Self { + Self { + max_amount: value.max_amount, + max_price_per_unit: value.max_price_per_unit, + } + } +} + +impl From for core::DataAvailabilityMode { + fn from(value: DataAvailabilityMode) -> Self { + match value { + DataAvailabilityMode::L1 => Self::L1, + DataAvailabilityMode::L2 => Self::L2, + } + } +} + +impl From for DataAvailabilityMode { + fn from(value: core::DataAvailabilityMode) -> Self { + match value { + core::DataAvailabilityMode::L1 => Self::L1, + core::DataAvailabilityMode::L2 => Self::L2, + } + } +} + impl TryFrom for core::MaybePendingStateUpdate { type Error = ConversionError; @@ -457,14 +545,41 @@ impl TryFrom for core::TransactionFinalityStatus { impl From for InvokeFunctionTransactionRequest { fn from(value: core::BroadcastedInvokeTransaction) -> Self { - Self::V1(InvokeFunctionV1TransactionRequest { + match value { + core::BroadcastedInvokeTransaction::V1(inner) => Self::V1(inner.into()), + core::BroadcastedInvokeTransaction::V3(inner) => Self::V3(inner.into()), + } + } +} + +impl From for InvokeFunctionV1TransactionRequest { + fn from(value: core::BroadcastedInvokeTransactionV1) -> Self { + Self { sender_address: value.sender_address, calldata: value.calldata, signature: value.signature, max_fee: value.max_fee, nonce: value.nonce, is_query: value.is_query, - }) + } + } +} + +impl From for InvokeFunctionV3TransactionRequest { + fn from(value: core::BroadcastedInvokeTransactionV3) -> Self { + Self { + sender_address: value.sender_address, + calldata: value.calldata, + signature: value.signature, + nonce: value.nonce, + nonce_data_availability_mode: value.nonce_data_availability_mode.into(), + fee_data_availability_mode: value.fee_data_availability_mode.into(), + resource_bounds: value.resource_bounds.into(), + tip: value.tip, + paymaster_data: value.paymaster_data, + account_deployment_data: value.account_deployment_data, + is_query: value.is_query, + } } } @@ -475,6 +590,7 @@ impl TryFrom for DeclareTransactionRequest match value { core::BroadcastedDeclareTransaction::V1(inner) => Ok(Self::V1(inner.into())), core::BroadcastedDeclareTransaction::V2(inner) => Ok(Self::V2(inner.try_into()?)), + core::BroadcastedDeclareTransaction::V3(inner) => Ok(Self::V3(inner.try_into()?)), } } } @@ -511,9 +627,42 @@ impl TryFrom for DeclareV2TransactionRequ } } +impl TryFrom for DeclareV3TransactionRequest { + type Error = ConversionError; + + fn try_from(value: core::BroadcastedDeclareTransactionV3) -> Result { + Ok(Self { + contract_class: Arc::new( + contract::CompressedSierraClass::from_flattened(&value.contract_class) + .map_err(|_| ConversionError)?, + ), + compiled_class_hash: value.compiled_class_hash, + sender_address: value.sender_address, + signature: value.signature, + nonce: value.nonce, + nonce_data_availability_mode: value.nonce_data_availability_mode.into(), + fee_data_availability_mode: value.fee_data_availability_mode.into(), + resource_bounds: value.resource_bounds.into(), + tip: value.tip, + paymaster_data: value.paymaster_data, + account_deployment_data: value.account_deployment_data, + is_query: value.is_query, + }) + } +} + impl From for DeployAccountTransactionRequest { fn from(value: core::BroadcastedDeployAccountTransaction) -> Self { - Self::V1(DeployAccountV1TransactionRequest { + match value { + core::BroadcastedDeployAccountTransaction::V1(inner) => Self::V1(inner.into()), + core::BroadcastedDeployAccountTransaction::V3(inner) => Self::V3(inner.into()), + } + } +} + +impl From for DeployAccountV1TransactionRequest { + fn from(value: core::BroadcastedDeployAccountTransactionV1) -> Self { + Self { class_hash: value.class_hash, contract_address_salt: value.contract_address_salt, constructor_calldata: value.constructor_calldata, @@ -521,7 +670,25 @@ impl From for DeployAccountTransactio signature: value.signature, nonce: value.nonce, is_query: value.is_query, - }) + } + } +} + +impl From for DeployAccountV3TransactionRequest { + fn from(value: core::BroadcastedDeployAccountTransactionV3) -> Self { + Self { + class_hash: value.class_hash, + contract_address_salt: value.contract_address_salt, + constructor_calldata: value.constructor_calldata, + signature: value.signature, + nonce: value.nonce, + nonce_data_availability_mode: value.nonce_data_availability_mode.into(), + fee_data_availability_mode: value.fee_data_availability_mode.into(), + resource_bounds: value.resource_bounds.into(), + tip: value.tip, + paymaster_data: value.paymaster_data, + is_query: value.is_query, + } } } @@ -599,6 +766,7 @@ impl TryFrom for core::FunctionInvocation { .into() }) .collect(), + execution_resources: value.execution_resources.into(), }) } } @@ -652,34 +820,14 @@ impl From for core::ExecutionResources { Self { steps: value.n_steps, memory_holes: Some(value.n_memory_holes), - range_check_builtin_applications: value - .builtin_instance_counter - .range_check_builtin - .unwrap_or_default(), - pedersen_builtin_applications: value - .builtin_instance_counter - .pedersen_builtin - .unwrap_or_default(), - poseidon_builtin_applications: value - .builtin_instance_counter - .poseidon_builtin - .unwrap_or_default(), - ec_op_builtin_applications: value - .builtin_instance_counter - .ec_op_builtin - .unwrap_or_default(), - ecdsa_builtin_applications: value - .builtin_instance_counter - .ecdsa_builtin - .unwrap_or_default(), - bitwise_builtin_applications: value - .builtin_instance_counter - .bitwise_builtin - .unwrap_or_default(), - keccak_builtin_applications: value - .builtin_instance_counter - .keccak_builtin - .unwrap_or_default(), + range_check_builtin_applications: value.builtin_instance_counter.range_check_builtin, + pedersen_builtin_applications: value.builtin_instance_counter.pedersen_builtin, + poseidon_builtin_applications: value.builtin_instance_counter.poseidon_builtin, + ec_op_builtin_applications: value.builtin_instance_counter.ec_op_builtin, + ecdsa_builtin_applications: value.builtin_instance_counter.ecdsa_builtin, + bitwise_builtin_applications: value.builtin_instance_counter.bitwise_builtin, + keccak_builtin_applications: value.builtin_instance_counter.keccak_builtin, + segment_arena_builtin: value.builtin_instance_counter.segment_arena_builtin, } } } diff --git a/starknet-providers/src/sequencer/provider.rs b/starknet-providers/src/sequencer/provider.rs index 7f13a2cc..f7ac82d7 100644 --- a/starknet-providers/src/sequencer/provider.rs +++ b/starknet-providers/src/sequencer/provider.rs @@ -9,8 +9,9 @@ use starknet_core::types::{ ContractClass, DeclareTransactionResult, DeployAccountTransactionResult, EventFilter, EventsPage, FeeEstimate, FieldElement, FunctionCall, InvokeTransactionResult, MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, MaybePendingStateUpdate, - MaybePendingTransactionReceipt, MsgFromL1, SimulatedTransaction, SimulationFlag, StarknetError, - SyncStatusType, Transaction, TransactionStatus, TransactionTrace, TransactionTraceWithHash, + MaybePendingTransactionReceipt, MsgFromL1, SimulatedTransaction, SimulationFlag, + SimulationFlagForEstimateFee, StarknetError, SyncStatusType, Transaction, TransactionStatus, + TransactionTrace, TransactionTraceWithHash, }; use crate::{ @@ -218,13 +219,15 @@ impl Provider for SequencerGatewayProvider { ))) } - async fn estimate_fee( + async fn estimate_fee( &self, request: R, + simulation_flags: S, block_id: B, ) -> Result, ProviderError> where R: AsRef<[BroadcastedTransaction]> + Send + Sync, + S: AsRef<[SimulationFlagForEstimateFee]> + Send + Sync, B: AsRef + Send + Sync, { // Deprecated since Starknet v0.12.3 diff --git a/starknet-providers/tests/jsonrpc.rs b/starknet-providers/tests/jsonrpc.rs index 51ee615c..ebbac729 100644 --- a/starknet-providers/tests/jsonrpc.rs +++ b/starknet-providers/tests/jsonrpc.rs @@ -1,11 +1,12 @@ use starknet_core::{ types::{ - BlockId, BlockTag, BroadcastedInvokeTransaction, BroadcastedTransaction, ContractClass, - DeclareTransaction, EthAddress, EventFilter, ExecuteInvocation, ExecutionResult, - FieldElement, FunctionCall, InvokeTransaction, MaybePendingBlockWithTxHashes, - MaybePendingBlockWithTxs, MaybePendingStateUpdate, MaybePendingTransactionReceipt, - MsgFromL1, StarknetError, SyncStatusType, Transaction, TransactionExecutionStatus, - TransactionReceipt, TransactionStatus, TransactionTrace, + BlockId, BlockTag, BroadcastedInvokeTransaction, BroadcastedInvokeTransactionV1, + BroadcastedTransaction, ContractClass, DeclareTransaction, DeployAccountTransaction, + EthAddress, EventFilter, ExecuteInvocation, ExecutionResult, FieldElement, FunctionCall, + InvokeTransaction, MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, + MaybePendingStateUpdate, MaybePendingTransactionReceipt, MsgFromL1, StarknetError, + SyncStatusType, Transaction, TransactionExecutionStatus, TransactionReceipt, + TransactionStatus, TransactionTrace, }, utils::{get_selector_from_name, get_storage_var_address}, }; @@ -16,18 +17,19 @@ use starknet_providers::{ use url::Url; fn create_jsonrpc_client() -> JsonRpcClient { - let rpc_url = - std::env::var("STARKNET_RPC").unwrap_or("https://rpc-goerli-1.starknet.rs/rpc/v0.5".into()); + let rpc_url = std::env::var("STARKNET_RPC") + .unwrap_or("https://juno.rpc.goerli.starknet.rs/rpc/v0_6".into()); JsonRpcClient::new(HttpTransport::new(Url::parse(&rpc_url).unwrap())) } +#[ignore = "nodes are incorrectly returning `0.6.0-rc5`"] #[tokio::test] async fn jsonrpc_spec_version() { let rpc_client = create_jsonrpc_client(); let version = rpc_client.spec_version().await.unwrap(); - assert_eq!(version, "0.5.1"); + assert_eq!(version, "0.6.0"); } #[tokio::test] @@ -323,7 +325,7 @@ async fn jsonrpc_get_transaction_by_hash_deploy() { } #[tokio::test] -async fn jsonrpc_get_transaction_by_hash_deploy_account() { +async fn jsonrpc_get_transaction_by_hash_deploy_account_v1() { let rpc_client = create_jsonrpc_client(); let tx = rpc_client @@ -337,7 +339,7 @@ async fn jsonrpc_get_transaction_by_hash_deploy_account() { .unwrap(); let tx = match tx { - Transaction::DeployAccount(tx) => tx, + Transaction::DeployAccount(DeployAccountTransaction::V1(tx)) => tx, _ => panic!("unexpected tx response type"), }; @@ -672,54 +674,57 @@ async fn jsonrpc_estimate_fee() { let estimate = rpc_client .estimate_fee_single( - &BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction { - max_fee: FieldElement::ZERO, - signature: vec![ - FieldElement::from_hex_be( - "156a781f12e8743bd07e20a4484154fd0baccee95d9ea791c121c916ad44ee0", - ) - .unwrap(), - FieldElement::from_hex_be( - "7228267473c670cbb86a644f8696973db978c51acde19431d3f1f8f100794c6", - ) - .unwrap(), - ], - nonce: FieldElement::ZERO, - sender_address: FieldElement::from_hex_be( - "5b5e9f6f6fb7d2647d81a8b2c2b99cbc9cc9d03d705576d7061812324dca5c0", - ) - .unwrap(), - calldata: vec![ - FieldElement::from_hex_be("1").unwrap(), - FieldElement::from_hex_be( - "7394cbe418daa16e42b87ba67372d4ab4a5df0b05c6e554d158458ce245bc10", - ) - .unwrap(), - FieldElement::from_hex_be( - "2f0b3c5710379609eb5495f1ecd348cb28167711b73609fe565a72734550354", - ) - .unwrap(), - FieldElement::from_hex_be("0").unwrap(), - FieldElement::from_hex_be("3").unwrap(), - FieldElement::from_hex_be("3").unwrap(), - FieldElement::from_hex_be( + &BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1( + BroadcastedInvokeTransactionV1 { + max_fee: FieldElement::ZERO, + signature: vec![ + FieldElement::from_hex_be( + "156a781f12e8743bd07e20a4484154fd0baccee95d9ea791c121c916ad44ee0", + ) + .unwrap(), + FieldElement::from_hex_be( + "7228267473c670cbb86a644f8696973db978c51acde19431d3f1f8f100794c6", + ) + .unwrap(), + ], + nonce: FieldElement::ZERO, + sender_address: FieldElement::from_hex_be( "5b5e9f6f6fb7d2647d81a8b2c2b99cbc9cc9d03d705576d7061812324dca5c0", ) .unwrap(), - FieldElement::from_hex_be("3635c9adc5dea00000").unwrap(), - FieldElement::from_hex_be("0").unwrap(), - ], - // TODO: make use of query version tx for estimating fees - is_query: false, - }), + calldata: vec![ + FieldElement::from_hex_be("1").unwrap(), + FieldElement::from_hex_be( + "7394cbe418daa16e42b87ba67372d4ab4a5df0b05c6e554d158458ce245bc10", + ) + .unwrap(), + FieldElement::from_hex_be( + "2f0b3c5710379609eb5495f1ecd348cb28167711b73609fe565a72734550354", + ) + .unwrap(), + FieldElement::from_hex_be("0").unwrap(), + FieldElement::from_hex_be("3").unwrap(), + FieldElement::from_hex_be("3").unwrap(), + FieldElement::from_hex_be( + "5b5e9f6f6fb7d2647d81a8b2c2b99cbc9cc9d03d705576d7061812324dca5c0", + ) + .unwrap(), + FieldElement::from_hex_be("3635c9adc5dea00000").unwrap(), + FieldElement::from_hex_be("0").unwrap(), + ], + // TODO: make use of query version tx for estimating fees + is_query: false, + }, + )), + [], BlockId::Tag(BlockTag::Latest), ) .await .unwrap(); - assert!(estimate.gas_consumed > 0); - assert!(estimate.gas_price > 0); - assert!(estimate.overall_fee > 0); + assert!(estimate.gas_consumed > FieldElement::ZERO); + assert!(estimate.gas_price > FieldElement::ZERO); + assert!(estimate.overall_fee > FieldElement::ZERO); } #[tokio::test] @@ -746,9 +751,9 @@ async fn jsonrpc_estimate_message_fee() { .await .unwrap(); - assert!(estimate.gas_consumed > 0); - assert!(estimate.gas_price > 0); - assert!(estimate.overall_fee > 0); + assert!(estimate.gas_consumed > FieldElement::ZERO); + assert!(estimate.gas_price > FieldElement::ZERO); + assert!(estimate.overall_fee > FieldElement::ZERO); } #[tokio::test]